pf.c revision 178888
1171168Smlaier/*	$OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
5130613Smlaier * Copyright (c) 2002,2003 Henning Brauer
6126258Smlaier * All rights reserved.
7126258Smlaier *
8126258Smlaier * Redistribution and use in source and binary forms, with or without
9126258Smlaier * modification, are permitted provided that the following conditions
10126258Smlaier * are met:
11126258Smlaier *
12126258Smlaier *    - Redistributions of source code must retain the above copyright
13126258Smlaier *      notice, this list of conditions and the following disclaimer.
14126258Smlaier *    - Redistributions in binary form must reproduce the above
15126258Smlaier *      copyright notice, this list of conditions and the following
16126258Smlaier *      disclaimer in the documentation and/or other materials provided
17126258Smlaier *      with the distribution.
18126258Smlaier *
19126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126258Smlaier *
32126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
33126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
34126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35126258Smlaier *
36126258Smlaier */
37126258Smlaier
38127145Smlaier#ifdef __FreeBSD__
39126261Smlaier#include "opt_inet.h"
40126261Smlaier#include "opt_inet6.h"
41171168Smlaier
42171168Smlaier#include <sys/cdefs.h>
43171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf.c 178888 2008-05-09 23:03:00Z julian $");
44126261Smlaier#endif
45126261Smlaier
46127145Smlaier#ifdef __FreeBSD__
47162238Scsjp#include "opt_mac.h"
48126261Smlaier#include "opt_bpf.h"
49126261Smlaier#include "opt_pf.h"
50153110Sru
51153110Sru#ifdef DEV_BPF
52127145Smlaier#define	NBPFILTER	DEV_BPF
53153110Sru#else
54153110Sru#define	NBPFILTER	0
55153110Sru#endif
56153110Sru
57153110Sru#ifdef DEV_PFLOG
58127145Smlaier#define	NPFLOG		DEV_PFLOG
59153110Sru#else
60153110Sru#define	NPFLOG		0
61153110Sru#endif
62153110Sru
63153110Sru#ifdef DEV_PFSYNC
64127145Smlaier#define	NPFSYNC		DEV_PFSYNC
65126261Smlaier#else
66153110Sru#define	NPFSYNC		0
67153110Sru#endif
68153110Sru
69153110Sru#else
70126258Smlaier#include "bpfilter.h"
71126258Smlaier#include "pflog.h"
72126258Smlaier#include "pfsync.h"
73126261Smlaier#endif
74126258Smlaier
75126258Smlaier#include <sys/param.h>
76126258Smlaier#include <sys/systm.h>
77126258Smlaier#include <sys/mbuf.h>
78126258Smlaier#include <sys/filio.h>
79126258Smlaier#include <sys/socket.h>
80126258Smlaier#include <sys/socketvar.h>
81126258Smlaier#include <sys/kernel.h>
82126258Smlaier#include <sys/time.h>
83127145Smlaier#ifdef __FreeBSD__
84126261Smlaier#include <sys/sysctl.h>
85130613Smlaier#include <sys/endian.h>
86126261Smlaier#else
87126258Smlaier#include <sys/pool.h>
88126261Smlaier#endif
89171168Smlaier#include <sys/proc.h>
90171168Smlaier#ifdef __FreeBSD__
91171168Smlaier#include <sys/kthread.h>
92171168Smlaier#include <sys/lock.h>
93171168Smlaier#include <sys/sx.h>
94171168Smlaier#else
95171168Smlaier#include <sys/rwlock.h>
96171168Smlaier#endif
97126258Smlaier
98126258Smlaier#include <net/if.h>
99126258Smlaier#include <net/if_types.h>
100126258Smlaier#include <net/bpf.h>
101126258Smlaier#include <net/route.h>
102171168Smlaier#ifndef __FreeBSD__
103171168Smlaier#include <net/radix_mpath.h>
104171168Smlaier#endif
105126258Smlaier
106126258Smlaier#include <netinet/in.h>
107126258Smlaier#include <netinet/in_var.h>
108126258Smlaier#include <netinet/in_systm.h>
109126258Smlaier#include <netinet/ip.h>
110126258Smlaier#include <netinet/ip_var.h>
111126258Smlaier#include <netinet/tcp.h>
112126258Smlaier#include <netinet/tcp_seq.h>
113126258Smlaier#include <netinet/udp.h>
114126258Smlaier#include <netinet/ip_icmp.h>
115126258Smlaier#include <netinet/in_pcb.h>
116126258Smlaier#include <netinet/tcp_timer.h>
117126258Smlaier#include <netinet/tcp_var.h>
118126258Smlaier#include <netinet/udp_var.h>
119126258Smlaier#include <netinet/icmp_var.h>
120145836Smlaier#include <netinet/if_ether.h>
121126258Smlaier
122127145Smlaier#ifndef __FreeBSD__
123126258Smlaier#include <dev/rndvar.h>
124126261Smlaier#endif
125126258Smlaier#include <net/pfvar.h>
126126258Smlaier#include <net/if_pflog.h>
127130613Smlaier
128130613Smlaier#if NPFSYNC > 0
129126258Smlaier#include <net/if_pfsync.h>
130130613Smlaier#endif /* NPFSYNC > 0 */
131126258Smlaier
132126258Smlaier#ifdef INET6
133126258Smlaier#include <netinet/ip6.h>
134126258Smlaier#include <netinet/in_pcb.h>
135126258Smlaier#include <netinet/icmp6.h>
136126258Smlaier#include <netinet6/nd6.h>
137127145Smlaier#ifdef __FreeBSD__
138126261Smlaier#include <netinet6/ip6_var.h>
139126261Smlaier#include <netinet6/in6_pcb.h>
140126261Smlaier#endif
141126258Smlaier#endif /* INET6 */
142126258Smlaier
143127145Smlaier#ifdef __FreeBSD__
144126261Smlaier#include <machine/in_cksum.h>
145126261Smlaier#include <sys/limits.h>
146126261Smlaier#include <sys/ucred.h>
147163606Srwatson#include <security/mac/mac_framework.h>
148126258Smlaier
149126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
150171168Smlaierextern int debug_pfugidhack;
151126261Smlaier#endif
152126261Smlaier
153126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
154126258Smlaier
155126258Smlaier/*
156126258Smlaier * Global variables
157126258Smlaier */
158126258Smlaier
159126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
160126258Smlaierstruct pf_palist	 pf_pabuf;
161126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
162126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
163126258Smlaierstruct pf_status	 pf_status;
164126258Smlaier
165126258Smlaieru_int32_t		 ticket_altqs_active;
166126258Smlaieru_int32_t		 ticket_altqs_inactive;
167130613Smlaierint			 altqs_inactive_open;
168126258Smlaieru_int32_t		 ticket_pabuf;
169126258Smlaier
170145836Smlaierstruct pf_anchor_stackframe {
171145836Smlaier	struct pf_ruleset			*rs;
172145836Smlaier	struct pf_rule				*r;
173145836Smlaier	struct pf_anchor_node			*parent;
174145836Smlaier	struct pf_anchor			*child;
175145836Smlaier} pf_anchor_stack[64];
176126261Smlaier
177127145Smlaier#ifdef __FreeBSD__
178130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
179126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
180126261Smlaier#else
181130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
182126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
183126261Smlaier#endif
184126258Smlaier
185126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
186126258Smlaier
187145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
188145836Smlaier			    u_int32_t);
189145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
190145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
191145836Smlaier
192126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
193126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
194126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
195171168Smlaierint			 pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
196171168Smlaier			    struct tcphdr *, struct pf_state_peer *);
197126258Smlaier#ifdef INET6
198126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
199126258Smlaier			    struct pf_addr *, u_int8_t);
200126258Smlaier#endif /* INET6 */
201126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
202126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
203126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
204126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
205162238Scsjp#ifdef __FreeBSD__
206162238Scsjpvoid			 pf_send_tcp(struct mbuf *,
207162238Scsjp			    const struct pf_rule *, sa_family_t,
208162238Scsjp#else
209126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
210162238Scsjp#endif
211126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
212126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
213145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
214171168Smlaier			    u_int16_t, struct ether_header *, struct ifnet *);
215126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
216126258Smlaier			    sa_family_t, struct pf_rule *);
217126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
218130613Smlaier			    int, int, struct pfi_kif *,
219126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
220126258Smlaier			    u_int16_t, int);
221126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
222130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
223126258Smlaier			    struct pf_addr *, u_int16_t,
224126258Smlaier			    struct pf_addr *, u_int16_t,
225126258Smlaier			    struct pf_addr *, u_int16_t *);
226126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
227130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
228126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
229135920Smlaier#ifdef __FreeBSD__
230145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
231145836Smlaier			    struct inpcb *);
232135920Smlaier#else
233145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
234135920Smlaier#endif
235126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
236130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
237126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
238135920Smlaier#ifdef __FreeBSD__
239145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
240145836Smlaier			    struct inpcb *);
241135920Smlaier#else
242145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
243135920Smlaier#endif
244126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
245130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
246126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
247145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
248126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
249130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
250126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
251145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
252126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
253130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
254126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
255126258Smlaier			    struct pf_ruleset **);
256126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
257130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
258126258Smlaier			    void *, struct pf_pdesc *, u_short *);
259126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
260130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
261126258Smlaier			    void *, struct pf_pdesc *);
262126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
263130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
264145836Smlaier			    void *, struct pf_pdesc *, u_short *);
265126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
266130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
267126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
268171168Smlaier			     struct pf_mtag *, int *);
269171168Smlaierint			 pf_step_out_of_anchor(int *, struct pf_ruleset **,
270171168Smlaier			     int, struct pf_rule **, struct pf_rule **,
271171168Smlaier			     int *);
272126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
273126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
274130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
275126258Smlaier			    struct pf_addr *, struct pf_addr *,
276130613Smlaier			    struct pf_addr *, struct pf_src_node **);
277130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
278126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
279130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
280130613Smlaier			    struct pf_src_node **);
281126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
282171168Smlaier			    struct ifnet *, struct pf_state *,
283171168Smlaier			    struct pf_pdesc *);
284126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
285171168Smlaier			    struct ifnet *, struct pf_state *,
286171168Smlaier			    struct pf_pdesc *);
287135920Smlaier#ifdef __FreeBSD__
288171168Smlaier/* XXX: import */
289135920Smlaier#else
290171168Smlaierint			 pf_socket_lookup(int, struct pf_pdesc *);
291135920Smlaier#endif
292126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
293126258Smlaier			    sa_family_t);
294126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
295126258Smlaier			    sa_family_t);
296126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
297126258Smlaier				u_int16_t);
298126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
299126258Smlaier			    struct pf_addr *);
300126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
301126258Smlaier			    u_int8_t, sa_family_t);
302126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
303126258Smlaier			    struct pf_addr_wrap *);
304130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
305171168Smlaier			    struct pf_state_cmp *, u_int8_t);
306145836Smlaierint			 pf_src_connlimit(struct pf_state **);
307145836Smlaierint			 pf_check_congestion(struct ifqueue *);
308126258Smlaier
309127145Smlaier#ifdef __FreeBSD__
310126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
311126258Smlaier
312171168Smlaierextern int pf_end_threads;
313171168Smlaier
314126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
315171168Smlaier#else
316171168Smlaierextern struct pool pfr_ktable_pl;
317171168Smlaierextern struct pool pfr_kentry_pl;
318145836Smlaier
319130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
320130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
321130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
322171168Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT },
323171168Smlaier	{ &pfr_ktable_pl, PFR_KTABLE_HIWAT },
324171168Smlaier	{ &pfr_kentry_pl, PFR_KENTRY_HIWAT }
325130613Smlaier};
326126261Smlaier#endif
327126258Smlaier
328126258Smlaier#define STATE_LOOKUP()							\
329126258Smlaier	do {								\
330126258Smlaier		if (direction == PF_IN)					\
331145836Smlaier			*state = pf_find_state_recurse(			\
332130613Smlaier			    kif, &key, PF_EXT_GWY);			\
333126258Smlaier		else							\
334145836Smlaier			*state = pf_find_state_recurse(			\
335130613Smlaier			    kif, &key, PF_LAN_EXT);			\
336145836Smlaier		if (*state == NULL || (*state)->timeout == PFTM_PURGE)	\
337126258Smlaier			return (PF_DROP);				\
338126258Smlaier		if (direction == PF_OUT &&				\
339126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
340126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
341126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
342126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
343130613Smlaier		    (*state)->rt_kif != NULL &&				\
344130613Smlaier		    (*state)->rt_kif != kif)				\
345126258Smlaier			return (PF_PASS);				\
346126258Smlaier	} while (0)
347126258Smlaier
348126258Smlaier#define	STATE_TRANSLATE(s) \
349126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
350126258Smlaier	((s)->af == AF_INET6 && \
351126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
352126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
353126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
354126258Smlaier	(s)->lan.port != (s)->gwy.port
355126258Smlaier
356171168Smlaier#define BOUND_IFACE(r, k) \
357171168Smlaier	((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
358126258Smlaier
359145836Smlaier#define STATE_INC_COUNTERS(s)				\
360145836Smlaier	do {						\
361145836Smlaier		s->rule.ptr->states++;			\
362145836Smlaier		if (s->anchor.ptr != NULL)		\
363145836Smlaier			s->anchor.ptr->states++;	\
364145836Smlaier		if (s->nat_rule.ptr != NULL)		\
365145836Smlaier			s->nat_rule.ptr->states++;	\
366145836Smlaier	} while (0)
367145836Smlaier
368145836Smlaier#define STATE_DEC_COUNTERS(s)				\
369145836Smlaier	do {						\
370145836Smlaier		if (s->nat_rule.ptr != NULL)		\
371145836Smlaier			s->nat_rule.ptr->states--;	\
372145836Smlaier		if (s->anchor.ptr != NULL)		\
373145836Smlaier			s->anchor.ptr->states--;	\
374145836Smlaier		s->rule.ptr->states--;			\
375145836Smlaier	} while (0)
376145836Smlaier
377130613Smlaierstruct pf_src_tree tree_src_tracking;
378130613Smlaier
379130613Smlaierstruct pf_state_tree_id tree_id;
380171168Smlaierstruct pf_state_queue state_list;
381130613Smlaier
382171168Smlaier#ifdef __FreeBSD__
383171168Smlaierstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
384171168Smlaierstatic int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *);
385171168Smlaierstatic int pf_state_compare_ext_gwy(struct pf_state *, struct pf_state *);
386171168Smlaierstatic int pf_state_compare_id(struct pf_state *, struct pf_state *);
387171168Smlaier#endif
388171168Smlaier
389130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
390130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
391130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
392130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
393130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
394130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
395130613Smlaier    u.s.entry_id, pf_state_compare_id);
396130613Smlaier
397127145Smlaier#ifdef __FreeBSD__
398126409Smlaierstatic int
399126409Smlaier#else
400126258Smlaierstatic __inline int
401126409Smlaier#endif
402130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
403126258Smlaier{
404126258Smlaier	int	diff;
405126258Smlaier
406130613Smlaier	if (a->rule.ptr > b->rule.ptr)
407130613Smlaier		return (1);
408130613Smlaier	if (a->rule.ptr < b->rule.ptr)
409130613Smlaier		return (-1);
410130613Smlaier	if ((diff = a->af - b->af) != 0)
411130613Smlaier		return (diff);
412130613Smlaier	switch (a->af) {
413130613Smlaier#ifdef INET
414130613Smlaier	case AF_INET:
415130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
416130613Smlaier			return (1);
417130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
418130613Smlaier			return (-1);
419130613Smlaier		break;
420130613Smlaier#endif /* INET */
421130613Smlaier#ifdef INET6
422130613Smlaier	case AF_INET6:
423130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
424130613Smlaier			return (1);
425130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
426130613Smlaier			return (-1);
427130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
428130613Smlaier			return (1);
429130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
430130613Smlaier			return (-1);
431130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
432130613Smlaier			return (1);
433130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
434130613Smlaier			return (-1);
435130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
436130613Smlaier			return (1);
437130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
438130613Smlaier			return (-1);
439130613Smlaier		break;
440130613Smlaier#endif /* INET6 */
441130613Smlaier	}
442130613Smlaier	return (0);
443130613Smlaier}
444130613Smlaier
445130613Smlaier#ifdef __FreeBSD__
446130613Smlaierstatic int
447130613Smlaier#else
448130613Smlaierstatic __inline int
449130613Smlaier#endif
450130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
451130613Smlaier{
452130613Smlaier	int	diff;
453130613Smlaier
454126258Smlaier	if ((diff = a->proto - b->proto) != 0)
455126258Smlaier		return (diff);
456126258Smlaier	if ((diff = a->af - b->af) != 0)
457126258Smlaier		return (diff);
458126258Smlaier	switch (a->af) {
459126258Smlaier#ifdef INET
460126258Smlaier	case AF_INET:
461130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
462126258Smlaier			return (1);
463130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
464126258Smlaier			return (-1);
465130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
466126258Smlaier			return (1);
467130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
468126258Smlaier			return (-1);
469126258Smlaier		break;
470126258Smlaier#endif /* INET */
471126258Smlaier#ifdef INET6
472126258Smlaier	case AF_INET6:
473130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
474126258Smlaier			return (1);
475130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
476126258Smlaier			return (-1);
477130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
478126258Smlaier			return (1);
479130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
480126258Smlaier			return (-1);
481130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
482126258Smlaier			return (1);
483130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
484126258Smlaier			return (-1);
485130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
486126258Smlaier			return (1);
487130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
488126258Smlaier			return (-1);
489130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
490126258Smlaier			return (1);
491130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
492126258Smlaier			return (-1);
493130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
494126258Smlaier			return (1);
495130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
496126258Smlaier			return (-1);
497130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
498126258Smlaier			return (1);
499130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
500126258Smlaier			return (-1);
501130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
502126258Smlaier			return (1);
503130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
504126258Smlaier			return (-1);
505126258Smlaier		break;
506126258Smlaier#endif /* INET6 */
507126258Smlaier	}
508126258Smlaier
509130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
510126258Smlaier		return (diff);
511130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
512126258Smlaier		return (diff);
513126258Smlaier
514126258Smlaier	return (0);
515126258Smlaier}
516126258Smlaier
517130613Smlaier#ifdef __FreeBSD__
518130613Smlaierstatic int
519130613Smlaier#else
520130613Smlaierstatic __inline int
521130613Smlaier#endif
522130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
523130613Smlaier{
524130613Smlaier	int	diff;
525130613Smlaier
526130613Smlaier	if ((diff = a->proto - b->proto) != 0)
527130613Smlaier		return (diff);
528130613Smlaier	if ((diff = a->af - b->af) != 0)
529130613Smlaier		return (diff);
530130613Smlaier	switch (a->af) {
531130613Smlaier#ifdef INET
532130613Smlaier	case AF_INET:
533130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
534130613Smlaier			return (1);
535130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
536130613Smlaier			return (-1);
537130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
538130613Smlaier			return (1);
539130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
540130613Smlaier			return (-1);
541130613Smlaier		break;
542130613Smlaier#endif /* INET */
543126258Smlaier#ifdef INET6
544130613Smlaier	case AF_INET6:
545130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
546130613Smlaier			return (1);
547130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
548130613Smlaier			return (-1);
549130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
550130613Smlaier			return (1);
551130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
552130613Smlaier			return (-1);
553130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
554130613Smlaier			return (1);
555130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
556130613Smlaier			return (-1);
557130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
558130613Smlaier			return (1);
559130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
560130613Smlaier			return (-1);
561130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
562130613Smlaier			return (1);
563130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
564130613Smlaier			return (-1);
565130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
566130613Smlaier			return (1);
567130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
568130613Smlaier			return (-1);
569130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
570130613Smlaier			return (1);
571130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
572130613Smlaier			return (-1);
573130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
574130613Smlaier			return (1);
575130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
576130613Smlaier			return (-1);
577130613Smlaier		break;
578130613Smlaier#endif /* INET6 */
579130613Smlaier	}
580130613Smlaier
581130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
582130613Smlaier		return (diff);
583130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
584130613Smlaier		return (diff);
585130613Smlaier
586130613Smlaier	return (0);
587130613Smlaier}
588130613Smlaier
589130613Smlaier#ifdef __FreeBSD__
590130613Smlaierstatic int
591130613Smlaier#else
592130613Smlaierstatic __inline int
593130613Smlaier#endif
594130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
595130613Smlaier{
596130613Smlaier	if (a->id > b->id)
597130613Smlaier		return (1);
598130613Smlaier	if (a->id < b->id)
599130613Smlaier		return (-1);
600130613Smlaier	if (a->creatorid > b->creatorid)
601130613Smlaier		return (1);
602130613Smlaier	if (a->creatorid < b->creatorid)
603130613Smlaier		return (-1);
604130613Smlaier
605130613Smlaier	return (0);
606130613Smlaier}
607130613Smlaier
608130613Smlaier#ifdef INET6
609126258Smlaiervoid
610126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
611126258Smlaier{
612126258Smlaier	switch (af) {
613126258Smlaier#ifdef INET
614126258Smlaier	case AF_INET:
615126258Smlaier		dst->addr32[0] = src->addr32[0];
616126258Smlaier		break;
617126258Smlaier#endif /* INET */
618126258Smlaier	case AF_INET6:
619126258Smlaier		dst->addr32[0] = src->addr32[0];
620126258Smlaier		dst->addr32[1] = src->addr32[1];
621126258Smlaier		dst->addr32[2] = src->addr32[2];
622126258Smlaier		dst->addr32[3] = src->addr32[3];
623126258Smlaier		break;
624126258Smlaier	}
625126258Smlaier}
626145836Smlaier#endif /* INET6 */
627126258Smlaier
628126258Smlaierstruct pf_state *
629171168Smlaierpf_find_state_byid(struct pf_state_cmp *key)
630126258Smlaier{
631130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
632171168Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
633130613Smlaier}
634126258Smlaier
635130613Smlaierstruct pf_state *
636171168Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree)
637130613Smlaier{
638130613Smlaier	struct pf_state *s;
639130613Smlaier
640126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
641130613Smlaier
642130613Smlaier	switch (tree) {
643130613Smlaier	case PF_LAN_EXT:
644171168Smlaier		if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext,
645171168Smlaier		    (struct pf_state *)key)) != NULL)
646171168Smlaier			return (s);
647171168Smlaier		if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext,
648171168Smlaier		    (struct pf_state *)key)) != NULL)
649171168Smlaier			return (s);
650126258Smlaier		return (NULL);
651130613Smlaier	case PF_EXT_GWY:
652171168Smlaier		if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy,
653171168Smlaier		    (struct pf_state *)key)) != NULL)
654171168Smlaier			return (s);
655171168Smlaier		if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy,
656171168Smlaier		    (struct pf_state *)key)) != NULL)
657171168Smlaier			return (s);
658130613Smlaier		return (NULL);
659130613Smlaier	default:
660130613Smlaier		panic("pf_find_state_recurse");
661130613Smlaier	}
662126258Smlaier}
663126258Smlaier
664130613Smlaierstruct pf_state *
665171168Smlaierpf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
666130613Smlaier{
667130613Smlaier	struct pf_state *s, *ss = NULL;
668130613Smlaier	struct pfi_kif	*kif;
669130613Smlaier
670130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
671130613Smlaier
672130613Smlaier	switch (tree) {
673130613Smlaier	case PF_LAN_EXT:
674130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
675130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
676171168Smlaier			    &kif->pfik_lan_ext, (struct pf_state *)key);
677130613Smlaier			if (s == NULL)
678130613Smlaier				continue;
679130613Smlaier			if (more == NULL)
680130613Smlaier				return (s);
681130613Smlaier			ss = s;
682130613Smlaier			(*more)++;
683130613Smlaier		}
684130613Smlaier		return (ss);
685130613Smlaier	case PF_EXT_GWY:
686130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
687130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
688171168Smlaier			    &kif->pfik_ext_gwy, (struct pf_state *)key);
689130613Smlaier			if (s == NULL)
690130613Smlaier				continue;
691130613Smlaier			if (more == NULL)
692130613Smlaier				return (s);
693130613Smlaier			ss = s;
694130613Smlaier			(*more)++;
695130613Smlaier		}
696130613Smlaier		return (ss);
697130613Smlaier	default:
698130613Smlaier		panic("pf_find_state_all");
699130613Smlaier	}
700130613Smlaier}
701130613Smlaier
702145836Smlaiervoid
703145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
704145836Smlaier    u_int32_t limit, u_int32_t seconds)
705145836Smlaier{
706145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
707145836Smlaier	threshold->seconds = seconds;
708145836Smlaier	threshold->count = 0;
709145836Smlaier	threshold->last = time_second;
710145836Smlaier}
711145836Smlaier
712145836Smlaiervoid
713145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
714145836Smlaier{
715145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
716145836Smlaier
717145836Smlaier	if (diff >= threshold->seconds)
718145836Smlaier		threshold->count = 0;
719145836Smlaier	else
720145836Smlaier		threshold->count -= threshold->count * diff /
721145836Smlaier		    threshold->seconds;
722145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
723145836Smlaier	threshold->last = t;
724145836Smlaier}
725145836Smlaier
726126258Smlaierint
727145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
728145836Smlaier{
729145836Smlaier	return (threshold->count > threshold->limit);
730145836Smlaier}
731145836Smlaier
732145836Smlaierint
733145836Smlaierpf_src_connlimit(struct pf_state **state)
734145836Smlaier{
735145836Smlaier	struct pf_state	*s;
736145836Smlaier	int bad = 0;
737145836Smlaier
738145836Smlaier	(*state)->src_node->conn++;
739171168Smlaier	(*state)->src.tcp_est = 1;
740145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
741145836Smlaier
742145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
743145836Smlaier	    (*state)->rule.ptr->max_src_conn <
744145836Smlaier	    (*state)->src_node->conn) {
745145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
746145836Smlaier		bad++;
747145836Smlaier	}
748145836Smlaier
749145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
750145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
751145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
752145836Smlaier		bad++;
753145836Smlaier	}
754145836Smlaier
755145836Smlaier	if (!bad)
756145836Smlaier		return (0);
757145836Smlaier
758145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
759145836Smlaier		struct pfr_addr p;
760145836Smlaier		u_int32_t	killed = 0;
761145836Smlaier
762145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
763145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
764145836Smlaier			printf("pf_src_connlimit: blocking address ");
765145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
766145836Smlaier			    (*state)->af);
767145836Smlaier		}
768145836Smlaier
769145836Smlaier		bzero(&p, sizeof(p));
770145836Smlaier		p.pfra_af = (*state)->af;
771145836Smlaier		switch ((*state)->af) {
772145836Smlaier#ifdef INET
773145836Smlaier		case AF_INET:
774145836Smlaier			p.pfra_net = 32;
775145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
776145836Smlaier			break;
777145836Smlaier#endif /* INET */
778145836Smlaier#ifdef INET6
779145836Smlaier		case AF_INET6:
780145836Smlaier			p.pfra_net = 128;
781145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
782145836Smlaier			break;
783145836Smlaier#endif /* INET6 */
784145836Smlaier		}
785145836Smlaier
786145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
787145836Smlaier		    &p, time_second);
788145836Smlaier
789145836Smlaier		/* kill existing states if that's required. */
790145836Smlaier		if ((*state)->rule.ptr->flush) {
791145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
792145836Smlaier
793145836Smlaier			RB_FOREACH(s, pf_state_tree_id, &tree_id) {
794145836Smlaier				/*
795145836Smlaier				 * Kill states from this source.  (Only those
796145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
797145836Smlaier				 * set)
798145836Smlaier				 */
799145836Smlaier				if (s->af == (*state)->af &&
800145836Smlaier				    (((*state)->direction == PF_OUT &&
801145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
802145836Smlaier				    &s->lan.addr, s->af)) ||
803145836Smlaier				    ((*state)->direction == PF_IN &&
804145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
805145836Smlaier				    &s->ext.addr, s->af))) &&
806145836Smlaier				    ((*state)->rule.ptr->flush &
807145836Smlaier				    PF_FLUSH_GLOBAL ||
808145836Smlaier				    (*state)->rule.ptr == s->rule.ptr)) {
809145836Smlaier					s->timeout = PFTM_PURGE;
810145836Smlaier					s->src.state = s->dst.state =
811145836Smlaier					    TCPS_CLOSED;
812145836Smlaier					killed++;
813145836Smlaier				}
814145836Smlaier			}
815145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
816145836Smlaier				printf(", %u states killed", killed);
817145836Smlaier		}
818145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
819145836Smlaier			printf("\n");
820145836Smlaier	}
821145836Smlaier
822145836Smlaier	/* kill this state */
823145836Smlaier	(*state)->timeout = PFTM_PURGE;
824145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
825145836Smlaier	return (1);
826145836Smlaier}
827145836Smlaier
828145836Smlaierint
829130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
830130613Smlaier    struct pf_addr *src, sa_family_t af)
831126258Smlaier{
832130613Smlaier	struct pf_src_node	k;
833126258Smlaier
834130613Smlaier	if (*sn == NULL) {
835130613Smlaier		k.af = af;
836130613Smlaier		PF_ACPY(&k.addr, src, af);
837130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
838130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
839130613Smlaier			k.rule.ptr = rule;
840130613Smlaier		else
841130613Smlaier			k.rule.ptr = NULL;
842130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
843130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
844130613Smlaier	}
845130613Smlaier	if (*sn == NULL) {
846130613Smlaier		if (!rule->max_src_nodes ||
847130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
848130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
849145836Smlaier		else
850145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
851130613Smlaier		if ((*sn) == NULL)
852130613Smlaier			return (-1);
853130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
854145836Smlaier
855145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
856145836Smlaier		    rule->max_src_conn_rate.limit,
857145836Smlaier		    rule->max_src_conn_rate.seconds);
858145836Smlaier
859130613Smlaier		(*sn)->af = af;
860130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
861130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
862130613Smlaier			(*sn)->rule.ptr = rule;
863130613Smlaier		else
864130613Smlaier			(*sn)->rule.ptr = NULL;
865130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
866130613Smlaier		if (RB_INSERT(pf_src_tree,
867130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
868130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
869130613Smlaier				printf("pf: src_tree insert failed: ");
870130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
871130613Smlaier				printf("\n");
872130613Smlaier			}
873130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
874130613Smlaier			return (-1);
875130613Smlaier		}
876130613Smlaier		(*sn)->creation = time_second;
877130613Smlaier		(*sn)->ruletype = rule->action;
878130613Smlaier		if ((*sn)->rule.ptr != NULL)
879130613Smlaier			(*sn)->rule.ptr->src_nodes++;
880130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
881130613Smlaier		pf_status.src_nodes++;
882130613Smlaier	} else {
883130613Smlaier		if (rule->max_src_states &&
884145836Smlaier		    (*sn)->states >= rule->max_src_states) {
885145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
886130613Smlaier			return (-1);
887145836Smlaier		}
888130613Smlaier	}
889130613Smlaier	return (0);
890130613Smlaier}
891126258Smlaier
892130613Smlaierint
893130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
894130613Smlaier{
895126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
896130613Smlaier	state->u.s.kif = kif;
897130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
898126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
899126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
900126258Smlaier			printf(" lan: ");
901126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
902126258Smlaier			    state->af);
903126258Smlaier			printf(" gwy: ");
904126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
905126258Smlaier			    state->af);
906126258Smlaier			printf(" ext: ");
907126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
908126258Smlaier			    state->af);
909130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
910130613Smlaier				printf(" (from sync)");
911126258Smlaier			printf("\n");
912126258Smlaier		}
913126258Smlaier		return (-1);
914126258Smlaier	}
915126258Smlaier
916130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
917126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
918126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
919126258Smlaier			printf(" lan: ");
920126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
921126258Smlaier			    state->af);
922126258Smlaier			printf(" gwy: ");
923126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
924126258Smlaier			    state->af);
925126258Smlaier			printf(" ext: ");
926126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
927126258Smlaier			    state->af);
928130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
929130613Smlaier				printf(" (from sync)");
930126258Smlaier			printf("\n");
931126258Smlaier		}
932130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
933126258Smlaier		return (-1);
934126258Smlaier	}
935126258Smlaier
936130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
937130613Smlaier		state->id = htobe64(pf_status.stateid++);
938130613Smlaier		state->creatorid = pf_status.hostid;
939130613Smlaier	}
940130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
941130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
942130613Smlaier#ifdef __FreeBSD__
943130613Smlaier			printf("pf: state insert failed: "
944130613Smlaier			    "id: %016llx creatorid: %08x",
945130613Smlaier			    (long long)be64toh(state->id),
946130613Smlaier			    ntohl(state->creatorid));
947130613Smlaier#else
948130613Smlaier			printf("pf: state insert failed: "
949130613Smlaier			    "id: %016llx creatorid: %08x",
950130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
951130613Smlaier#endif
952130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
953130613Smlaier				printf(" (from sync)");
954130613Smlaier			printf("\n");
955130613Smlaier		}
956130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
957130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
958130613Smlaier		return (-1);
959130613Smlaier	}
960171168Smlaier	TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
961126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
962126258Smlaier	pf_status.states++;
963171168Smlaier	pfi_kif_ref(kif, PFI_KIF_REF_STATE);
964126258Smlaier#if NPFSYNC
965126258Smlaier	pfsync_insert_state(state);
966126258Smlaier#endif
967126258Smlaier	return (0);
968126258Smlaier}
969126258Smlaier
970126258Smlaiervoid
971171168Smlaierpf_purge_thread(void *v)
972126258Smlaier{
973171168Smlaier	int nloops = 0, s;
974171168Smlaier
975171168Smlaier	for (;;) {
976171168Smlaier		tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
977171168Smlaier
978127145Smlaier#ifdef __FreeBSD__
979171168Smlaier		sx_slock(&pf_consistency_lock);
980171168Smlaier		PF_LOCK();
981126258Smlaier
982171168Smlaier		if (pf_end_threads) {
983171168Smlaier			pf_purge_expired_states(pf_status.states);
984171168Smlaier			pf_purge_expired_fragments();
985171168Smlaier			pf_purge_expired_src_nodes(0);
986171168Smlaier			pf_end_threads++;
987171168Smlaier
988171168Smlaier			sx_sunlock(&pf_consistency_lock);
989171168Smlaier			PF_UNLOCK();
990171168Smlaier			wakeup(pf_purge_thread);
991172836Sjulian			kproc_exit(0);
992171168Smlaier		}
993126261Smlaier#endif
994171168Smlaier		s = splsoftnet();
995126258Smlaier
996171168Smlaier		/* process a fraction of the state table every second */
997171168Smlaier		pf_purge_expired_states(1 + (pf_status.states
998171168Smlaier		    / pf_default_rule.timeout[PFTM_INTERVAL]));
999171168Smlaier
1000171168Smlaier		/* purge other expired types every PFTM_INTERVAL seconds */
1001171168Smlaier		if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
1002171168Smlaier			pf_purge_expired_fragments();
1003171168Smlaier			pf_purge_expired_src_nodes(0);
1004171168Smlaier			nloops = 0;
1005171168Smlaier		}
1006171168Smlaier
1007171168Smlaier		splx(s);
1008127145Smlaier#ifdef __FreeBSD__
1009171168Smlaier		PF_UNLOCK();
1010171168Smlaier		sx_sunlock(&pf_consistency_lock);
1011126261Smlaier#endif
1012171168Smlaier	}
1013126258Smlaier}
1014126258Smlaier
1015126258Smlaieru_int32_t
1016126258Smlaierpf_state_expires(const struct pf_state *state)
1017126258Smlaier{
1018126258Smlaier	u_int32_t	timeout;
1019126258Smlaier	u_int32_t	start;
1020126258Smlaier	u_int32_t	end;
1021126258Smlaier	u_int32_t	states;
1022126258Smlaier
1023126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1024126258Smlaier	if (state->timeout == PFTM_PURGE)
1025126261Smlaier		return (time_second);
1026126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1027126258Smlaier		return (0);
1028127145Smlaier#ifdef __FreeBSD__
1029171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED,
1030171168Smlaier	    ("pf_state_expires: timeout == PFTM_UNLINKED"));
1031126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1032126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1033126261Smlaier#else
1034171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED);
1035126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1036126261Smlaier#endif
1037126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1038126258Smlaier	if (!timeout)
1039126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1040126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1041126258Smlaier	if (start) {
1042126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1043126258Smlaier		states = state->rule.ptr->states;
1044126258Smlaier	} else {
1045126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1046126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1047126258Smlaier		states = pf_status.states;
1048126258Smlaier	}
1049126258Smlaier	if (end && states > start && start < end) {
1050126258Smlaier		if (states < end)
1051126258Smlaier			return (state->expire + timeout * (end - states) /
1052126258Smlaier			    (end - start));
1053126258Smlaier		else
1054126261Smlaier			return (time_second);
1055126258Smlaier	}
1056126258Smlaier	return (state->expire + timeout);
1057126258Smlaier}
1058126258Smlaier
1059126258Smlaiervoid
1060171168Smlaierpf_purge_expired_src_nodes(int waslocked)
1061126258Smlaier{
1062130613Smlaier	 struct pf_src_node		*cur, *next;
1063171168Smlaier	 int				 locked = waslocked;
1064126258Smlaier
1065130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1066130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1067126258Smlaier
1068130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1069171168Smlaier			 if (! locked) {
1070171168Smlaier#ifdef __FreeBSD__
1071171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1072171168Smlaier					 PF_UNLOCK();
1073171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1074171168Smlaier					 sx_xlock(&pf_consistency_lock);
1075171168Smlaier					 PF_LOCK();
1076171168Smlaier				 }
1077171168Smlaier#else
1078171168Smlaier				 rw_enter_write(&pf_consistency_lock);
1079171168Smlaier#endif
1080171168Smlaier			 	 next = RB_NEXT(pf_src_tree,
1081171168Smlaier				     &tree_src_tracking, cur);
1082171168Smlaier				 locked = 1;
1083171168Smlaier			 }
1084130613Smlaier			 if (cur->rule.ptr != NULL) {
1085130613Smlaier				 cur->rule.ptr->src_nodes--;
1086130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1087130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1088130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1089130613Smlaier			 }
1090130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1091130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1092130613Smlaier			 pf_status.src_nodes--;
1093130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1094130613Smlaier		 }
1095130613Smlaier	 }
1096171168Smlaier
1097171168Smlaier	 if (locked && !waslocked)
1098171168Smlaier#ifdef __FreeBSD__
1099171168Smlaier		sx_downgrade(&pf_consistency_lock);
1100171168Smlaier#else
1101171168Smlaier		rw_exit_write(&pf_consistency_lock);
1102171168Smlaier#endif
1103130613Smlaier}
1104126258Smlaier
1105130613Smlaiervoid
1106130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1107130613Smlaier{
1108130613Smlaier	u_int32_t timeout;
1109126258Smlaier
1110130613Smlaier	if (s->src_node != NULL) {
1111145836Smlaier		if (s->proto == IPPROTO_TCP) {
1112171168Smlaier			if (s->src.tcp_est)
1113145836Smlaier				--s->src_node->conn;
1114145836Smlaier		}
1115130613Smlaier		if (--s->src_node->states <= 0) {
1116130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1117130613Smlaier			if (!timeout)
1118130613Smlaier				timeout =
1119130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1120130613Smlaier			s->src_node->expire = time_second + timeout;
1121130613Smlaier		}
1122130613Smlaier	}
1123130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1124130613Smlaier		if (--s->nat_src_node->states <= 0) {
1125130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1126130613Smlaier			if (!timeout)
1127130613Smlaier				timeout =
1128130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1129130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1130130613Smlaier		}
1131130613Smlaier	}
1132130613Smlaier	s->src_node = s->nat_src_node = NULL;
1133130613Smlaier}
1134126258Smlaier
1135171168Smlaier/* callers should be at splsoftnet */
1136130613Smlaiervoid
1137171168Smlaierpf_unlink_state(struct pf_state *cur)
1138145836Smlaier{
1139148196Smlaier#ifdef __FreeBSD__
1140153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1141148196Smlaier		return;
1142153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1143148196Smlaier#endif
1144171168Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST) {
1145162238Scsjp#ifdef __FreeBSD__
1146162238Scsjp		pf_send_tcp(NULL, cur->rule.ptr, cur->af,
1147162238Scsjp#else
1148145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1149162238Scsjp#endif
1150145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1151145836Smlaier		    cur->ext.port, cur->lan.port,
1152145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1153171168Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
1154171168Smlaier	}
1155145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1156145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1157145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1158145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1159145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1160145836Smlaier#if NPFSYNC
1161171168Smlaier	if (cur->creatorid == pf_status.hostid)
1162171168Smlaier		pfsync_delete_state(cur);
1163145836Smlaier#endif
1164171168Smlaier	cur->timeout = PFTM_UNLINKED;
1165145836Smlaier	pf_src_tree_remove_state(cur);
1166171168Smlaier}
1167171168Smlaier
1168171168Smlaier/* callers should be at splsoftnet and hold the
1169171168Smlaier * write_lock on pf_consistency_lock */
1170171168Smlaiervoid
1171171168Smlaierpf_free_state(struct pf_state *cur)
1172171168Smlaier{
1173171168Smlaier#if NPFSYNC
1174171168Smlaier	if (pfsyncif != NULL &&
1175171168Smlaier	    (pfsyncif->sc_bulk_send_next == cur ||
1176171168Smlaier	    pfsyncif->sc_bulk_terminator == cur))
1177171168Smlaier		return;
1178171168Smlaier#endif
1179171168Smlaier#ifdef __FreeBSD__
1180171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED,
1181171168Smlaier	    ("pf_free_state: cur->timeout != PFTM_UNLINKED"));
1182171168Smlaier#else
1183171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED);
1184171168Smlaier#endif
1185145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1186145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1187145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1188145836Smlaier	if (cur->nat_rule.ptr != NULL)
1189145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1190145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1191145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1192145836Smlaier	if (cur->anchor.ptr != NULL)
1193145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1194145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1195145836Smlaier	pf_normalize_tcp_cleanup(cur);
1196171168Smlaier	pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
1197171168Smlaier	TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
1198145836Smlaier	if (cur->tag)
1199145836Smlaier		pf_tag_unref(cur->tag);
1200145836Smlaier	pool_put(&pf_state_pl, cur);
1201145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1202145836Smlaier	pf_status.states--;
1203145836Smlaier}
1204145836Smlaier
1205145836Smlaiervoid
1206171168Smlaierpf_purge_expired_states(u_int32_t maxcheck)
1207130613Smlaier{
1208171168Smlaier	static struct pf_state	*cur = NULL;
1209171168Smlaier	struct pf_state		*next;
1210171168Smlaier	int 			 locked = 0;
1211130613Smlaier
1212171168Smlaier	while (maxcheck--) {
1213171168Smlaier		/* wrap to start of list when we hit the end */
1214171168Smlaier		if (cur == NULL) {
1215171168Smlaier			cur = TAILQ_FIRST(&state_list);
1216171168Smlaier			if (cur == NULL)
1217171168Smlaier				break;	/* list empty */
1218171168Smlaier		}
1219171168Smlaier
1220171168Smlaier		/* get next state, as cur may get deleted */
1221171168Smlaier		next = TAILQ_NEXT(cur, u.s.entry_list);
1222171168Smlaier
1223171168Smlaier		if (cur->timeout == PFTM_UNLINKED) {
1224171168Smlaier			/* free unlinked state */
1225171168Smlaier			if (! locked) {
1226171168Smlaier#ifdef __FreeBSD__
1227171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1228171168Smlaier					 PF_UNLOCK();
1229171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1230171168Smlaier					 sx_xlock(&pf_consistency_lock);
1231171168Smlaier					 PF_LOCK();
1232171168Smlaier				 }
1233171168Smlaier#else
1234171168Smlaier				rw_enter_write(&pf_consistency_lock);
1235171168Smlaier#endif
1236171168Smlaier				locked = 1;
1237171168Smlaier			}
1238171168Smlaier			pf_free_state(cur);
1239171168Smlaier		} else if (pf_state_expires(cur) <= time_second) {
1240171168Smlaier			/* unlink and free expired state */
1241171168Smlaier			pf_unlink_state(cur);
1242171168Smlaier			if (! locked) {
1243171168Smlaier#ifdef __FreeBSD__
1244171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1245171168Smlaier					 PF_UNLOCK();
1246171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1247171168Smlaier					 sx_xlock(&pf_consistency_lock);
1248171168Smlaier					 PF_LOCK();
1249171168Smlaier				 }
1250171168Smlaier#else
1251171168Smlaier				rw_enter_write(&pf_consistency_lock);
1252171168Smlaier#endif
1253171168Smlaier				locked = 1;
1254171168Smlaier			}
1255171168Smlaier			pf_free_state(cur);
1256171168Smlaier		}
1257171168Smlaier		cur = next;
1258126258Smlaier	}
1259171168Smlaier
1260171168Smlaier	if (locked)
1261171168Smlaier#ifdef __FreeBSD__
1262171168Smlaier		sx_downgrade(&pf_consistency_lock);
1263171168Smlaier#else
1264171168Smlaier		rw_exit_write(&pf_consistency_lock);
1265171168Smlaier#endif
1266126258Smlaier}
1267126258Smlaier
1268126258Smlaierint
1269126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1270126258Smlaier{
1271126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1272126258Smlaier		return (0);
1273126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1274126258Smlaier		return (1);
1275126258Smlaier	return (0);
1276126258Smlaier}
1277126258Smlaier
1278126258Smlaiervoid
1279126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1280126258Smlaier{
1281126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1282126258Smlaier		return;
1283126258Smlaier	pfr_detach_table(aw->p.tbl);
1284126258Smlaier	aw->p.tbl = NULL;
1285126258Smlaier}
1286126258Smlaier
1287126258Smlaiervoid
1288126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1289126258Smlaier{
1290126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1291126258Smlaier
1292126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1293126258Smlaier		return;
1294126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1295126258Smlaier		kt = kt->pfrkt_root;
1296126258Smlaier	aw->p.tbl = NULL;
1297126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1298126258Smlaier		kt->pfrkt_cnt : -1;
1299126258Smlaier}
1300126258Smlaier
1301126258Smlaiervoid
1302126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1303126258Smlaier{
1304126258Smlaier	switch (af) {
1305126258Smlaier#ifdef INET
1306126258Smlaier	case AF_INET: {
1307126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1308126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1309126258Smlaier		    (a>>8)&255, a&255);
1310126258Smlaier		if (p) {
1311126258Smlaier			p = ntohs(p);
1312126258Smlaier			printf(":%u", p);
1313126258Smlaier		}
1314126258Smlaier		break;
1315126258Smlaier	}
1316126258Smlaier#endif /* INET */
1317126258Smlaier#ifdef INET6
1318126258Smlaier	case AF_INET6: {
1319126258Smlaier		u_int16_t b;
1320126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1321126258Smlaier		    maxstart = 0, maxend = 0;
1322126258Smlaier		for (i = 0; i < 8; i++) {
1323126258Smlaier			if (!addr->addr16[i]) {
1324126258Smlaier				if (curstart == 255)
1325126258Smlaier					curstart = i;
1326126258Smlaier				else
1327126258Smlaier					curend = i;
1328126258Smlaier			} else {
1329126258Smlaier				if (curstart) {
1330126258Smlaier					if ((curend - curstart) >
1331126258Smlaier					    (maxend - maxstart)) {
1332126258Smlaier						maxstart = curstart;
1333126258Smlaier						maxend = curend;
1334126258Smlaier						curstart = 255;
1335126258Smlaier					}
1336126258Smlaier				}
1337126258Smlaier			}
1338126258Smlaier		}
1339126258Smlaier		for (i = 0; i < 8; i++) {
1340126258Smlaier			if (i >= maxstart && i <= maxend) {
1341126258Smlaier				if (maxend != 7) {
1342126258Smlaier					if (i == maxstart)
1343126258Smlaier						printf(":");
1344126258Smlaier				} else {
1345126258Smlaier					if (i == maxend)
1346126258Smlaier						printf(":");
1347126258Smlaier				}
1348126258Smlaier			} else {
1349126258Smlaier				b = ntohs(addr->addr16[i]);
1350126258Smlaier				printf("%x", b);
1351126258Smlaier				if (i < 7)
1352126258Smlaier					printf(":");
1353126258Smlaier			}
1354126258Smlaier		}
1355126258Smlaier		if (p) {
1356126258Smlaier			p = ntohs(p);
1357126258Smlaier			printf("[%u]", p);
1358126258Smlaier		}
1359126258Smlaier		break;
1360126258Smlaier	}
1361126258Smlaier#endif /* INET6 */
1362126258Smlaier	}
1363126258Smlaier}
1364126258Smlaier
1365126258Smlaiervoid
1366126258Smlaierpf_print_state(struct pf_state *s)
1367126258Smlaier{
1368126258Smlaier	switch (s->proto) {
1369126258Smlaier	case IPPROTO_TCP:
1370126258Smlaier		printf("TCP ");
1371126258Smlaier		break;
1372126258Smlaier	case IPPROTO_UDP:
1373126258Smlaier		printf("UDP ");
1374126258Smlaier		break;
1375126258Smlaier	case IPPROTO_ICMP:
1376126258Smlaier		printf("ICMP ");
1377126258Smlaier		break;
1378126258Smlaier	case IPPROTO_ICMPV6:
1379126258Smlaier		printf("ICMPV6 ");
1380126258Smlaier		break;
1381126258Smlaier	default:
1382126258Smlaier		printf("%u ", s->proto);
1383126258Smlaier		break;
1384126258Smlaier	}
1385126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1386126258Smlaier	printf(" ");
1387126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1388126258Smlaier	printf(" ");
1389126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1390126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1391126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1392126258Smlaier	if (s->src.wscale && s->dst.wscale)
1393126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1394126258Smlaier	printf("]");
1395126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1396126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1397126258Smlaier	if (s->src.wscale && s->dst.wscale)
1398126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1399126258Smlaier	printf("]");
1400126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1401126258Smlaier}
1402126258Smlaier
1403126258Smlaiervoid
1404126258Smlaierpf_print_flags(u_int8_t f)
1405126258Smlaier{
1406126258Smlaier	if (f)
1407126258Smlaier		printf(" ");
1408126258Smlaier	if (f & TH_FIN)
1409126258Smlaier		printf("F");
1410126258Smlaier	if (f & TH_SYN)
1411126258Smlaier		printf("S");
1412126258Smlaier	if (f & TH_RST)
1413126258Smlaier		printf("R");
1414126258Smlaier	if (f & TH_PUSH)
1415126258Smlaier		printf("P");
1416126258Smlaier	if (f & TH_ACK)
1417126258Smlaier		printf("A");
1418126258Smlaier	if (f & TH_URG)
1419126258Smlaier		printf("U");
1420126258Smlaier	if (f & TH_ECE)
1421126258Smlaier		printf("E");
1422126258Smlaier	if (f & TH_CWR)
1423126258Smlaier		printf("W");
1424126258Smlaier}
1425126258Smlaier
1426126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1427126258Smlaier	do {							\
1428126258Smlaier		while (head[i] != cur) {			\
1429126258Smlaier			head[i]->skip[i].ptr = cur;		\
1430126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1431126258Smlaier		}						\
1432126258Smlaier	} while (0)
1433126258Smlaier
1434126258Smlaiervoid
1435126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1436126258Smlaier{
1437126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1438126258Smlaier	int i;
1439126258Smlaier
1440126258Smlaier	cur = TAILQ_FIRST(rules);
1441126258Smlaier	prev = cur;
1442126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1443126258Smlaier		head[i] = cur;
1444126258Smlaier	while (cur != NULL) {
1445126258Smlaier
1446130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1447126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1448126258Smlaier		if (cur->direction != prev->direction)
1449126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1450126258Smlaier		if (cur->af != prev->af)
1451126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1452126258Smlaier		if (cur->proto != prev->proto)
1453126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1454145836Smlaier		if (cur->src.neg != prev->src.neg ||
1455126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1456126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1457126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1458126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1459126258Smlaier		    cur->src.port_op != prev->src.port_op)
1460126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1461145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1462126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1463126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1464126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1465126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1466126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1467126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1468126258Smlaier
1469126258Smlaier		prev = cur;
1470126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1471126258Smlaier	}
1472126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1473126258Smlaier		PF_SET_SKIP_STEPS(i);
1474126258Smlaier}
1475126258Smlaier
1476126258Smlaierint
1477126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1478126258Smlaier{
1479126258Smlaier	if (aw1->type != aw2->type)
1480126258Smlaier		return (1);
1481126258Smlaier	switch (aw1->type) {
1482126258Smlaier	case PF_ADDR_ADDRMASK:
1483126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1484126258Smlaier			return (1);
1485126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1486126258Smlaier			return (1);
1487126258Smlaier		return (0);
1488126258Smlaier	case PF_ADDR_DYNIFTL:
1489130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1490126258Smlaier	case PF_ADDR_NOROUTE:
1491171168Smlaier	case PF_ADDR_URPFFAILED:
1492126258Smlaier		return (0);
1493126258Smlaier	case PF_ADDR_TABLE:
1494126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1495171168Smlaier	case PF_ADDR_RTLABEL:
1496171168Smlaier		return (aw1->v.rtlabel != aw2->v.rtlabel);
1497126258Smlaier	default:
1498126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1499126258Smlaier		return (1);
1500126258Smlaier	}
1501126258Smlaier}
1502126258Smlaier
1503126258Smlaieru_int16_t
1504126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1505126258Smlaier{
1506126258Smlaier	u_int32_t	l;
1507126258Smlaier
1508126258Smlaier	if (udp && !cksum)
1509126258Smlaier		return (0x0000);
1510126258Smlaier	l = cksum + old - new;
1511126258Smlaier	l = (l >> 16) + (l & 65535);
1512126258Smlaier	l = l & 65535;
1513126258Smlaier	if (udp && !l)
1514126258Smlaier		return (0xFFFF);
1515126258Smlaier	return (l);
1516126258Smlaier}
1517126258Smlaier
1518126258Smlaiervoid
1519126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1520126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1521126258Smlaier{
1522126258Smlaier	struct pf_addr	ao;
1523126258Smlaier	u_int16_t	po = *p;
1524126258Smlaier
1525126258Smlaier	PF_ACPY(&ao, a, af);
1526126258Smlaier	PF_ACPY(a, an, af);
1527126258Smlaier
1528126258Smlaier	*p = pn;
1529126258Smlaier
1530126258Smlaier	switch (af) {
1531126258Smlaier#ifdef INET
1532126258Smlaier	case AF_INET:
1533126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1534126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1535126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1536126258Smlaier		*p = pn;
1537126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1538126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1539126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1540126258Smlaier		    po, pn, u);
1541126258Smlaier		break;
1542126258Smlaier#endif /* INET */
1543126258Smlaier#ifdef INET6
1544126258Smlaier	case AF_INET6:
1545126258Smlaier		*pc = 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(pf_cksum_fixup(*pc,
1548126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1549126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1550126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1551126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1552126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1553126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1554126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1555126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1556126258Smlaier		    po, pn, u);
1557126258Smlaier		break;
1558126258Smlaier#endif /* INET6 */
1559126258Smlaier	}
1560126258Smlaier}
1561126258Smlaier
1562126258Smlaier
1563126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1564126258Smlaiervoid
1565126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1566126258Smlaier{
1567126258Smlaier	u_int32_t	ao;
1568126258Smlaier
1569126258Smlaier	memcpy(&ao, a, sizeof(ao));
1570126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1571126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1572126258Smlaier	    ao % 65536, an % 65536, u);
1573126258Smlaier}
1574126258Smlaier
1575126258Smlaier#ifdef INET6
1576126258Smlaiervoid
1577126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1578126258Smlaier{
1579126258Smlaier	struct pf_addr	ao;
1580126258Smlaier
1581126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1582126258Smlaier	PF_ACPY(a, an, AF_INET6);
1583126258Smlaier
1584126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1585126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1586126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1587126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1588126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1589126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1590126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1591126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1592126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1593126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1594126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1595126258Smlaier}
1596126258Smlaier#endif /* INET6 */
1597126258Smlaier
1598126258Smlaiervoid
1599126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1600126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1601126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1602126258Smlaier{
1603126258Smlaier	struct pf_addr	oia, ooa;
1604126258Smlaier
1605126258Smlaier	PF_ACPY(&oia, ia, af);
1606126258Smlaier	PF_ACPY(&ooa, oa, af);
1607126258Smlaier
1608126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1609126258Smlaier	if (ip != NULL) {
1610126258Smlaier		u_int16_t	oip = *ip;
1611127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1612126258Smlaier
1613126258Smlaier		if (pc != NULL)
1614126258Smlaier			opc = *pc;
1615126258Smlaier		*ip = np;
1616126258Smlaier		if (pc != NULL)
1617126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1618126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1619126258Smlaier		if (pc != NULL)
1620126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1621126258Smlaier	}
1622126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1623126258Smlaier	PF_ACPY(ia, na, af);
1624126258Smlaier	switch (af) {
1625126258Smlaier#ifdef INET
1626126258Smlaier	case AF_INET: {
1627126258Smlaier		u_int32_t	 oh2c = *h2c;
1628126258Smlaier
1629126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1630126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1631126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1632126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1633126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1634126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1635126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1636126258Smlaier		break;
1637126258Smlaier	}
1638126258Smlaier#endif /* INET */
1639126258Smlaier#ifdef INET6
1640126258Smlaier	case AF_INET6:
1641126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1642126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1643126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1644126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1645126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1646126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1647126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1648126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1649126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1650126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1651126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1652126258Smlaier		break;
1653126258Smlaier#endif /* INET6 */
1654126258Smlaier	}
1655126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1656126258Smlaier	PF_ACPY(oa, na, af);
1657126258Smlaier	switch (af) {
1658126258Smlaier#ifdef INET
1659126258Smlaier	case AF_INET:
1660126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1661126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1662126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1663126258Smlaier		break;
1664126258Smlaier#endif /* INET */
1665126258Smlaier#ifdef INET6
1666126258Smlaier	case AF_INET6:
1667126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1668126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1669126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1670126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1671126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1672126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1673126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1674126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1675126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1676126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1677126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1678126258Smlaier		break;
1679126258Smlaier#endif /* INET6 */
1680126258Smlaier	}
1681126258Smlaier}
1682126258Smlaier
1683171168Smlaier
1684171168Smlaier/*
1685171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option
1686171168Smlaier * (credits to Krzysztof Pfaff for report and patch)
1687171168Smlaier */
1688171168Smlaierint
1689171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
1690171168Smlaier    struct tcphdr *th, struct pf_state_peer *dst)
1691171168Smlaier{
1692171168Smlaier	int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
1693171168Smlaier#ifdef __FreeBSD__
1694171168Smlaier	u_int8_t opts[TCP_MAXOLEN], *opt = opts;
1695171168Smlaier#else
1696171168Smlaier	u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
1697171168Smlaier#endif
1698171168Smlaier	int copyback = 0, i, olen;
1699171168Smlaier	struct sackblk sack;
1700171168Smlaier
1701171168Smlaier#define TCPOLEN_SACKLEN	(TCPOLEN_SACK + 2)
1702171168Smlaier	if (hlen < TCPOLEN_SACKLEN ||
1703171168Smlaier	    !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
1704171168Smlaier		return 0;
1705171168Smlaier
1706171168Smlaier	while (hlen >= TCPOLEN_SACKLEN) {
1707171168Smlaier		olen = opt[1];
1708171168Smlaier		switch (*opt) {
1709171168Smlaier		case TCPOPT_EOL:	/* FALLTHROUGH */
1710171168Smlaier		case TCPOPT_NOP:
1711171168Smlaier			opt++;
1712171168Smlaier			hlen--;
1713171168Smlaier			break;
1714171168Smlaier		case TCPOPT_SACK:
1715171168Smlaier			if (olen > hlen)
1716171168Smlaier				olen = hlen;
1717171168Smlaier			if (olen >= TCPOLEN_SACKLEN) {
1718171168Smlaier				for (i = 2; i + TCPOLEN_SACK <= olen;
1719171168Smlaier				    i += TCPOLEN_SACK) {
1720171168Smlaier					memcpy(&sack, &opt[i], sizeof(sack));
1721171168Smlaier					pf_change_a(&sack.start, &th->th_sum,
1722171168Smlaier					    htonl(ntohl(sack.start) -
1723171168Smlaier					    dst->seqdiff), 0);
1724171168Smlaier					pf_change_a(&sack.end, &th->th_sum,
1725171168Smlaier					    htonl(ntohl(sack.end) -
1726171168Smlaier					    dst->seqdiff), 0);
1727171168Smlaier					memcpy(&opt[i], &sack, sizeof(sack));
1728171168Smlaier				}
1729171168Smlaier				copyback = 1;
1730171168Smlaier			}
1731171168Smlaier			/* FALLTHROUGH */
1732171168Smlaier		default:
1733171168Smlaier			if (olen < 2)
1734171168Smlaier				olen = 2;
1735171168Smlaier			hlen -= olen;
1736171168Smlaier			opt += olen;
1737171168Smlaier		}
1738171168Smlaier	}
1739171168Smlaier
1740171168Smlaier	if (copyback)
1741171168Smlaier#ifdef __FreeBSD__
1742171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts);
1743171168Smlaier#else
1744171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, opts);
1745171168Smlaier#endif
1746171168Smlaier	return (copyback);
1747171168Smlaier}
1748171168Smlaier
1749126258Smlaiervoid
1750162238Scsjp#ifdef __FreeBSD__
1751162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
1752162238Scsjp#else
1753126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1754162238Scsjp#endif
1755126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1756126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1757145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1758171168Smlaier    u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
1759126258Smlaier{
1760126258Smlaier	struct mbuf	*m;
1761171168Smlaier	int		 len, tlen;
1762126258Smlaier#ifdef INET
1763171168Smlaier	struct ip	*h;
1764126258Smlaier#endif /* INET */
1765126258Smlaier#ifdef INET6
1766171168Smlaier	struct ip6_hdr	*h6;
1767126258Smlaier#endif /* INET6 */
1768171168Smlaier	struct tcphdr	*th;
1769171168Smlaier	char		*opt;
1770171168Smlaier	struct pf_mtag	*pf_mtag;
1771126258Smlaier
1772171168Smlaier#ifdef __FreeBSD__
1773171168Smlaier	KASSERT(
1774171168Smlaier#ifdef INET
1775171168Smlaier	    af == AF_INET
1776171168Smlaier#else
1777171168Smlaier	    0
1778171168Smlaier#endif
1779171168Smlaier	    ||
1780171168Smlaier#ifdef INET6
1781171168Smlaier	    af == AF_INET6
1782171168Smlaier#else
1783171168Smlaier	    0
1784171168Smlaier#endif
1785171168Smlaier	    , ("Unsupported AF %d", af));
1786171168Smlaier	len = 0;
1787171168Smlaier	th = NULL;
1788171168Smlaier#ifdef INET
1789171168Smlaier	h = NULL;
1790171168Smlaier#endif
1791171168Smlaier#ifdef INET6
1792171168Smlaier	h6 = NULL;
1793171168Smlaier#endif
1794171168Smlaier#endif
1795171168Smlaier
1796126258Smlaier	/* maximum segment size tcp option */
1797126258Smlaier	tlen = sizeof(struct tcphdr);
1798126258Smlaier	if (mss)
1799126258Smlaier		tlen += 4;
1800126258Smlaier
1801126258Smlaier	switch (af) {
1802126258Smlaier#ifdef INET
1803126258Smlaier	case AF_INET:
1804126258Smlaier		len = sizeof(struct ip) + tlen;
1805126258Smlaier		break;
1806126258Smlaier#endif /* INET */
1807126258Smlaier#ifdef INET6
1808126258Smlaier	case AF_INET6:
1809126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1810126258Smlaier		break;
1811126258Smlaier#endif /* INET6 */
1812126258Smlaier	}
1813126258Smlaier
1814126258Smlaier	/* create outgoing mbuf */
1815132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1816132280Smlaier	if (m == NULL)
1817132280Smlaier		return;
1818162238Scsjp#ifdef __FreeBSD__
1819162238Scsjp#ifdef MAC
1820162238Scsjp	if (replyto)
1821173102Srwatson		mac_netinet_firewall_reply(replyto, m);
1822162238Scsjp	else
1823173018Srwatson		mac_netinet_firewall_send(m);
1824162238Scsjp#else
1825162238Scsjp	(void)replyto;
1826162238Scsjp#endif
1827162238Scsjp#endif
1828171168Smlaier	if ((pf_mtag = pf_get_mtag(m)) == NULL) {
1829171168Smlaier		m_freem(m);
1830171168Smlaier		return;
1831171168Smlaier	}
1832171168Smlaier	if (tag)
1833145836Smlaier#ifdef __FreeBSD__
1834145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1835132280Smlaier#else
1836171168Smlaier		pf_mtag->flags |= PF_TAG_GENERATED;
1837171168Smlaier#endif
1838145836Smlaier
1839171168Smlaier	pf_mtag->tag = rtag;
1840171168Smlaier
1841171168Smlaier	if (r != NULL && r->rtableid >= 0)
1842178888Sjulian#ifdef __FreeBSD__
1843178888Sjulian	{
1844178888Sjulian		M_SETFIB(m, r->rtableid);
1845178888Sjulian#endif
1846171168Smlaier		pf_mtag->rtableid = r->rtableid;
1847178888Sjulian#ifdef __FreeBSD__
1848178888Sjulian	}
1849178888Sjulian#endif
1850126258Smlaier#ifdef ALTQ
1851126258Smlaier	if (r != NULL && r->qid) {
1852171168Smlaier		pf_mtag->qid = r->qid;
1853171168Smlaier		/* add hints for ecn */
1854171168Smlaier		pf_mtag->af = af;
1855171168Smlaier		pf_mtag->hdr = mtod(m, struct ip *);
1856126258Smlaier	}
1857145836Smlaier#endif /* ALTQ */
1858126258Smlaier	m->m_data += max_linkhdr;
1859126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1860126258Smlaier	m->m_pkthdr.rcvif = NULL;
1861126258Smlaier	bzero(m->m_data, len);
1862126258Smlaier	switch (af) {
1863126258Smlaier#ifdef INET
1864126258Smlaier	case AF_INET:
1865126258Smlaier		h = mtod(m, struct ip *);
1866126258Smlaier
1867126258Smlaier		/* IP header fields included in the TCP checksum */
1868126258Smlaier		h->ip_p = IPPROTO_TCP;
1869126258Smlaier		h->ip_len = htons(tlen);
1870126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1871126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1872126258Smlaier
1873126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1874126258Smlaier		break;
1875126258Smlaier#endif /* INET */
1876126258Smlaier#ifdef INET6
1877126258Smlaier	case AF_INET6:
1878126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1879126258Smlaier
1880126258Smlaier		/* IP header fields included in the TCP checksum */
1881126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1882126258Smlaier		h6->ip6_plen = htons(tlen);
1883126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1884126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1885126258Smlaier
1886126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1887126258Smlaier		break;
1888126258Smlaier#endif /* INET6 */
1889126258Smlaier	}
1890126258Smlaier
1891126258Smlaier	/* TCP header */
1892126258Smlaier	th->th_sport = sport;
1893126258Smlaier	th->th_dport = dport;
1894126258Smlaier	th->th_seq = htonl(seq);
1895126258Smlaier	th->th_ack = htonl(ack);
1896126258Smlaier	th->th_off = tlen >> 2;
1897126258Smlaier	th->th_flags = flags;
1898126258Smlaier	th->th_win = htons(win);
1899126258Smlaier
1900126258Smlaier	if (mss) {
1901126258Smlaier		opt = (char *)(th + 1);
1902126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1903126258Smlaier		opt[1] = 4;
1904126258Smlaier		HTONS(mss);
1905126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1906126258Smlaier	}
1907126258Smlaier
1908126258Smlaier	switch (af) {
1909126258Smlaier#ifdef INET
1910126258Smlaier	case AF_INET:
1911126258Smlaier		/* TCP checksum */
1912126258Smlaier		th->th_sum = in_cksum(m, len);
1913126258Smlaier
1914126258Smlaier		/* Finish the IP header */
1915126258Smlaier		h->ip_v = 4;
1916126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1917126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1918127145Smlaier#ifdef __FreeBSD__
1919130613Smlaier		h->ip_off = path_mtu_discovery ? IP_DF : 0;
1920130613Smlaier		h->ip_len = len;
1921126261Smlaier#else
1922126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1923130613Smlaier		h->ip_len = htons(len);
1924126261Smlaier#endif
1925126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1926126258Smlaier		h->ip_sum = 0;
1927145836Smlaier		if (eh == NULL) {
1928127145Smlaier#ifdef __FreeBSD__
1929145836Smlaier			PF_UNLOCK();
1930145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1931145836Smlaier			    (void *)NULL, (void *)NULL);
1932145836Smlaier			PF_LOCK();
1933126261Smlaier#else /* ! __FreeBSD__ */
1934145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1935145836Smlaier			    (void *)NULL, (void *)NULL);
1936126261Smlaier#endif
1937145836Smlaier		} else {
1938145836Smlaier			struct route		 ro;
1939145836Smlaier			struct rtentry		 rt;
1940145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1941145836Smlaier
1942145836Smlaier			if (ifp == NULL) {
1943145836Smlaier				m_freem(m);
1944145836Smlaier				return;
1945145836Smlaier			}
1946145836Smlaier			rt.rt_ifp = ifp;
1947145836Smlaier			ro.ro_rt = &rt;
1948145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1949145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1950145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1951145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1952145836Smlaier			e->ether_type = eh->ether_type;
1953145836Smlaier#ifdef __FreeBSD__
1954145836Smlaier			PF_UNLOCK();
1955145836Smlaier			/* XXX_IMPORT: later */
1956145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1957145836Smlaier			    (void *)NULL, (void *)NULL);
1958145836Smlaier			PF_LOCK();
1959145836Smlaier#else /* ! __FreeBSD__ */
1960145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
1961145836Smlaier			    (void *)NULL, (void *)NULL);
1962145836Smlaier#endif
1963145836Smlaier		}
1964126258Smlaier		break;
1965126258Smlaier#endif /* INET */
1966126258Smlaier#ifdef INET6
1967126258Smlaier	case AF_INET6:
1968126258Smlaier		/* TCP checksum */
1969126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1970126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1971126258Smlaier
1972126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1973126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1974126258Smlaier
1975127145Smlaier#ifdef __FreeBSD__
1976126261Smlaier		PF_UNLOCK();
1977126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1978126261Smlaier		PF_LOCK();
1979126261Smlaier#else
1980126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1981126261Smlaier#endif
1982126258Smlaier		break;
1983126258Smlaier#endif /* INET6 */
1984126258Smlaier	}
1985126258Smlaier}
1986126258Smlaier
1987126258Smlaiervoid
1988126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1989126258Smlaier    struct pf_rule *r)
1990126258Smlaier{
1991171168Smlaier	struct pf_mtag	*pf_mtag;
1992126258Smlaier	struct mbuf	*m0;
1993127145Smlaier#ifdef __FreeBSD__
1994126261Smlaier	struct ip *ip;
1995126261Smlaier#endif
1996126258Smlaier
1997132280Smlaier#ifdef __FreeBSD__
1998132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
1999132280Smlaier	if (m0 == NULL)
2000132280Smlaier		return;
2001132280Smlaier#else
2002126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
2003171168Smlaier#endif
2004171168Smlaier	if ((pf_mtag = pf_get_mtag(m0)) == NULL)
2005126258Smlaier		return;
2006171168Smlaier#ifdef __FreeBSD__
2007171168Smlaier	/* XXX: revisit */
2008171168Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
2009171168Smlaier#else
2010171168Smlaier	pf_mtag->flags |= PF_TAG_GENERATED;
2011132280Smlaier#endif
2012126258Smlaier
2013171168Smlaier	if (r->rtableid >= 0)
2014178888Sjulian#ifdef __FreeBSD__
2015178888Sjulian	{
2016178888Sjulian		M_SETFIB(m0, r->rtableid);
2017178888Sjulian#endif
2018171168Smlaier		pf_mtag->rtableid = r->rtableid;
2019178888Sjulian#ifdef __FreeBSD__
2020178888Sjulian	}
2021178888Sjulian#endif
2022171168Smlaier
2023126258Smlaier#ifdef ALTQ
2024126258Smlaier	if (r->qid) {
2025171168Smlaier		pf_mtag->qid = r->qid;
2026171168Smlaier		/* add hints for ecn */
2027171168Smlaier		pf_mtag->af = af;
2028171168Smlaier		pf_mtag->hdr = mtod(m0, struct ip *);
2029126258Smlaier	}
2030145836Smlaier#endif /* ALTQ */
2031126258Smlaier
2032126258Smlaier	switch (af) {
2033126258Smlaier#ifdef INET
2034126258Smlaier	case AF_INET:
2035127145Smlaier#ifdef __FreeBSD__
2036126261Smlaier		/* icmp_error() expects host byte ordering */
2037126261Smlaier		ip = mtod(m0, struct ip *);
2038126261Smlaier		NTOHS(ip->ip_len);
2039126261Smlaier		NTOHS(ip->ip_off);
2040126261Smlaier		PF_UNLOCK();
2041145863Sandre		icmp_error(m0, type, code, 0, 0);
2042126261Smlaier		PF_LOCK();
2043145874Smlaier#else
2044171168Smlaier		icmp_error(m0, type, code, 0, 0);
2045126261Smlaier#endif
2046126258Smlaier		break;
2047126258Smlaier#endif /* INET */
2048126258Smlaier#ifdef INET6
2049126258Smlaier	case AF_INET6:
2050127145Smlaier#ifdef __FreeBSD__
2051126261Smlaier		PF_UNLOCK();
2052126261Smlaier#endif
2053126258Smlaier		icmp6_error(m0, type, code, 0);
2054127145Smlaier#ifdef __FreeBSD__
2055126261Smlaier		PF_LOCK();
2056126261Smlaier#endif
2057126258Smlaier		break;
2058126258Smlaier#endif /* INET6 */
2059126258Smlaier	}
2060126258Smlaier}
2061126258Smlaier
2062126258Smlaier/*
2063126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
2064126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
2065126258Smlaier * are different.
2066126258Smlaier */
2067126258Smlaierint
2068126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
2069126258Smlaier    struct pf_addr *b, sa_family_t af)
2070126258Smlaier{
2071126258Smlaier	int	match = 0;
2072126258Smlaier
2073126258Smlaier	switch (af) {
2074126258Smlaier#ifdef INET
2075126258Smlaier	case AF_INET:
2076126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
2077126258Smlaier		    (b->addr32[0] & m->addr32[0]))
2078126258Smlaier			match++;
2079126258Smlaier		break;
2080126258Smlaier#endif /* INET */
2081126258Smlaier#ifdef INET6
2082126258Smlaier	case AF_INET6:
2083126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
2084126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
2085126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
2086126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
2087126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
2088126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
2089126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
2090126258Smlaier		     (b->addr32[3] & m->addr32[3])))
2091126258Smlaier			match++;
2092126258Smlaier		break;
2093126258Smlaier#endif /* INET6 */
2094126258Smlaier	}
2095126258Smlaier	if (match) {
2096126258Smlaier		if (n)
2097126258Smlaier			return (0);
2098126258Smlaier		else
2099126258Smlaier			return (1);
2100126258Smlaier	} else {
2101126258Smlaier		if (n)
2102126258Smlaier			return (1);
2103126258Smlaier		else
2104126258Smlaier			return (0);
2105126258Smlaier	}
2106126258Smlaier}
2107126258Smlaier
2108126258Smlaierint
2109126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
2110126258Smlaier{
2111126258Smlaier	switch (op) {
2112126258Smlaier	case PF_OP_IRG:
2113126258Smlaier		return ((p > a1) && (p < a2));
2114126258Smlaier	case PF_OP_XRG:
2115126258Smlaier		return ((p < a1) || (p > a2));
2116126258Smlaier	case PF_OP_RRG:
2117126258Smlaier		return ((p >= a1) && (p <= a2));
2118126258Smlaier	case PF_OP_EQ:
2119126258Smlaier		return (p == a1);
2120126258Smlaier	case PF_OP_NE:
2121126258Smlaier		return (p != a1);
2122126258Smlaier	case PF_OP_LT:
2123126258Smlaier		return (p < a1);
2124126258Smlaier	case PF_OP_LE:
2125126258Smlaier		return (p <= a1);
2126126258Smlaier	case PF_OP_GT:
2127126258Smlaier		return (p > a1);
2128126258Smlaier	case PF_OP_GE:
2129126258Smlaier		return (p >= a1);
2130126258Smlaier	}
2131126258Smlaier	return (0); /* never reached */
2132126258Smlaier}
2133126258Smlaier
2134126258Smlaierint
2135126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
2136126258Smlaier{
2137126258Smlaier	NTOHS(a1);
2138126258Smlaier	NTOHS(a2);
2139126258Smlaier	NTOHS(p);
2140126258Smlaier	return (pf_match(op, a1, a2, p));
2141126258Smlaier}
2142126258Smlaier
2143126258Smlaierint
2144126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
2145126258Smlaier{
2146126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2147126258Smlaier		return (0);
2148126258Smlaier	return (pf_match(op, a1, a2, u));
2149126258Smlaier}
2150126258Smlaier
2151126258Smlaierint
2152126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
2153126258Smlaier{
2154126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2155126258Smlaier		return (0);
2156126258Smlaier	return (pf_match(op, a1, a2, g));
2157126258Smlaier}
2158126258Smlaier
2159171168Smlaier#ifndef __FreeBSD__
2160171168Smlaierstruct pf_mtag *
2161171168Smlaierpf_find_mtag(struct mbuf *m)
2162126258Smlaier{
2163126258Smlaier	struct m_tag	*mtag;
2164126258Smlaier
2165171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
2166126258Smlaier		return (NULL);
2167171168Smlaier
2168171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2169126258Smlaier}
2170126258Smlaier
2171171168Smlaierstruct pf_mtag *
2172171168Smlaierpf_get_mtag(struct mbuf *m)
2173126258Smlaier{
2174171168Smlaier	struct m_tag	*mtag;
2175171168Smlaier
2176171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
2177171168Smlaier		mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
2178171168Smlaier		    M_NOWAIT);
2179171168Smlaier		if (mtag == NULL)
2180171168Smlaier			return (NULL);
2181171168Smlaier		bzero(mtag + 1, sizeof(struct pf_mtag));
2182171168Smlaier		m_tag_prepend(m, mtag);
2183126258Smlaier	}
2184126258Smlaier
2185171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2186171168Smlaier}
2187171168Smlaier#endif
2188171168Smlaier
2189171168Smlaierint
2190171168Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
2191171168Smlaier    int *tag)
2192171168Smlaier{
2193171168Smlaier	if (*tag == -1)
2194171168Smlaier		*tag = pf_mtag->tag;
2195171168Smlaier
2196126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
2197126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
2198126258Smlaier}
2199126258Smlaier
2200126258Smlaierint
2201171168Smlaierpf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
2202126258Smlaier{
2203171168Smlaier	if (tag <= 0 && rtableid < 0)
2204126258Smlaier		return (0);
2205126258Smlaier
2206171168Smlaier	if (pf_mtag == NULL)
2207171168Smlaier		if ((pf_mtag = pf_get_mtag(m)) == NULL)
2208126258Smlaier			return (1);
2209171168Smlaier	if (tag > 0)
2210171168Smlaier		pf_mtag->tag = tag;
2211171168Smlaier	if (rtableid >= 0)
2212178888Sjulian#ifdef __FreeBSD__
2213178888Sjulian	{
2214178888Sjulian		M_SETFIB(m, rtableid);
2215178888Sjulian#endif
2216171168Smlaier		pf_mtag->rtableid = rtableid;
2217178888Sjulian#ifdef __FreeBSD__
2218178888Sjulian	}
2219178888Sjulian#endif
2220126258Smlaier
2221126258Smlaier	return (0);
2222126258Smlaier}
2223126258Smlaier
2224145836Smlaierstatic void
2225145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
2226171168Smlaier    struct pf_rule **r, struct pf_rule **a,  int *match)
2227145836Smlaier{
2228145836Smlaier	struct pf_anchor_stackframe	*f;
2229126258Smlaier
2230171168Smlaier	(*r)->anchor->match = 0;
2231171168Smlaier	if (match)
2232171168Smlaier		*match = 0;
2233145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
2234145836Smlaier	    sizeof(pf_anchor_stack[0])) {
2235145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
2236145836Smlaier		*r = TAILQ_NEXT(*r, entries);
2237145836Smlaier		return;
2238145836Smlaier	} else if (*depth == 0 && a != NULL)
2239145836Smlaier		*a = *r;
2240145836Smlaier	f = pf_anchor_stack + (*depth)++;
2241145836Smlaier	f->rs = *rs;
2242145836Smlaier	f->r = *r;
2243145836Smlaier	if ((*r)->anchor_wildcard) {
2244145836Smlaier		f->parent = &(*r)->anchor->children;
2245145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2246145836Smlaier		    NULL) {
2247145836Smlaier			*r = NULL;
2248145836Smlaier			return;
2249145836Smlaier		}
2250145836Smlaier		*rs = &f->child->ruleset;
2251145836Smlaier	} else {
2252145836Smlaier		f->parent = NULL;
2253145836Smlaier		f->child = NULL;
2254145836Smlaier		*rs = &(*r)->anchor->ruleset;
2255145836Smlaier	}
2256145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2257145836Smlaier}
2258126258Smlaier
2259171168Smlaierint
2260145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2261171168Smlaier    struct pf_rule **r, struct pf_rule **a, int *match)
2262145836Smlaier{
2263145836Smlaier	struct pf_anchor_stackframe	*f;
2264171168Smlaier	int quick = 0;
2265145836Smlaier
2266145836Smlaier	do {
2267145836Smlaier		if (*depth <= 0)
2268145836Smlaier			break;
2269145836Smlaier		f = pf_anchor_stack + *depth - 1;
2270145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2271171168Smlaier			if (f->child->match ||
2272171168Smlaier			    (match != NULL && *match)) {
2273171168Smlaier				f->r->anchor->match = 1;
2274171168Smlaier				*match = 0;
2275171168Smlaier			}
2276145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2277145836Smlaier			if (f->child != NULL) {
2278145836Smlaier				*rs = &f->child->ruleset;
2279145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2280145836Smlaier				if (*r == NULL)
2281145836Smlaier					continue;
2282145836Smlaier				else
2283145836Smlaier					break;
2284145836Smlaier			}
2285145836Smlaier		}
2286145836Smlaier		(*depth)--;
2287145836Smlaier		if (*depth == 0 && a != NULL)
2288145836Smlaier			*a = NULL;
2289145836Smlaier		*rs = f->rs;
2290171168Smlaier		if (f->r->anchor->match || (match  != NULL && *match))
2291171168Smlaier			quick = f->r->quick;
2292145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2293145836Smlaier	} while (*r == NULL);
2294171168Smlaier
2295171168Smlaier	return (quick);
2296145836Smlaier}
2297145836Smlaier
2298126258Smlaier#ifdef INET6
2299126258Smlaiervoid
2300126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2301126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2302126258Smlaier{
2303126258Smlaier	switch (af) {
2304126258Smlaier#ifdef INET
2305126258Smlaier	case AF_INET:
2306126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2307126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2308126258Smlaier		break;
2309126258Smlaier#endif /* INET */
2310126258Smlaier	case AF_INET6:
2311126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2312126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2313126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2314126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2315126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2316126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2317126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2318126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2319126258Smlaier		break;
2320126258Smlaier	}
2321126258Smlaier}
2322126258Smlaier
2323126258Smlaiervoid
2324130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2325126258Smlaier{
2326126258Smlaier	switch (af) {
2327126258Smlaier#ifdef INET
2328126258Smlaier	case AF_INET:
2329126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2330126258Smlaier		break;
2331126258Smlaier#endif /* INET */
2332126258Smlaier	case AF_INET6:
2333126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2334126258Smlaier			addr->addr32[3] = 0;
2335126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2336126258Smlaier				addr->addr32[2] = 0;
2337126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2338126258Smlaier					addr->addr32[1] = 0;
2339126258Smlaier					addr->addr32[0] =
2340126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2341126258Smlaier				} else
2342126258Smlaier					addr->addr32[1] =
2343126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2344126258Smlaier			} else
2345126258Smlaier				addr->addr32[2] =
2346126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2347126258Smlaier		} else
2348126258Smlaier			addr->addr32[3] =
2349126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2350126258Smlaier		break;
2351126258Smlaier	}
2352126258Smlaier}
2353126258Smlaier#endif /* INET6 */
2354126258Smlaier
2355126258Smlaier#define mix(a,b,c) \
2356126258Smlaier	do {					\
2357126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2358126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2359126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2360126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2361126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2362126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2363126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2364126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2365126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2366126258Smlaier	} while (0)
2367126258Smlaier
2368126258Smlaier/*
2369126258Smlaier * hash function based on bridge_hash in if_bridge.c
2370126258Smlaier */
2371126258Smlaiervoid
2372126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2373126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2374126258Smlaier{
2375126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2376126258Smlaier
2377126258Smlaier	switch (af) {
2378126258Smlaier#ifdef INET
2379126258Smlaier	case AF_INET:
2380126258Smlaier		a += inaddr->addr32[0];
2381126258Smlaier		b += key->key32[1];
2382126258Smlaier		mix(a, b, c);
2383126258Smlaier		hash->addr32[0] = c + key->key32[2];
2384126258Smlaier		break;
2385126258Smlaier#endif /* INET */
2386126258Smlaier#ifdef INET6
2387126258Smlaier	case AF_INET6:
2388126258Smlaier		a += inaddr->addr32[0];
2389126258Smlaier		b += inaddr->addr32[2];
2390126258Smlaier		mix(a, b, c);
2391126258Smlaier		hash->addr32[0] = c;
2392126258Smlaier		a += inaddr->addr32[1];
2393126258Smlaier		b += inaddr->addr32[3];
2394126258Smlaier		c += key->key32[1];
2395126258Smlaier		mix(a, b, c);
2396126258Smlaier		hash->addr32[1] = c;
2397126258Smlaier		a += inaddr->addr32[2];
2398126258Smlaier		b += inaddr->addr32[1];
2399126258Smlaier		c += key->key32[2];
2400126258Smlaier		mix(a, b, c);
2401126258Smlaier		hash->addr32[2] = c;
2402126258Smlaier		a += inaddr->addr32[3];
2403126258Smlaier		b += inaddr->addr32[0];
2404126258Smlaier		c += key->key32[3];
2405126258Smlaier		mix(a, b, c);
2406126258Smlaier		hash->addr32[3] = c;
2407126258Smlaier		break;
2408126258Smlaier#endif /* INET6 */
2409126258Smlaier	}
2410126258Smlaier}
2411126258Smlaier
2412126258Smlaierint
2413130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2414130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2415126258Smlaier{
2416126258Smlaier	unsigned char		 hash[16];
2417130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2418130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2419130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2420126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2421130613Smlaier	struct pf_src_node	 k;
2422126258Smlaier
2423130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2424130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2425130613Smlaier		k.af = af;
2426130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2427130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2428130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2429130613Smlaier			k.rule.ptr = r;
2430130613Smlaier		else
2431130613Smlaier			k.rule.ptr = NULL;
2432130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2433130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2434130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2435130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2436130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2437130613Smlaier				printf("pf_map_addr: src tracking maps ");
2438130613Smlaier				pf_print_host(&k.addr, 0, af);
2439130613Smlaier				printf(" to ");
2440130613Smlaier				pf_print_host(naddr, 0, af);
2441130613Smlaier				printf("\n");
2442130613Smlaier			}
2443130613Smlaier			return (0);
2444130613Smlaier		}
2445130613Smlaier	}
2446130613Smlaier
2447126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2448126258Smlaier		return (1);
2449130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2450145836Smlaier		switch (af) {
2451145836Smlaier#ifdef INET
2452145836Smlaier		case AF_INET:
2453130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2454130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2455130613Smlaier			    PF_POOL_ROUNDROBIN)
2456130613Smlaier				return (1);
2457130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2458130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2459145836Smlaier			break;
2460145836Smlaier#endif /* INET */
2461145836Smlaier#ifdef INET6
2462145836Smlaier		case AF_INET6:
2463130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2464130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2465130613Smlaier			    PF_POOL_ROUNDROBIN)
2466130613Smlaier				return (1);
2467130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2468130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2469145836Smlaier			break;
2470145836Smlaier#endif /* INET6 */
2471130613Smlaier		}
2472130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2473126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2474126258Smlaier			return (1); /* unsupported */
2475126258Smlaier	} else {
2476126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2477126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2478126258Smlaier	}
2479126258Smlaier
2480126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2481126258Smlaier	case PF_POOL_NONE:
2482126258Smlaier		PF_ACPY(naddr, raddr, af);
2483126258Smlaier		break;
2484126258Smlaier	case PF_POOL_BITMASK:
2485126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2486126258Smlaier		break;
2487126258Smlaier	case PF_POOL_RANDOM:
2488126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2489126258Smlaier			switch (af) {
2490126258Smlaier#ifdef INET
2491126258Smlaier			case AF_INET:
2492145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2493126258Smlaier				break;
2494126258Smlaier#endif /* INET */
2495126258Smlaier#ifdef INET6
2496126258Smlaier			case AF_INET6:
2497126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2498145836Smlaier					rpool->counter.addr32[3] =
2499145836Smlaier					    htonl(arc4random());
2500126258Smlaier				else
2501126258Smlaier					break;
2502126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2503145836Smlaier					rpool->counter.addr32[2] =
2504145836Smlaier					    htonl(arc4random());
2505126258Smlaier				else
2506126258Smlaier					break;
2507126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2508145836Smlaier					rpool->counter.addr32[1] =
2509145836Smlaier					    htonl(arc4random());
2510126258Smlaier				else
2511126258Smlaier					break;
2512126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2513145836Smlaier					rpool->counter.addr32[0] =
2514145836Smlaier					    htonl(arc4random());
2515126258Smlaier				break;
2516126258Smlaier#endif /* INET6 */
2517126258Smlaier			}
2518126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2519126258Smlaier			PF_ACPY(init_addr, naddr, af);
2520126258Smlaier
2521126258Smlaier		} else {
2522126258Smlaier			PF_AINC(&rpool->counter, af);
2523126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2524126258Smlaier		}
2525126258Smlaier		break;
2526126258Smlaier	case PF_POOL_SRCHASH:
2527126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2528126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2529126258Smlaier		break;
2530126258Smlaier	case PF_POOL_ROUNDROBIN:
2531126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2532126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2533126258Smlaier			    &rpool->tblidx, &rpool->counter,
2534126258Smlaier			    &raddr, &rmask, af))
2535126258Smlaier				goto get_addr;
2536130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2537130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2538130613Smlaier			    &rpool->tblidx, &rpool->counter,
2539130613Smlaier			    &raddr, &rmask, af))
2540130613Smlaier				goto get_addr;
2541126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2542126258Smlaier			goto get_addr;
2543126258Smlaier
2544126258Smlaier	try_next:
2545126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2546126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2547126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2548126258Smlaier			rpool->tblidx = -1;
2549126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2550126258Smlaier			    &rpool->tblidx, &rpool->counter,
2551126258Smlaier			    &raddr, &rmask, af)) {
2552130613Smlaier				/* table contains no address of type 'af' */
2553126258Smlaier				if (rpool->cur != acur)
2554126258Smlaier					goto try_next;
2555126258Smlaier				return (1);
2556126258Smlaier			}
2557130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2558130613Smlaier			rpool->tblidx = -1;
2559130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2560130613Smlaier			    &rpool->tblidx, &rpool->counter,
2561130613Smlaier			    &raddr, &rmask, af)) {
2562130613Smlaier				/* table contains no address of type 'af' */
2563130613Smlaier				if (rpool->cur != acur)
2564130613Smlaier					goto try_next;
2565130613Smlaier				return (1);
2566130613Smlaier			}
2567126258Smlaier		} else {
2568126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2569126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2570126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2571126258Smlaier		}
2572126258Smlaier
2573126258Smlaier	get_addr:
2574126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2575139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2576139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2577126258Smlaier		PF_AINC(&rpool->counter, af);
2578126258Smlaier		break;
2579126258Smlaier	}
2580130613Smlaier	if (*sn != NULL)
2581130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2582126258Smlaier
2583126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2584126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2585130613Smlaier		printf("pf_map_addr: selected address ");
2586126258Smlaier		pf_print_host(naddr, 0, af);
2587126258Smlaier		printf("\n");
2588126258Smlaier	}
2589126258Smlaier
2590126258Smlaier	return (0);
2591126258Smlaier}
2592126258Smlaier
2593126258Smlaierint
2594130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2595126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2596130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2597130613Smlaier    struct pf_src_node **sn)
2598126258Smlaier{
2599171168Smlaier	struct pf_state_cmp	key;
2600126258Smlaier	struct pf_addr		init_addr;
2601126258Smlaier	u_int16_t		cut;
2602126258Smlaier
2603126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2604130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2605126258Smlaier		return (1);
2606126258Smlaier
2607149884Smlaier	if (proto == IPPROTO_ICMP) {
2608149884Smlaier		low = 1;
2609149884Smlaier		high = 65535;
2610149884Smlaier	}
2611149884Smlaier
2612126258Smlaier	do {
2613126258Smlaier		key.af = af;
2614126258Smlaier		key.proto = proto;
2615130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2616130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2617130613Smlaier		key.ext.port = dport;
2618126258Smlaier
2619126258Smlaier		/*
2620126258Smlaier		 * port search; start random, step;
2621126258Smlaier		 * similar 2 portloop in in_pcbbind
2622126258Smlaier		 */
2623149884Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
2624149884Smlaier		    proto == IPPROTO_ICMP)) {
2625139045Sdhartmei			key.gwy.port = dport;
2626130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2627126258Smlaier				return (0);
2628126258Smlaier		} else if (low == 0 && high == 0) {
2629130613Smlaier			key.gwy.port = *nport;
2630130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2631126258Smlaier				return (0);
2632126258Smlaier		} else if (low == high) {
2633130613Smlaier			key.gwy.port = htons(low);
2634130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2635126258Smlaier				*nport = htons(low);
2636126258Smlaier				return (0);
2637126258Smlaier			}
2638126258Smlaier		} else {
2639126258Smlaier			u_int16_t tmp;
2640126258Smlaier
2641126258Smlaier			if (low > high) {
2642126258Smlaier				tmp = low;
2643126258Smlaier				low = high;
2644126258Smlaier				high = tmp;
2645126258Smlaier			}
2646126258Smlaier			/* low < high */
2647145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2648126258Smlaier			/* low <= cut <= high */
2649126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2650130613Smlaier				key.gwy.port = htons(tmp);
2651130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2652126258Smlaier				    NULL) {
2653126258Smlaier					*nport = htons(tmp);
2654126258Smlaier					return (0);
2655126258Smlaier				}
2656126258Smlaier			}
2657126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2658130613Smlaier				key.gwy.port = htons(tmp);
2659130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2660126258Smlaier				    NULL) {
2661126258Smlaier					*nport = htons(tmp);
2662126258Smlaier					return (0);
2663126258Smlaier				}
2664126258Smlaier			}
2665126258Smlaier		}
2666126258Smlaier
2667130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2668126258Smlaier		case PF_POOL_RANDOM:
2669126258Smlaier		case PF_POOL_ROUNDROBIN:
2670130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2671126258Smlaier				return (1);
2672126258Smlaier			break;
2673126258Smlaier		case PF_POOL_NONE:
2674126258Smlaier		case PF_POOL_SRCHASH:
2675126258Smlaier		case PF_POOL_BITMASK:
2676126258Smlaier		default:
2677126258Smlaier			return (1);
2678126258Smlaier		}
2679126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2680126258Smlaier
2681126258Smlaier	return (1);					/* none available */
2682126258Smlaier}
2683126258Smlaier
2684126258Smlaierstruct pf_rule *
2685126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2686130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2687126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2688126258Smlaier{
2689145836Smlaier	struct pf_rule		*r, *rm = NULL;
2690126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2691145836Smlaier	int			 tag = -1;
2692171168Smlaier	int			 rtableid = -1;
2693145836Smlaier	int			 asd = 0;
2694126258Smlaier
2695126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2696126258Smlaier	while (r && rm == NULL) {
2697126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2698126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2699126258Smlaier
2700126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2701126258Smlaier			src = &r->dst;
2702126258Smlaier			if (r->rpool.cur != NULL)
2703126258Smlaier				xdst = &r->rpool.cur->addr;
2704126258Smlaier		} else {
2705126258Smlaier			src = &r->src;
2706126258Smlaier			dst = &r->dst;
2707126258Smlaier		}
2708126258Smlaier
2709126258Smlaier		r->evaluations++;
2710171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
2711126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2712126258Smlaier		else if (r->direction && r->direction != direction)
2713126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2714126258Smlaier		else if (r->af && r->af != pd->af)
2715126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2716126258Smlaier		else if (r->proto && r->proto != pd->proto)
2717126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2718171168Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
2719171168Smlaier		    src->neg, kif))
2720126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2721126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2722126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2723126258Smlaier		    src->port[0], src->port[1], sport))
2724126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2725126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2726126258Smlaier		else if (dst != NULL &&
2727171168Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
2728126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2729171168Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
2730171168Smlaier		    0, NULL))
2731126258Smlaier			r = TAILQ_NEXT(r, entries);
2732126258Smlaier		else if (dst != NULL && dst->port_op &&
2733126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2734126258Smlaier		    dst->port[1], dport))
2735126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2736171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
2737145836Smlaier			r = TAILQ_NEXT(r, entries);
2738126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2739126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2740126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2741126258Smlaier			r = TAILQ_NEXT(r, entries);
2742145836Smlaier		else {
2743145836Smlaier			if (r->tag)
2744145836Smlaier				tag = r->tag;
2745171168Smlaier			if (r->rtableid >= 0)
2746171168Smlaier				rtableid = r->rtableid;
2747145836Smlaier			if (r->anchor == NULL) {
2748126258Smlaier				rm = r;
2749145836Smlaier			} else
2750171168Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num,
2751171168Smlaier				    &r, NULL, NULL);
2752145836Smlaier		}
2753145836Smlaier		if (r == NULL)
2754171168Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
2755171168Smlaier			    NULL, NULL);
2756126258Smlaier	}
2757171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
2758145836Smlaier		return (NULL);
2759126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2760126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2761126258Smlaier		return (NULL);
2762126258Smlaier	return (rm);
2763126258Smlaier}
2764126258Smlaier
2765126258Smlaierstruct pf_rule *
2766126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2767130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2768126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2769126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2770126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2771126258Smlaier{
2772126258Smlaier	struct pf_rule	*r = NULL;
2773126258Smlaier
2774126258Smlaier	if (direction == PF_OUT) {
2775130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2776126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2777126258Smlaier		if (r == NULL)
2778130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2779126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2780126258Smlaier	} else {
2781130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2782126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2783126258Smlaier		if (r == NULL)
2784130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2785126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2786126258Smlaier	}
2787126258Smlaier
2788126258Smlaier	if (r != NULL) {
2789126258Smlaier		switch (r->action) {
2790126258Smlaier		case PF_NONAT:
2791126258Smlaier		case PF_NOBINAT:
2792126258Smlaier		case PF_NORDR:
2793126258Smlaier			return (NULL);
2794126258Smlaier		case PF_NAT:
2795130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2796126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2797130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2798126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2799126258Smlaier				    ("pf: NAT proxy port allocation "
2800126258Smlaier				    "(%u-%u) failed\n",
2801126258Smlaier				    r->rpool.proxy_port[0],
2802126258Smlaier				    r->rpool.proxy_port[1]));
2803126258Smlaier				return (NULL);
2804126258Smlaier			}
2805126258Smlaier			break;
2806126258Smlaier		case PF_BINAT:
2807126258Smlaier			switch (direction) {
2808126258Smlaier			case PF_OUT:
2809130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2810145836Smlaier					switch (pd->af) {
2811145836Smlaier#ifdef INET
2812145836Smlaier					case AF_INET:
2813130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2814130613Smlaier						    pfid_acnt4 < 1)
2815130613Smlaier							return (NULL);
2816130613Smlaier						PF_POOLMASK(naddr,
2817130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2818130613Smlaier						    pfid_addr4,
2819130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2820130613Smlaier						    pfid_mask4,
2821130613Smlaier						    saddr, AF_INET);
2822145836Smlaier						break;
2823145836Smlaier#endif /* INET */
2824145836Smlaier#ifdef INET6
2825145836Smlaier					case AF_INET6:
2826130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2827130613Smlaier						    pfid_acnt6 < 1)
2828130613Smlaier							return (NULL);
2829130613Smlaier						PF_POOLMASK(naddr,
2830130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2831130613Smlaier						    pfid_addr6,
2832130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2833130613Smlaier						    pfid_mask6,
2834130613Smlaier						    saddr, AF_INET6);
2835145836Smlaier						break;
2836145836Smlaier#endif /* INET6 */
2837130613Smlaier					}
2838130613Smlaier				} else
2839126258Smlaier					PF_POOLMASK(naddr,
2840126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2841126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2842126258Smlaier					    saddr, pd->af);
2843126258Smlaier				break;
2844126258Smlaier			case PF_IN:
2845138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2846145836Smlaier					switch (pd->af) {
2847145836Smlaier#ifdef INET
2848145836Smlaier					case AF_INET:
2849130613Smlaier						if (r->src.addr.p.dyn->
2850130613Smlaier						    pfid_acnt4 < 1)
2851130613Smlaier							return (NULL);
2852130613Smlaier						PF_POOLMASK(naddr,
2853130613Smlaier						    &r->src.addr.p.dyn->
2854130613Smlaier						    pfid_addr4,
2855130613Smlaier						    &r->src.addr.p.dyn->
2856130613Smlaier						    pfid_mask4,
2857130613Smlaier						    daddr, AF_INET);
2858145836Smlaier						break;
2859145836Smlaier#endif /* INET */
2860145836Smlaier#ifdef INET6
2861145836Smlaier					case AF_INET6:
2862130613Smlaier						if (r->src.addr.p.dyn->
2863130613Smlaier						    pfid_acnt6 < 1)
2864130613Smlaier							return (NULL);
2865130613Smlaier						PF_POOLMASK(naddr,
2866130613Smlaier						    &r->src.addr.p.dyn->
2867130613Smlaier						    pfid_addr6,
2868130613Smlaier						    &r->src.addr.p.dyn->
2869130613Smlaier						    pfid_mask6,
2870130613Smlaier						    daddr, AF_INET6);
2871145836Smlaier						break;
2872145836Smlaier#endif /* INET6 */
2873130613Smlaier					}
2874130613Smlaier				} else
2875126258Smlaier					PF_POOLMASK(naddr,
2876126258Smlaier					    &r->src.addr.v.a.addr,
2877126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2878126258Smlaier					    pd->af);
2879126258Smlaier				break;
2880126258Smlaier			}
2881126258Smlaier			break;
2882126258Smlaier		case PF_RDR: {
2883140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2884126258Smlaier				return (NULL);
2885149884Smlaier			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
2886149884Smlaier			    PF_POOL_BITMASK)
2887149884Smlaier				PF_POOLMASK(naddr, naddr,
2888149884Smlaier				    &r->rpool.cur->addr.v.a.mask, daddr,
2889149884Smlaier				    pd->af);
2890126258Smlaier
2891126258Smlaier			if (r->rpool.proxy_port[1]) {
2892126258Smlaier				u_int32_t	tmp_nport;
2893126258Smlaier
2894126258Smlaier				tmp_nport = ((ntohs(dport) -
2895126258Smlaier				    ntohs(r->dst.port[0])) %
2896126258Smlaier				    (r->rpool.proxy_port[1] -
2897126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2898126258Smlaier				    r->rpool.proxy_port[0];
2899126258Smlaier
2900126258Smlaier				/* wrap around if necessary */
2901126258Smlaier				if (tmp_nport > 65535)
2902126258Smlaier					tmp_nport -= 65535;
2903126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2904126258Smlaier			} else if (r->rpool.proxy_port[0])
2905126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2906126258Smlaier			break;
2907126258Smlaier		}
2908126258Smlaier		default:
2909126258Smlaier			return (NULL);
2910126258Smlaier		}
2911126258Smlaier	}
2912126258Smlaier
2913126258Smlaier	return (r);
2914126258Smlaier}
2915126258Smlaier
2916126258Smlaierint
2917135920Smlaier#ifdef __FreeBSD__
2918171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
2919135920Smlaier#else
2920171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd)
2921135920Smlaier#endif
2922126258Smlaier{
2923126258Smlaier	struct pf_addr		*saddr, *daddr;
2924126258Smlaier	u_int16_t		 sport, dport;
2925127145Smlaier#ifdef __FreeBSD__
2926126261Smlaier	struct inpcbinfo	*pi;
2927126261Smlaier#else
2928126258Smlaier	struct inpcbtable	*tb;
2929126261Smlaier#endif
2930126258Smlaier	struct inpcb		*inp;
2931126258Smlaier
2932171168Smlaier	if (pd == NULL)
2933171168Smlaier		return (-1);
2934171168Smlaier	pd->lookup.uid = UID_MAX;
2935171168Smlaier	pd->lookup.gid = GID_MAX;
2936171168Smlaier	pd->lookup.pid = NO_PID;		/* XXX: revisit */
2937135920Smlaier#ifdef __FreeBSD__
2938135920Smlaier	if (inp_arg != NULL) {
2939178325Srwatson		INP_LOCK_ASSERT(inp_arg);
2940135920Smlaier		if (inp_arg->inp_socket) {
2941171168Smlaier			pd->lookup.uid = inp_arg->inp_socket->so_cred->cr_uid;
2942171168Smlaier			pd->lookup.gid =
2943171168Smlaier			    inp_arg->inp_socket->so_cred->cr_groups[0];
2944135920Smlaier			return (1);
2945135920Smlaier		} else
2946171168Smlaier			return (-1);
2947135920Smlaier	}
2948135920Smlaier#endif
2949130613Smlaier	switch (pd->proto) {
2950126258Smlaier	case IPPROTO_TCP:
2951171168Smlaier		if (pd->hdr.tcp == NULL)
2952171168Smlaier			return (-1);
2953126258Smlaier		sport = pd->hdr.tcp->th_sport;
2954126258Smlaier		dport = pd->hdr.tcp->th_dport;
2955127145Smlaier#ifdef __FreeBSD__
2956126261Smlaier		pi = &tcbinfo;
2957126261Smlaier#else
2958126258Smlaier		tb = &tcbtable;
2959126261Smlaier#endif
2960126258Smlaier		break;
2961126258Smlaier	case IPPROTO_UDP:
2962171168Smlaier		if (pd->hdr.udp == NULL)
2963171168Smlaier			return (-1);
2964126258Smlaier		sport = pd->hdr.udp->uh_sport;
2965126258Smlaier		dport = pd->hdr.udp->uh_dport;
2966127145Smlaier#ifdef __FreeBSD__
2967126261Smlaier		pi = &udbinfo;
2968126261Smlaier#else
2969126258Smlaier		tb = &udbtable;
2970126261Smlaier#endif
2971126258Smlaier		break;
2972126258Smlaier	default:
2973171168Smlaier		return (-1);
2974126258Smlaier	}
2975126258Smlaier	if (direction == PF_IN) {
2976126258Smlaier		saddr = pd->src;
2977126258Smlaier		daddr = pd->dst;
2978126258Smlaier	} else {
2979126258Smlaier		u_int16_t	p;
2980126258Smlaier
2981126258Smlaier		p = sport;
2982126258Smlaier		sport = dport;
2983126258Smlaier		dport = p;
2984126258Smlaier		saddr = pd->dst;
2985126258Smlaier		daddr = pd->src;
2986126258Smlaier	}
2987130613Smlaier	switch (pd->af) {
2988145836Smlaier#ifdef INET
2989126258Smlaier	case AF_INET:
2990127145Smlaier#ifdef __FreeBSD__
2991126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2992126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2993126261Smlaier			dport, 0, NULL);
2994126261Smlaier		if (inp == NULL) {
2995126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2996126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2997126261Smlaier			if(inp == NULL) {
2998126261Smlaier				INP_INFO_RUNLOCK(pi);
2999171168Smlaier				return (-1);
3000126261Smlaier			}
3001126261Smlaier		}
3002126261Smlaier#else
3003126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
3004126258Smlaier		if (inp == NULL) {
3005130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
3006126258Smlaier			if (inp == NULL)
3007171168Smlaier				return (-1);
3008126258Smlaier		}
3009126261Smlaier#endif
3010126258Smlaier		break;
3011145836Smlaier#endif /* INET */
3012126258Smlaier#ifdef INET6
3013126258Smlaier	case AF_INET6:
3014127145Smlaier#ifdef __FreeBSD__
3015126261Smlaier		INP_INFO_RLOCK(pi);
3016126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3017126261Smlaier			&daddr->v6, dport, 0, NULL);
3018126261Smlaier		if (inp == NULL) {
3019126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3020126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
3021126261Smlaier			if (inp == NULL) {
3022126261Smlaier				INP_INFO_RUNLOCK(pi);
3023171168Smlaier				return (-1);
3024126261Smlaier			}
3025126261Smlaier		}
3026126261Smlaier#else
3027126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
3028126258Smlaier		    dport);
3029126258Smlaier		if (inp == NULL) {
3030130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
3031126258Smlaier			if (inp == NULL)
3032171168Smlaier				return (-1);
3033126258Smlaier		}
3034126261Smlaier#endif
3035126258Smlaier		break;
3036126258Smlaier#endif /* INET6 */
3037126258Smlaier
3038126258Smlaier	default:
3039171168Smlaier		return (-1);
3040126258Smlaier	}
3041127145Smlaier#ifdef __FreeBSD__
3042178325Srwatson	INP_RLOCK(inp);
3043178325Srwatson	INP_INFO_RUNLOCK(pi);
3044136925Smlaier	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
3045178325Srwatson		INP_RUNLOCK(inp);
3046171168Smlaier		return (-1);
3047136925Smlaier	}
3048171168Smlaier	pd->lookup.uid = inp->inp_socket->so_cred->cr_uid;
3049171168Smlaier	pd->lookup.gid = inp->inp_socket->so_cred->cr_groups[0];
3050178325Srwatson	INP_RUNLOCK(inp);
3051126261Smlaier#else
3052171168Smlaier	pd->lookup.uid = inp->inp_socket->so_euid;
3053171168Smlaier	pd->lookup.gid = inp->inp_socket->so_egid;
3054171168Smlaier	pd->lookup.pid = inp->inp_socket->so_cpid;
3055126261Smlaier#endif
3056126258Smlaier	return (1);
3057126258Smlaier}
3058126258Smlaier
3059126258Smlaieru_int8_t
3060126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3061126258Smlaier{
3062126258Smlaier	int		 hlen;
3063126258Smlaier	u_int8_t	 hdr[60];
3064126258Smlaier	u_int8_t	*opt, optlen;
3065126258Smlaier	u_int8_t	 wscale = 0;
3066126258Smlaier
3067126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
3068126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3069126258Smlaier		return (0);
3070126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3071126258Smlaier		return (0);
3072126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3073126258Smlaier	hlen -= sizeof(struct tcphdr);
3074126258Smlaier	while (hlen >= 3) {
3075126258Smlaier		switch (*opt) {
3076126258Smlaier		case TCPOPT_EOL:
3077126258Smlaier		case TCPOPT_NOP:
3078126258Smlaier			++opt;
3079126258Smlaier			--hlen;
3080126258Smlaier			break;
3081126258Smlaier		case TCPOPT_WINDOW:
3082126258Smlaier			wscale = opt[2];
3083126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
3084126258Smlaier				wscale = TCP_MAX_WINSHIFT;
3085126258Smlaier			wscale |= PF_WSCALE_FLAG;
3086130613Smlaier			/* FALLTHROUGH */
3087126258Smlaier		default:
3088126258Smlaier			optlen = opt[1];
3089126258Smlaier			if (optlen < 2)
3090126258Smlaier				optlen = 2;
3091126258Smlaier			hlen -= optlen;
3092126258Smlaier			opt += optlen;
3093130613Smlaier			break;
3094126258Smlaier		}
3095126258Smlaier	}
3096126258Smlaier	return (wscale);
3097126258Smlaier}
3098126258Smlaier
3099126258Smlaieru_int16_t
3100126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3101126258Smlaier{
3102126258Smlaier	int		 hlen;
3103126258Smlaier	u_int8_t	 hdr[60];
3104126258Smlaier	u_int8_t	*opt, optlen;
3105126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
3106126258Smlaier
3107126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
3108126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3109126258Smlaier		return (0);
3110126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3111126258Smlaier		return (0);
3112126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3113126258Smlaier	hlen -= sizeof(struct tcphdr);
3114126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
3115126258Smlaier		switch (*opt) {
3116126258Smlaier		case TCPOPT_EOL:
3117126258Smlaier		case TCPOPT_NOP:
3118126258Smlaier			++opt;
3119126258Smlaier			--hlen;
3120126258Smlaier			break;
3121126258Smlaier		case TCPOPT_MAXSEG:
3122126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
3123145030Sglebius			NTOHS(mss);
3124130613Smlaier			/* FALLTHROUGH */
3125126258Smlaier		default:
3126126258Smlaier			optlen = opt[1];
3127126258Smlaier			if (optlen < 2)
3128126258Smlaier				optlen = 2;
3129126258Smlaier			hlen -= optlen;
3130126258Smlaier			opt += optlen;
3131130613Smlaier			break;
3132126258Smlaier		}
3133126258Smlaier	}
3134126258Smlaier	return (mss);
3135126258Smlaier}
3136126258Smlaier
3137126258Smlaieru_int16_t
3138126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
3139126258Smlaier{
3140126258Smlaier#ifdef INET
3141126258Smlaier	struct sockaddr_in	*dst;
3142126258Smlaier	struct route		 ro;
3143126258Smlaier#endif /* INET */
3144126258Smlaier#ifdef INET6
3145126258Smlaier	struct sockaddr_in6	*dst6;
3146126258Smlaier	struct route_in6	 ro6;
3147126258Smlaier#endif /* INET6 */
3148126258Smlaier	struct rtentry		*rt = NULL;
3149127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
3150126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
3151126258Smlaier
3152126258Smlaier	switch (af) {
3153126258Smlaier#ifdef INET
3154126258Smlaier	case AF_INET:
3155126258Smlaier		hlen = sizeof(struct ip);
3156126258Smlaier		bzero(&ro, sizeof(ro));
3157126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
3158126258Smlaier		dst->sin_family = AF_INET;
3159126258Smlaier		dst->sin_len = sizeof(*dst);
3160126258Smlaier		dst->sin_addr = addr->v4;
3161127145Smlaier#ifdef __FreeBSD__
3162126261Smlaier#ifdef RTF_PRCLONING
3163126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
3164126261Smlaier#else /* !RTF_PRCLONING */
3165178888Sjulian		in_rtalloc_ign(&ro, RTF_CLONING, 0);
3166126261Smlaier#endif
3167126261Smlaier#else /* ! __FreeBSD__ */
3168126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
3169126261Smlaier#endif
3170126258Smlaier		rt = ro.ro_rt;
3171126258Smlaier		break;
3172126258Smlaier#endif /* INET */
3173126258Smlaier#ifdef INET6
3174126258Smlaier	case AF_INET6:
3175126258Smlaier		hlen = sizeof(struct ip6_hdr);
3176126258Smlaier		bzero(&ro6, sizeof(ro6));
3177126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
3178126258Smlaier		dst6->sin6_family = AF_INET6;
3179126258Smlaier		dst6->sin6_len = sizeof(*dst6);
3180126258Smlaier		dst6->sin6_addr = addr->v6;
3181127145Smlaier#ifdef __FreeBSD__
3182126261Smlaier#ifdef RTF_PRCLONING
3183126261Smlaier		rtalloc_ign((struct route *)&ro6,
3184126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
3185126261Smlaier#else /* !RTF_PRCLONING */
3186126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
3187126261Smlaier#endif
3188126261Smlaier#else /* ! __FreeBSD__ */
3189126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
3190126261Smlaier#endif
3191126258Smlaier		rt = ro6.ro_rt;
3192126258Smlaier		break;
3193126258Smlaier#endif /* INET6 */
3194126258Smlaier	}
3195126258Smlaier
3196126258Smlaier	if (rt && rt->rt_ifp) {
3197126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
3198126258Smlaier		mss = max(tcp_mssdflt, mss);
3199126258Smlaier		RTFREE(rt);
3200126258Smlaier	}
3201126258Smlaier	mss = min(mss, offer);
3202126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
3203126258Smlaier	return (mss);
3204126258Smlaier}
3205126258Smlaier
3206126258Smlaiervoid
3207126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
3208126258Smlaier{
3209126258Smlaier	struct pf_rule *r = s->rule.ptr;
3210126258Smlaier
3211130613Smlaier	s->rt_kif = NULL;
3212126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
3213126258Smlaier		return;
3214126258Smlaier	switch (s->af) {
3215126258Smlaier#ifdef INET
3216126258Smlaier	case AF_INET:
3217130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
3218130613Smlaier		    &s->nat_src_node);
3219130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3220126258Smlaier		break;
3221126258Smlaier#endif /* INET */
3222126258Smlaier#ifdef INET6
3223126258Smlaier	case AF_INET6:
3224130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
3225130613Smlaier		    &s->nat_src_node);
3226130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3227126258Smlaier		break;
3228126258Smlaier#endif /* INET6 */
3229126258Smlaier	}
3230126258Smlaier}
3231126258Smlaier
3232126258Smlaierint
3233126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
3234130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3235135920Smlaier#ifdef __FreeBSD__
3236135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3237145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3238135920Smlaier#else
3239145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3240145836Smlaier    struct ifqueue *ifq)
3241135920Smlaier#endif
3242126258Smlaier{
3243130613Smlaier	struct pf_rule		*nr = NULL;
3244126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3245126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3246126258Smlaier	u_int16_t		 bport, nport = 0;
3247126258Smlaier	sa_family_t		 af = pd->af;
3248126258Smlaier	struct pf_rule		*r, *a = NULL;
3249126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3250130613Smlaier	struct pf_src_node	*nsn = NULL;
3251126258Smlaier	u_short			 reason;
3252126258Smlaier	int			 rewrite = 0;
3253171168Smlaier	int			 tag = -1, rtableid = -1;
3254126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
3255145836Smlaier	int			 asd = 0;
3256171168Smlaier	int			 match = 0;
3257126258Smlaier
3258145836Smlaier	if (pf_check_congestion(ifq)) {
3259145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3260145836Smlaier		return (PF_DROP);
3261145836Smlaier	}
3262145836Smlaier
3263171168Smlaier#ifdef __FreeBSD__
3264171168Smlaier	if (inp != NULL)
3265171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3266171168Smlaier	else if (debug_pfugidhack) {
3267171168Smlaier		PF_UNLOCK();
3268171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3269171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3270171168Smlaier		PF_LOCK();
3271171168Smlaier	}
3272165631Smlaier#endif
3273165631Smlaier
3274126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3275126258Smlaier
3276126258Smlaier	if (direction == PF_OUT) {
3277126258Smlaier		bport = nport = th->th_sport;
3278126258Smlaier		/* check outgoing packet for BINAT/NAT */
3279130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3280126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3281130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3282130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3283126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3284130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3285126258Smlaier			rewrite++;
3286130613Smlaier			if (nr->natpass)
3287126258Smlaier				r = NULL;
3288130613Smlaier			pd->nat_rule = nr;
3289126258Smlaier		}
3290126258Smlaier	} else {
3291126258Smlaier		bport = nport = th->th_dport;
3292126258Smlaier		/* check incoming packet for BINAT/RDR */
3293130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3294130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3295130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3296130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3297126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3298130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3299126258Smlaier			rewrite++;
3300130613Smlaier			if (nr->natpass)
3301126258Smlaier				r = NULL;
3302130613Smlaier			pd->nat_rule = nr;
3303126258Smlaier		}
3304126258Smlaier	}
3305126258Smlaier
3306126258Smlaier	while (r != NULL) {
3307126258Smlaier		r->evaluations++;
3308171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3309126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3310126258Smlaier		else if (r->direction && r->direction != direction)
3311126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3312126258Smlaier		else if (r->af && r->af != af)
3313126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3314126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3315126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3316171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3317171168Smlaier		    r->src.neg, kif))
3318126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3319126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3320126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3321126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3322171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3323171168Smlaier		    r->dst.neg, NULL))
3324126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3325126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3326126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3327126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3328171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3329126258Smlaier			r = TAILQ_NEXT(r, entries);
3330126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3331126258Smlaier			r = TAILQ_NEXT(r, entries);
3332126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3333126258Smlaier			r = TAILQ_NEXT(r, entries);
3334171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3335135920Smlaier#ifdef __FreeBSD__
3336171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3337135920Smlaier#else
3338171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3339135920Smlaier#endif
3340126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3341171168Smlaier		    pd->lookup.uid))
3342126258Smlaier			r = TAILQ_NEXT(r, entries);
3343171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3344135920Smlaier#ifdef __FreeBSD__
3345171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3346135920Smlaier#else
3347171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3348135920Smlaier#endif
3349126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3350171168Smlaier		    pd->lookup.gid))
3351126258Smlaier			r = TAILQ_NEXT(r, entries);
3352145836Smlaier		else if (r->prob && r->prob <= arc4random())
3353126258Smlaier			r = TAILQ_NEXT(r, entries);
3354171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3355126258Smlaier			r = TAILQ_NEXT(r, entries);
3356126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3357126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3358126258Smlaier			r = TAILQ_NEXT(r, entries);
3359126258Smlaier		else {
3360126258Smlaier			if (r->tag)
3361126258Smlaier				tag = r->tag;
3362171168Smlaier			if (r->rtableid >= 0)
3363171168Smlaier				rtableid = r->rtableid;
3364126258Smlaier			if (r->anchor == NULL) {
3365171168Smlaier				match = 1;
3366126258Smlaier				*rm = r;
3367126258Smlaier				*am = a;
3368126258Smlaier				*rsm = ruleset;
3369126258Smlaier				if ((*rm)->quick)
3370126258Smlaier					break;
3371126258Smlaier				r = TAILQ_NEXT(r, entries);
3372126258Smlaier			} else
3373145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3374171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3375126258Smlaier		}
3376171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3377171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3378171168Smlaier			break;
3379126258Smlaier	}
3380126258Smlaier	r = *rm;
3381126258Smlaier	a = *am;
3382126258Smlaier	ruleset = *rsm;
3383126258Smlaier
3384126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3385126258Smlaier
3386171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3387126258Smlaier		if (rewrite)
3388171168Smlaier#ifdef __FreeBSD__
3389126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3390171168Smlaier#else
3391171168Smlaier			m_copyback(m, off, sizeof(*th), th);
3392171168Smlaier#endif
3393171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3394171168Smlaier		    a, ruleset, pd);
3395126258Smlaier	}
3396126258Smlaier
3397126258Smlaier	if ((r->action == PF_DROP) &&
3398126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3399126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3400126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3401126258Smlaier		/* undo NAT changes, if they have taken place */
3402130613Smlaier		if (nr != NULL) {
3403130613Smlaier			if (direction == PF_OUT) {
3404130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3405130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3406130613Smlaier				rewrite++;
3407130613Smlaier			} else {
3408130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3409130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3410130613Smlaier				rewrite++;
3411130613Smlaier			}
3412126258Smlaier		}
3413126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3414126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3415126258Smlaier		    !(th->th_flags & TH_RST)) {
3416126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3417126258Smlaier
3418126258Smlaier			if (th->th_flags & TH_SYN)
3419126258Smlaier				ack++;
3420126258Smlaier			if (th->th_flags & TH_FIN)
3421126258Smlaier				ack++;
3422162238Scsjp#ifdef __FreeBSD__
3423162238Scsjp			pf_send_tcp(m, r, af, pd->dst,
3424162238Scsjp#else
3425126258Smlaier			pf_send_tcp(r, af, pd->dst,
3426162238Scsjp#endif
3427126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3428126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3429171168Smlaier			    r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
3430126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3431126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3432126258Smlaier			    r->return_icmp & 255, af, r);
3433126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3434126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3435126258Smlaier			    r->return_icmp6 & 255, af, r);
3436126258Smlaier	}
3437126258Smlaier
3438126258Smlaier	if (r->action == PF_DROP)
3439126258Smlaier		return (PF_DROP);
3440126258Smlaier
3441171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3442126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3443126258Smlaier		return (PF_DROP);
3444126258Smlaier	}
3445126258Smlaier
3446130613Smlaier	if (r->keep_state || nr != NULL ||
3447126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3448126258Smlaier		/* create new state */
3449126258Smlaier		u_int16_t	 len;
3450126258Smlaier		struct pf_state	*s = NULL;
3451130613Smlaier		struct pf_src_node *sn = NULL;
3452126258Smlaier
3453126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3454130613Smlaier
3455130613Smlaier		/* check maximums */
3456145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3457145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3458145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3459130613Smlaier			goto cleanup;
3460145836Smlaier		}
3461171168Smlaier		/* src node for filter rule */
3462130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3463130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3464145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3465145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3466130613Smlaier			goto cleanup;
3467145836Smlaier		}
3468130613Smlaier		/* src node for translation rule */
3469130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3470130613Smlaier		    ((direction == PF_OUT &&
3471130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3472145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3473145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3474130613Smlaier			goto cleanup;
3475145836Smlaier		}
3476130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3477126258Smlaier		if (s == NULL) {
3478145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3479130613Smlaiercleanup:
3480130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3481130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3482130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3483130613Smlaier				pf_status.src_nodes--;
3484130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3485130613Smlaier			}
3486130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3487130613Smlaier			    nsn->expire == 0) {
3488130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3489130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3490130613Smlaier				pf_status.src_nodes--;
3491130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3492130613Smlaier			}
3493126258Smlaier			return (PF_DROP);
3494126258Smlaier		}
3495126258Smlaier		bzero(s, sizeof(*s));
3496126258Smlaier		s->rule.ptr = r;
3497130613Smlaier		s->nat_rule.ptr = nr;
3498126258Smlaier		s->anchor.ptr = a;
3499145836Smlaier		STATE_INC_COUNTERS(s);
3500126258Smlaier		s->allow_opts = r->allow_opts;
3501171168Smlaier		s->log = r->log & PF_LOG_ALL;
3502171168Smlaier		if (nr != NULL)
3503171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3504126258Smlaier		s->proto = IPPROTO_TCP;
3505126258Smlaier		s->direction = direction;
3506126258Smlaier		s->af = af;
3507126258Smlaier		if (direction == PF_OUT) {
3508126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3509126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3510126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3511126258Smlaier			s->ext.port = th->th_dport;
3512130613Smlaier			if (nr != NULL) {
3513130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3514126258Smlaier				s->lan.port = bport;
3515126258Smlaier			} else {
3516126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3517126258Smlaier				s->lan.port = s->gwy.port;
3518126258Smlaier			}
3519126258Smlaier		} else {
3520126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3521126258Smlaier			s->lan.port = th->th_dport;
3522126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3523126258Smlaier			s->ext.port = th->th_sport;
3524130613Smlaier			if (nr != NULL) {
3525130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3526126258Smlaier				s->gwy.port = bport;
3527126258Smlaier			} else {
3528126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3529126258Smlaier				s->gwy.port = s->lan.port;
3530126258Smlaier			}
3531126258Smlaier		}
3532126258Smlaier
3533126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3534126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3535126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3536126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3537126258Smlaier			/* Generate sequence number modulator */
3538171168Smlaier#ifdef __FreeBSD__
3539171168Smlaier			while ((s->src.seqdiff =
3540171168Smlaier			    pf_new_isn(s) - s->src.seqlo) == 0)
3541171168Smlaier				;
3542171168Smlaier#else
3543171168Smlaier			while ((s->src.seqdiff =
3544171168Smlaier			    tcp_rndiss_next() - s->src.seqlo) == 0)
3545126258Smlaier				;
3546171168Smlaier#endif
3547126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3548126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3549126258Smlaier			rewrite = 1;
3550126258Smlaier		} else
3551126258Smlaier			s->src.seqdiff = 0;
3552126258Smlaier		if (th->th_flags & TH_SYN) {
3553126258Smlaier			s->src.seqhi++;
3554126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3555126258Smlaier		}
3556126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3557126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3558126258Smlaier			/* Remove scale factor from initial window */
3559126258Smlaier			int win = s->src.max_win;
3560126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3561126258Smlaier			s->src.max_win = (win - 1) >>
3562126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3563126258Smlaier		}
3564126258Smlaier		if (th->th_flags & TH_FIN)
3565126258Smlaier			s->src.seqhi++;
3566126258Smlaier		s->dst.seqhi = 1;
3567126258Smlaier		s->dst.max_win = 1;
3568126258Smlaier		s->src.state = TCPS_SYN_SENT;
3569126258Smlaier		s->dst.state = TCPS_CLOSED;
3570126261Smlaier		s->creation = time_second;
3571126261Smlaier		s->expire = time_second;
3572126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3573126258Smlaier		pf_set_rt_ifp(s, saddr);
3574130613Smlaier		if (sn != NULL) {
3575130613Smlaier			s->src_node = sn;
3576130613Smlaier			s->src_node->states++;
3577130613Smlaier		}
3578130613Smlaier		if (nsn != NULL) {
3579130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3580130613Smlaier			s->nat_src_node = nsn;
3581130613Smlaier			s->nat_src_node->states++;
3582130613Smlaier		}
3583126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3584126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3585126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3586130613Smlaier			pf_src_tree_remove_state(s);
3587145836Smlaier			STATE_DEC_COUNTERS(s);
3588126258Smlaier			pool_put(&pf_state_pl, s);
3589126258Smlaier			return (PF_DROP);
3590126258Smlaier		}
3591126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3592145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3593145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3594145836Smlaier			/* This really shouldn't happen!!! */
3595145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3596145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3597126258Smlaier			pf_normalize_tcp_cleanup(s);
3598130613Smlaier			pf_src_tree_remove_state(s);
3599145836Smlaier			STATE_DEC_COUNTERS(s);
3600126258Smlaier			pool_put(&pf_state_pl, s);
3601126258Smlaier			return (PF_DROP);
3602126258Smlaier		}
3603130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3604126258Smlaier			pf_normalize_tcp_cleanup(s);
3605145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3606130613Smlaier			pf_src_tree_remove_state(s);
3607145836Smlaier			STATE_DEC_COUNTERS(s);
3608126258Smlaier			pool_put(&pf_state_pl, s);
3609126258Smlaier			return (PF_DROP);
3610126258Smlaier		} else
3611126258Smlaier			*sm = s;
3612145836Smlaier		if (tag > 0) {
3613145836Smlaier			pf_tag_ref(tag);
3614145836Smlaier			s->tag = tag;
3615145836Smlaier		}
3616126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3617126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3618126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3619130613Smlaier			if (nr != NULL) {
3620130613Smlaier				if (direction == PF_OUT) {
3621130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3622130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3623130613Smlaier					    bport, 0, af);
3624130613Smlaier				} else {
3625130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3626130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3627130613Smlaier					    bport, 0, af);
3628130613Smlaier				}
3629130613Smlaier			}
3630145836Smlaier			s->src.seqhi = htonl(arc4random());
3631126258Smlaier			/* Find mss option */
3632126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3633126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3634126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3635126258Smlaier			s->src.mss = mss;
3636162238Scsjp#ifdef __FreeBSD__
3637162238Scsjp			pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
3638162238Scsjp#else
3639126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3640162238Scsjp#endif
3641130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3642171168Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
3643145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3644126258Smlaier			return (PF_SYNPROXY_DROP);
3645126258Smlaier		}
3646126258Smlaier	}
3647126258Smlaier
3648126258Smlaier	/* copy back packet headers if we performed NAT operations */
3649126258Smlaier	if (rewrite)
3650126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3651126258Smlaier
3652126258Smlaier	return (PF_PASS);
3653126258Smlaier}
3654126258Smlaier
3655126258Smlaierint
3656126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3657130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3658135920Smlaier#ifdef __FreeBSD__
3659135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3660145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3661135920Smlaier#else
3662145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3663145836Smlaier    struct ifqueue *ifq)
3664135920Smlaier#endif
3665126258Smlaier{
3666130613Smlaier	struct pf_rule		*nr = NULL;
3667126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3668126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3669126258Smlaier	u_int16_t		 bport, nport = 0;
3670126258Smlaier	sa_family_t		 af = pd->af;
3671126258Smlaier	struct pf_rule		*r, *a = NULL;
3672126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3673130613Smlaier	struct pf_src_node	*nsn = NULL;
3674126258Smlaier	u_short			 reason;
3675126258Smlaier	int			 rewrite = 0;
3676171168Smlaier	int			 tag = -1, rtableid = -1;
3677145836Smlaier	int			 asd = 0;
3678171168Smlaier	int			 match = 0;
3679126258Smlaier
3680145836Smlaier	if (pf_check_congestion(ifq)) {
3681145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3682145836Smlaier		return (PF_DROP);
3683145836Smlaier	}
3684145836Smlaier
3685171168Smlaier#ifdef __FreeBSD__
3686171168Smlaier	if (inp != NULL)
3687171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3688171168Smlaier	else if (debug_pfugidhack) {
3689171168Smlaier		PF_UNLOCK();
3690171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3691171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3692171168Smlaier		PF_LOCK();
3693171168Smlaier	}
3694165631Smlaier#endif
3695165631Smlaier
3696126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3697126258Smlaier
3698126258Smlaier	if (direction == PF_OUT) {
3699126258Smlaier		bport = nport = uh->uh_sport;
3700126258Smlaier		/* check outgoing packet for BINAT/NAT */
3701130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3702126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3703130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3704130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3705126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3706130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3707126258Smlaier			rewrite++;
3708130613Smlaier			if (nr->natpass)
3709126258Smlaier				r = NULL;
3710130613Smlaier			pd->nat_rule = nr;
3711126258Smlaier		}
3712126258Smlaier	} else {
3713126258Smlaier		bport = nport = uh->uh_dport;
3714126258Smlaier		/* check incoming packet for BINAT/RDR */
3715130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3716130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3717130613Smlaier		    &nport)) != NULL) {
3718130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3719126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3720130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3721126258Smlaier			rewrite++;
3722130613Smlaier			if (nr->natpass)
3723126258Smlaier				r = NULL;
3724130613Smlaier			pd->nat_rule = nr;
3725126258Smlaier		}
3726126258Smlaier	}
3727126258Smlaier
3728126258Smlaier	while (r != NULL) {
3729126258Smlaier		r->evaluations++;
3730171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3731126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3732126258Smlaier		else if (r->direction && r->direction != direction)
3733126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3734126258Smlaier		else if (r->af && r->af != af)
3735126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3736126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3737126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3738171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3739171168Smlaier		    r->src.neg, kif))
3740126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3741126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3742126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3743126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3744171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3745171168Smlaier		    r->dst.neg, NULL))
3746126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3747126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3748126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3749126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3750171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3751126258Smlaier			r = TAILQ_NEXT(r, entries);
3752126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3753126258Smlaier			r = TAILQ_NEXT(r, entries);
3754171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3755135920Smlaier#ifdef __FreeBSD__
3756171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3757135920Smlaier#else
3758171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3759135920Smlaier#endif
3760126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3761171168Smlaier		    pd->lookup.uid))
3762126258Smlaier			r = TAILQ_NEXT(r, entries);
3763171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3764135920Smlaier#ifdef __FreeBSD__
3765171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3766135920Smlaier#else
3767171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3768135920Smlaier#endif
3769126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3770171168Smlaier		    pd->lookup.gid))
3771126258Smlaier			r = TAILQ_NEXT(r, entries);
3772145836Smlaier		else if (r->prob && r->prob <= arc4random())
3773126258Smlaier			r = TAILQ_NEXT(r, entries);
3774171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3775126258Smlaier			r = TAILQ_NEXT(r, entries);
3776126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3777126258Smlaier			r = TAILQ_NEXT(r, entries);
3778126258Smlaier		else {
3779126258Smlaier			if (r->tag)
3780126258Smlaier				tag = r->tag;
3781171168Smlaier			if (r->rtableid >= 0)
3782171168Smlaier				rtableid = r->rtableid;
3783126258Smlaier			if (r->anchor == NULL) {
3784171168Smlaier				match = 1;
3785126258Smlaier				*rm = r;
3786126258Smlaier				*am = a;
3787126258Smlaier				*rsm = ruleset;
3788126258Smlaier				if ((*rm)->quick)
3789126258Smlaier					break;
3790126258Smlaier				r = TAILQ_NEXT(r, entries);
3791126258Smlaier			} else
3792145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3793171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3794126258Smlaier		}
3795171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3796171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3797171168Smlaier			break;
3798126258Smlaier	}
3799126258Smlaier	r = *rm;
3800126258Smlaier	a = *am;
3801126258Smlaier	ruleset = *rsm;
3802126258Smlaier
3803126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3804126258Smlaier
3805171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3806126258Smlaier		if (rewrite)
3807171168Smlaier#ifdef __FreeBSD__
3808126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3809171168Smlaier#else
3810171168Smlaier			m_copyback(m, off, sizeof(*uh), uh);
3811171168Smlaier#endif
3812171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3813171168Smlaier		    a, ruleset, pd);
3814126258Smlaier	}
3815126258Smlaier
3816126258Smlaier	if ((r->action == PF_DROP) &&
3817126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3818126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3819126258Smlaier		/* undo NAT changes, if they have taken place */
3820130613Smlaier		if (nr != NULL) {
3821130613Smlaier			if (direction == PF_OUT) {
3822130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3823130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3824130613Smlaier				rewrite++;
3825130613Smlaier			} else {
3826130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3827130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3828130613Smlaier				rewrite++;
3829130613Smlaier			}
3830126258Smlaier		}
3831126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3832126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3833126258Smlaier			    r->return_icmp & 255, af, r);
3834126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3835126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3836126258Smlaier			    r->return_icmp6 & 255, af, r);
3837126258Smlaier	}
3838126258Smlaier
3839126258Smlaier	if (r->action == PF_DROP)
3840126258Smlaier		return (PF_DROP);
3841126258Smlaier
3842171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3843126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3844126258Smlaier		return (PF_DROP);
3845126258Smlaier	}
3846126258Smlaier
3847130613Smlaier	if (r->keep_state || nr != NULL) {
3848126258Smlaier		/* create new state */
3849126258Smlaier		struct pf_state	*s = NULL;
3850130613Smlaier		struct pf_src_node *sn = NULL;
3851126258Smlaier
3852130613Smlaier		/* check maximums */
3853145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3854145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3855145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3856130613Smlaier			goto cleanup;
3857145836Smlaier		}
3858171168Smlaier		/* src node for filter rule */
3859130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3860130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3861145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3862145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3863130613Smlaier			goto cleanup;
3864145836Smlaier		}
3865130613Smlaier		/* src node for translation rule */
3866130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3867130613Smlaier		    ((direction == PF_OUT &&
3868130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3869145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3870145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3871130613Smlaier			goto cleanup;
3872145836Smlaier		}
3873130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3874126258Smlaier		if (s == NULL) {
3875145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3876130613Smlaiercleanup:
3877130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3878130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3879130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3880130613Smlaier				pf_status.src_nodes--;
3881130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3882130613Smlaier			}
3883130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3884130613Smlaier			    nsn->expire == 0) {
3885130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3886130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3887130613Smlaier				pf_status.src_nodes--;
3888130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3889130613Smlaier			}
3890126258Smlaier			return (PF_DROP);
3891126258Smlaier		}
3892126258Smlaier		bzero(s, sizeof(*s));
3893126258Smlaier		s->rule.ptr = r;
3894130613Smlaier		s->nat_rule.ptr = nr;
3895126258Smlaier		s->anchor.ptr = a;
3896145836Smlaier		STATE_INC_COUNTERS(s);
3897126258Smlaier		s->allow_opts = r->allow_opts;
3898171168Smlaier		s->log = r->log & PF_LOG_ALL;
3899171168Smlaier		if (nr != NULL)
3900171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3901126258Smlaier		s->proto = IPPROTO_UDP;
3902126258Smlaier		s->direction = direction;
3903126258Smlaier		s->af = af;
3904126258Smlaier		if (direction == PF_OUT) {
3905126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3906126258Smlaier			s->gwy.port = uh->uh_sport;
3907126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3908126258Smlaier			s->ext.port = uh->uh_dport;
3909130613Smlaier			if (nr != NULL) {
3910130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3911126258Smlaier				s->lan.port = bport;
3912126258Smlaier			} else {
3913126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3914126258Smlaier				s->lan.port = s->gwy.port;
3915126258Smlaier			}
3916126258Smlaier		} else {
3917126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3918126258Smlaier			s->lan.port = uh->uh_dport;
3919126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3920126258Smlaier			s->ext.port = uh->uh_sport;
3921130613Smlaier			if (nr != NULL) {
3922130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3923126258Smlaier				s->gwy.port = bport;
3924126258Smlaier			} else {
3925126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3926126258Smlaier				s->gwy.port = s->lan.port;
3927126258Smlaier			}
3928126258Smlaier		}
3929126258Smlaier		s->src.state = PFUDPS_SINGLE;
3930126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3931126261Smlaier		s->creation = time_second;
3932126261Smlaier		s->expire = time_second;
3933126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3934126258Smlaier		pf_set_rt_ifp(s, saddr);
3935130613Smlaier		if (sn != NULL) {
3936130613Smlaier			s->src_node = sn;
3937130613Smlaier			s->src_node->states++;
3938130613Smlaier		}
3939130613Smlaier		if (nsn != NULL) {
3940130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3941130613Smlaier			s->nat_src_node = nsn;
3942130613Smlaier			s->nat_src_node->states++;
3943130613Smlaier		}
3944130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3945145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3946130613Smlaier			pf_src_tree_remove_state(s);
3947145836Smlaier			STATE_DEC_COUNTERS(s);
3948126258Smlaier			pool_put(&pf_state_pl, s);
3949126258Smlaier			return (PF_DROP);
3950126258Smlaier		} else
3951126258Smlaier			*sm = s;
3952145836Smlaier		if (tag > 0) {
3953145836Smlaier			pf_tag_ref(tag);
3954145836Smlaier			s->tag = tag;
3955145836Smlaier		}
3956126258Smlaier	}
3957126258Smlaier
3958126258Smlaier	/* copy back packet headers if we performed NAT operations */
3959126258Smlaier	if (rewrite)
3960126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3961126258Smlaier
3962126258Smlaier	return (PF_PASS);
3963126258Smlaier}
3964126258Smlaier
3965126258Smlaierint
3966126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3967130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3968145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3969145836Smlaier    struct ifqueue *ifq)
3970126258Smlaier{
3971130613Smlaier	struct pf_rule		*nr = NULL;
3972126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3973126258Smlaier	struct pf_rule		*r, *a = NULL;
3974126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3975130613Smlaier	struct pf_src_node	*nsn = NULL;
3976126258Smlaier	u_short			 reason;
3977149893Smlaier	u_int16_t		 icmpid = 0, bport, nport = 0;
3978126258Smlaier	sa_family_t		 af = pd->af;
3979127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3980127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3981126258Smlaier	int			 state_icmp = 0;
3982171168Smlaier	int			 tag = -1, rtableid = -1;
3983126258Smlaier#ifdef INET6
3984126258Smlaier	int			 rewrite = 0;
3985126258Smlaier#endif /* INET6 */
3986145836Smlaier	int			 asd = 0;
3987171168Smlaier	int			 match = 0;
3988126258Smlaier
3989145836Smlaier	if (pf_check_congestion(ifq)) {
3990145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3991145836Smlaier		return (PF_DROP);
3992145836Smlaier	}
3993145836Smlaier
3994126258Smlaier	switch (pd->proto) {
3995126258Smlaier#ifdef INET
3996126258Smlaier	case IPPROTO_ICMP:
3997126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3998126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
3999126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4000126258Smlaier
4001126258Smlaier		if (icmptype == ICMP_UNREACH ||
4002126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4003126258Smlaier		    icmptype == ICMP_REDIRECT ||
4004126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4005126258Smlaier		    icmptype == ICMP_PARAMPROB)
4006126258Smlaier			state_icmp++;
4007126258Smlaier		break;
4008126258Smlaier#endif /* INET */
4009126258Smlaier#ifdef INET6
4010126258Smlaier	case IPPROTO_ICMPV6:
4011126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4012126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
4013126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4014126258Smlaier
4015126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4016126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4017126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4018126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4019126258Smlaier			state_icmp++;
4020126258Smlaier		break;
4021126258Smlaier#endif /* INET6 */
4022126258Smlaier	}
4023126258Smlaier
4024126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4025126258Smlaier
4026126258Smlaier	if (direction == PF_OUT) {
4027149884Smlaier		bport = nport = icmpid;
4028126258Smlaier		/* check outgoing packet for BINAT/NAT */
4029130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4030149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4031149884Smlaier		    NULL) {
4032130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4033126258Smlaier			switch (af) {
4034126258Smlaier#ifdef INET
4035126258Smlaier			case AF_INET:
4036126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4037130613Smlaier				    pd->naddr.v4.s_addr, 0);
4038149884Smlaier				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
4039149884Smlaier				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
4040149884Smlaier				pd->hdr.icmp->icmp_id = nport;
4041149893Smlaier				m_copyback(m, off, ICMP_MINLEN,
4042149893Smlaier				    (caddr_t)pd->hdr.icmp);
4043126258Smlaier				break;
4044126258Smlaier#endif /* INET */
4045126258Smlaier#ifdef INET6
4046126258Smlaier			case AF_INET6:
4047126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
4048130613Smlaier				    &pd->naddr, 0);
4049126258Smlaier				rewrite++;
4050126258Smlaier				break;
4051126258Smlaier#endif /* INET6 */
4052126258Smlaier			}
4053130613Smlaier			if (nr->natpass)
4054126258Smlaier				r = NULL;
4055130613Smlaier			pd->nat_rule = nr;
4056126258Smlaier		}
4057126258Smlaier	} else {
4058149884Smlaier		bport = nport = icmpid;
4059126258Smlaier		/* check incoming packet for BINAT/RDR */
4060130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4061149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4062149884Smlaier		    NULL) {
4063130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4064126258Smlaier			switch (af) {
4065126258Smlaier#ifdef INET
4066126258Smlaier			case AF_INET:
4067126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4068130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4069126258Smlaier				break;
4070126258Smlaier#endif /* INET */
4071126258Smlaier#ifdef INET6
4072126258Smlaier			case AF_INET6:
4073126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
4074130613Smlaier				    &pd->naddr, 0);
4075126258Smlaier				rewrite++;
4076126258Smlaier				break;
4077126258Smlaier#endif /* INET6 */
4078126258Smlaier			}
4079130613Smlaier			if (nr->natpass)
4080126258Smlaier				r = NULL;
4081130613Smlaier			pd->nat_rule = nr;
4082126258Smlaier		}
4083126258Smlaier	}
4084126258Smlaier
4085126258Smlaier	while (r != NULL) {
4086126258Smlaier		r->evaluations++;
4087171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4088126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4089126258Smlaier		else if (r->direction && r->direction != direction)
4090126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4091126258Smlaier		else if (r->af && r->af != af)
4092126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4093126258Smlaier		else if (r->proto && r->proto != pd->proto)
4094126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4095171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
4096171168Smlaier		    r->src.neg, kif))
4097126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4098171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
4099171168Smlaier		    r->dst.neg, NULL))
4100126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4101126258Smlaier		else if (r->type && r->type != icmptype + 1)
4102126258Smlaier			r = TAILQ_NEXT(r, entries);
4103126258Smlaier		else if (r->code && r->code != icmpcode + 1)
4104126258Smlaier			r = TAILQ_NEXT(r, entries);
4105171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4106126258Smlaier			r = TAILQ_NEXT(r, entries);
4107126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4108126258Smlaier			r = TAILQ_NEXT(r, entries);
4109145836Smlaier		else if (r->prob && r->prob <= arc4random())
4110126258Smlaier			r = TAILQ_NEXT(r, entries);
4111171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4112126258Smlaier			r = TAILQ_NEXT(r, entries);
4113126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4114126258Smlaier			r = TAILQ_NEXT(r, entries);
4115126258Smlaier		else {
4116126258Smlaier			if (r->tag)
4117126258Smlaier				tag = r->tag;
4118171168Smlaier			if (r->rtableid >= 0)
4119171168Smlaier				rtableid = r->rtableid;
4120126258Smlaier			if (r->anchor == NULL) {
4121171168Smlaier				match = 1;
4122126258Smlaier				*rm = r;
4123126258Smlaier				*am = a;
4124126258Smlaier				*rsm = ruleset;
4125126258Smlaier				if ((*rm)->quick)
4126126258Smlaier					break;
4127126258Smlaier				r = TAILQ_NEXT(r, entries);
4128126258Smlaier			} else
4129145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4130171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4131126258Smlaier		}
4132171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4133171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4134171168Smlaier			break;
4135126258Smlaier	}
4136126258Smlaier	r = *rm;
4137126258Smlaier	a = *am;
4138126258Smlaier	ruleset = *rsm;
4139126258Smlaier
4140126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4141126258Smlaier
4142171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
4143126258Smlaier#ifdef INET6
4144126258Smlaier		if (rewrite)
4145126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
4146126261Smlaier			    (caddr_t)pd->hdr.icmp6);
4147126258Smlaier#endif /* INET6 */
4148171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4149171168Smlaier		    a, ruleset, pd);
4150126258Smlaier	}
4151126258Smlaier
4152126258Smlaier	if (r->action != PF_PASS)
4153126258Smlaier		return (PF_DROP);
4154126258Smlaier
4155171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4156126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4157126258Smlaier		return (PF_DROP);
4158126258Smlaier	}
4159126258Smlaier
4160130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
4161126258Smlaier		/* create new state */
4162126258Smlaier		struct pf_state	*s = NULL;
4163130613Smlaier		struct pf_src_node *sn = NULL;
4164126258Smlaier
4165130613Smlaier		/* check maximums */
4166145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4167145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4168145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4169130613Smlaier			goto cleanup;
4170145836Smlaier		}
4171171168Smlaier		/* src node for filter rule */
4172130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4173130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4174145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4175145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4176130613Smlaier			goto cleanup;
4177145836Smlaier		}
4178130613Smlaier		/* src node for translation rule */
4179130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4180130613Smlaier		    ((direction == PF_OUT &&
4181130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4182145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4183145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4184130613Smlaier			goto cleanup;
4185145836Smlaier		}
4186130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4187126258Smlaier		if (s == NULL) {
4188145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4189130613Smlaiercleanup:
4190130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4191130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4192130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4193130613Smlaier				pf_status.src_nodes--;
4194130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4195130613Smlaier			}
4196130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4197130613Smlaier			    nsn->expire == 0) {
4198130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4199130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4200130613Smlaier				pf_status.src_nodes--;
4201130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4202130613Smlaier			}
4203126258Smlaier			return (PF_DROP);
4204126258Smlaier		}
4205126258Smlaier		bzero(s, sizeof(*s));
4206126258Smlaier		s->rule.ptr = r;
4207130613Smlaier		s->nat_rule.ptr = nr;
4208126258Smlaier		s->anchor.ptr = a;
4209145836Smlaier		STATE_INC_COUNTERS(s);
4210126258Smlaier		s->allow_opts = r->allow_opts;
4211171168Smlaier		s->log = r->log & PF_LOG_ALL;
4212171168Smlaier		if (nr != NULL)
4213171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4214126258Smlaier		s->proto = pd->proto;
4215126258Smlaier		s->direction = direction;
4216126258Smlaier		s->af = af;
4217126258Smlaier		if (direction == PF_OUT) {
4218126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4219149884Smlaier			s->gwy.port = nport;
4220126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4221149884Smlaier			s->ext.port = 0;
4222149884Smlaier			if (nr != NULL) {
4223130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4224149884Smlaier				s->lan.port = bport;
4225149884Smlaier			} else {
4226126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4227149884Smlaier				s->lan.port = s->gwy.port;
4228149884Smlaier			}
4229126258Smlaier		} else {
4230126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4231149884Smlaier			s->lan.port = nport;
4232126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4233149884Smlaier			s->ext.port = 0;
4234149884Smlaier			if (nr != NULL) {
4235130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4236149884Smlaier				s->gwy.port = bport;
4237149884Smlaier			} else {
4238126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4239149884Smlaier				s->gwy.port = s->lan.port;
4240149884Smlaier			}
4241126258Smlaier		}
4242126261Smlaier		s->creation = time_second;
4243126261Smlaier		s->expire = time_second;
4244126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
4245126258Smlaier		pf_set_rt_ifp(s, saddr);
4246130613Smlaier		if (sn != NULL) {
4247130613Smlaier			s->src_node = sn;
4248130613Smlaier			s->src_node->states++;
4249130613Smlaier		}
4250130613Smlaier		if (nsn != NULL) {
4251130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4252130613Smlaier			s->nat_src_node = nsn;
4253130613Smlaier			s->nat_src_node->states++;
4254130613Smlaier		}
4255130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4256145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4257130613Smlaier			pf_src_tree_remove_state(s);
4258145836Smlaier			STATE_DEC_COUNTERS(s);
4259126258Smlaier			pool_put(&pf_state_pl, s);
4260126258Smlaier			return (PF_DROP);
4261126258Smlaier		} else
4262126258Smlaier			*sm = s;
4263145836Smlaier		if (tag > 0) {
4264145836Smlaier			pf_tag_ref(tag);
4265145836Smlaier			s->tag = tag;
4266145836Smlaier		}
4267126258Smlaier	}
4268126258Smlaier
4269126258Smlaier#ifdef INET6
4270126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
4271126258Smlaier	if (rewrite)
4272126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
4273126261Smlaier		    (caddr_t)pd->hdr.icmp6);
4274126258Smlaier#endif /* INET6 */
4275126258Smlaier
4276126258Smlaier	return (PF_PASS);
4277126258Smlaier}
4278126258Smlaier
4279126258Smlaierint
4280126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
4281130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4282145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
4283126258Smlaier{
4284130613Smlaier	struct pf_rule		*nr = NULL;
4285126258Smlaier	struct pf_rule		*r, *a = NULL;
4286126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4287130613Smlaier	struct pf_src_node	*nsn = NULL;
4288126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
4289126258Smlaier	sa_family_t		 af = pd->af;
4290126258Smlaier	u_short			 reason;
4291171168Smlaier	int			 tag = -1, rtableid = -1;
4292145836Smlaier	int			 asd = 0;
4293171168Smlaier	int			 match = 0;
4294126258Smlaier
4295145836Smlaier	if (pf_check_congestion(ifq)) {
4296145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
4297145836Smlaier		return (PF_DROP);
4298145836Smlaier	}
4299145836Smlaier
4300126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4301126258Smlaier
4302126258Smlaier	if (direction == PF_OUT) {
4303126258Smlaier		/* check outgoing packet for BINAT/NAT */
4304130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4305130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4306130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4307126258Smlaier			switch (af) {
4308126258Smlaier#ifdef INET
4309126258Smlaier			case AF_INET:
4310126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4311130613Smlaier				    pd->naddr.v4.s_addr, 0);
4312126258Smlaier				break;
4313126258Smlaier#endif /* INET */
4314126258Smlaier#ifdef INET6
4315126258Smlaier			case AF_INET6:
4316130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
4317126258Smlaier				break;
4318126258Smlaier#endif /* INET6 */
4319126258Smlaier			}
4320130613Smlaier			if (nr->natpass)
4321126258Smlaier				r = NULL;
4322130613Smlaier			pd->nat_rule = nr;
4323126258Smlaier		}
4324126258Smlaier	} else {
4325126258Smlaier		/* check incoming packet for BINAT/RDR */
4326130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4327130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4328130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4329126258Smlaier			switch (af) {
4330126258Smlaier#ifdef INET
4331126258Smlaier			case AF_INET:
4332126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4333130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4334126258Smlaier				break;
4335126258Smlaier#endif /* INET */
4336126258Smlaier#ifdef INET6
4337126258Smlaier			case AF_INET6:
4338130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
4339126258Smlaier				break;
4340126258Smlaier#endif /* INET6 */
4341126258Smlaier			}
4342130613Smlaier			if (nr->natpass)
4343126258Smlaier				r = NULL;
4344130613Smlaier			pd->nat_rule = nr;
4345126258Smlaier		}
4346126258Smlaier	}
4347126258Smlaier
4348126258Smlaier	while (r != NULL) {
4349126258Smlaier		r->evaluations++;
4350171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4351126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4352126258Smlaier		else if (r->direction && r->direction != direction)
4353126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4354126258Smlaier		else if (r->af && r->af != af)
4355126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4356126258Smlaier		else if (r->proto && r->proto != pd->proto)
4357126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4358171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4359171168Smlaier		    r->src.neg, kif))
4360126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4361171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4362171168Smlaier		    r->dst.neg, NULL))
4363126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4364171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4365126258Smlaier			r = TAILQ_NEXT(r, entries);
4366126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4367126258Smlaier			r = TAILQ_NEXT(r, entries);
4368145836Smlaier		else if (r->prob && r->prob <= arc4random())
4369126258Smlaier			r = TAILQ_NEXT(r, entries);
4370171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4371126258Smlaier			r = TAILQ_NEXT(r, entries);
4372126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4373126258Smlaier			r = TAILQ_NEXT(r, entries);
4374126258Smlaier		else {
4375126258Smlaier			if (r->tag)
4376126258Smlaier				tag = r->tag;
4377171168Smlaier			if (r->rtableid >= 0)
4378171168Smlaier				rtableid = r->rtableid;
4379126258Smlaier			if (r->anchor == NULL) {
4380171168Smlaier				match = 1;
4381126258Smlaier				*rm = r;
4382126258Smlaier				*am = a;
4383126258Smlaier				*rsm = ruleset;
4384126258Smlaier				if ((*rm)->quick)
4385126258Smlaier					break;
4386126258Smlaier				r = TAILQ_NEXT(r, entries);
4387126258Smlaier			} else
4388145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4389171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4390126258Smlaier		}
4391171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4392171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4393171168Smlaier			break;
4394126258Smlaier	}
4395126258Smlaier	r = *rm;
4396126258Smlaier	a = *am;
4397126258Smlaier	ruleset = *rsm;
4398126258Smlaier
4399126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4400130613Smlaier
4401171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log))
4402171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4403171168Smlaier		    a, ruleset, pd);
4404126258Smlaier
4405126258Smlaier	if ((r->action == PF_DROP) &&
4406126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4407126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4408126258Smlaier		struct pf_addr *a = NULL;
4409126258Smlaier
4410130613Smlaier		if (nr != NULL) {
4411130613Smlaier			if (direction == PF_OUT)
4412130613Smlaier				a = saddr;
4413130613Smlaier			else
4414130613Smlaier				a = daddr;
4415130613Smlaier		}
4416126258Smlaier		if (a != NULL) {
4417126258Smlaier			switch (af) {
4418126258Smlaier#ifdef INET
4419126258Smlaier			case AF_INET:
4420126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4421130613Smlaier				    pd->baddr.v4.s_addr, 0);
4422126258Smlaier				break;
4423126258Smlaier#endif /* INET */
4424126258Smlaier#ifdef INET6
4425126258Smlaier			case AF_INET6:
4426130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4427126258Smlaier				break;
4428126258Smlaier#endif /* INET6 */
4429126258Smlaier			}
4430126258Smlaier		}
4431126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4432126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4433126258Smlaier			    r->return_icmp & 255, af, r);
4434126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4435126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4436126258Smlaier			    r->return_icmp6 & 255, af, r);
4437126258Smlaier	}
4438126258Smlaier
4439126258Smlaier	if (r->action != PF_PASS)
4440126258Smlaier		return (PF_DROP);
4441126258Smlaier
4442171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4443126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4444126258Smlaier		return (PF_DROP);
4445126258Smlaier	}
4446126258Smlaier
4447130613Smlaier	if (r->keep_state || nr != NULL) {
4448126258Smlaier		/* create new state */
4449126258Smlaier		struct pf_state	*s = NULL;
4450130613Smlaier		struct pf_src_node *sn = NULL;
4451126258Smlaier
4452130613Smlaier		/* check maximums */
4453145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4454145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4455145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4456130613Smlaier			goto cleanup;
4457145836Smlaier		}
4458171168Smlaier		/* src node for filter rule */
4459130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4460130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4461145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4462145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4463130613Smlaier			goto cleanup;
4464145836Smlaier		}
4465130613Smlaier		/* src node for translation rule */
4466130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4467130613Smlaier		    ((direction == PF_OUT &&
4468130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4469145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4470145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4471130613Smlaier			goto cleanup;
4472145836Smlaier		}
4473130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4474126258Smlaier		if (s == NULL) {
4475145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4476130613Smlaiercleanup:
4477130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4478130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4479130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4480130613Smlaier				pf_status.src_nodes--;
4481130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4482130613Smlaier			}
4483130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4484130613Smlaier			    nsn->expire == 0) {
4485130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4486130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4487130613Smlaier				pf_status.src_nodes--;
4488130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4489130613Smlaier			}
4490126258Smlaier			return (PF_DROP);
4491126258Smlaier		}
4492126258Smlaier		bzero(s, sizeof(*s));
4493126258Smlaier		s->rule.ptr = r;
4494130613Smlaier		s->nat_rule.ptr = nr;
4495126258Smlaier		s->anchor.ptr = a;
4496145836Smlaier		STATE_INC_COUNTERS(s);
4497126258Smlaier		s->allow_opts = r->allow_opts;
4498171168Smlaier		s->log = r->log & PF_LOG_ALL;
4499171168Smlaier		if (nr != NULL)
4500171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4501126258Smlaier		s->proto = pd->proto;
4502126258Smlaier		s->direction = direction;
4503126258Smlaier		s->af = af;
4504126258Smlaier		if (direction == PF_OUT) {
4505126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4506126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4507130613Smlaier			if (nr != NULL)
4508130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4509126258Smlaier			else
4510126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4511126258Smlaier		} else {
4512126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4513126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4514130613Smlaier			if (nr != NULL)
4515130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4516126258Smlaier			else
4517126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4518126258Smlaier		}
4519126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4520126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4521126261Smlaier		s->creation = time_second;
4522126261Smlaier		s->expire = time_second;
4523126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4524126258Smlaier		pf_set_rt_ifp(s, saddr);
4525130613Smlaier		if (sn != NULL) {
4526130613Smlaier			s->src_node = sn;
4527130613Smlaier			s->src_node->states++;
4528130613Smlaier		}
4529130613Smlaier		if (nsn != NULL) {
4530130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4531130613Smlaier			s->nat_src_node = nsn;
4532130613Smlaier			s->nat_src_node->states++;
4533130613Smlaier		}
4534130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4535145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4536130613Smlaier			pf_src_tree_remove_state(s);
4537145836Smlaier			STATE_DEC_COUNTERS(s);
4538126258Smlaier			pool_put(&pf_state_pl, s);
4539126258Smlaier			return (PF_DROP);
4540126258Smlaier		} else
4541126258Smlaier			*sm = s;
4542145836Smlaier		if (tag > 0) {
4543145836Smlaier			pf_tag_ref(tag);
4544145836Smlaier			s->tag = tag;
4545145836Smlaier		}
4546126258Smlaier	}
4547126258Smlaier
4548126258Smlaier	return (PF_PASS);
4549126258Smlaier}
4550126258Smlaier
4551126258Smlaierint
4552130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4553126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4554126258Smlaier    struct pf_ruleset **rsm)
4555126258Smlaier{
4556126258Smlaier	struct pf_rule		*r, *a = NULL;
4557126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4558126258Smlaier	sa_family_t		 af = pd->af;
4559126258Smlaier	u_short			 reason;
4560126258Smlaier	int			 tag = -1;
4561145836Smlaier	int			 asd = 0;
4562171168Smlaier	int			 match = 0;
4563126258Smlaier
4564126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4565126258Smlaier	while (r != NULL) {
4566126258Smlaier		r->evaluations++;
4567171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4568126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4569126258Smlaier		else if (r->direction && r->direction != direction)
4570126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4571126258Smlaier		else if (r->af && r->af != af)
4572126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4573126258Smlaier		else if (r->proto && r->proto != pd->proto)
4574126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4575171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4576171168Smlaier		    r->src.neg, kif))
4577126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4578171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4579171168Smlaier		    r->dst.neg, NULL))
4580126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4581171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4582126258Smlaier			r = TAILQ_NEXT(r, entries);
4583173815Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4584126258Smlaier			r = TAILQ_NEXT(r, entries);
4585173815Smlaier		else if (pd->proto == IPPROTO_UDP &&
4586173815Smlaier		    (r->src.port_op || r->dst.port_op))
4587173815Smlaier			r = TAILQ_NEXT(r, entries);
4588173815Smlaier		else if (pd->proto == IPPROTO_TCP &&
4589173815Smlaier		    (r->src.port_op || r->dst.port_op || r->flagset))
4590173815Smlaier			r = TAILQ_NEXT(r, entries);
4591173815Smlaier		else if ((pd->proto == IPPROTO_ICMP ||
4592173815Smlaier		    pd->proto == IPPROTO_ICMPV6) &&
4593173815Smlaier		    (r->type || r->code))
4594173815Smlaier			r = TAILQ_NEXT(r, entries);
4595145836Smlaier		else if (r->prob && r->prob <= arc4random())
4596126258Smlaier			r = TAILQ_NEXT(r, entries);
4597171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4598126258Smlaier			r = TAILQ_NEXT(r, entries);
4599126258Smlaier		else {
4600126258Smlaier			if (r->anchor == NULL) {
4601171168Smlaier				match = 1;
4602126258Smlaier				*rm = r;
4603126258Smlaier				*am = a;
4604126258Smlaier				*rsm = ruleset;
4605126258Smlaier				if ((*rm)->quick)
4606126258Smlaier					break;
4607126258Smlaier				r = TAILQ_NEXT(r, entries);
4608126258Smlaier			} else
4609145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4610171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4611126258Smlaier		}
4612171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4613171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4614171168Smlaier			break;
4615126258Smlaier	}
4616126258Smlaier	r = *rm;
4617126258Smlaier	a = *am;
4618126258Smlaier	ruleset = *rsm;
4619126258Smlaier
4620126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4621130613Smlaier
4622126258Smlaier	if (r->log)
4623171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
4624171168Smlaier		    pd);
4625126258Smlaier
4626126258Smlaier	if (r->action != PF_PASS)
4627126258Smlaier		return (PF_DROP);
4628126258Smlaier
4629171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
4630126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4631126258Smlaier		return (PF_DROP);
4632126258Smlaier	}
4633126258Smlaier
4634126258Smlaier	return (PF_PASS);
4635126258Smlaier}
4636126258Smlaier
4637126258Smlaierint
4638130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4639130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4640126258Smlaier    u_short *reason)
4641126258Smlaier{
4642171168Smlaier	struct pf_state_cmp	 key;
4643126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4644126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4645145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4646126258Smlaier	u_int8_t		 sws, dws;
4647130613Smlaier	int			 ackskew;
4648126258Smlaier	int			 copyback = 0;
4649126258Smlaier	struct pf_state_peer	*src, *dst;
4650126258Smlaier
4651126258Smlaier	key.af = pd->af;
4652126258Smlaier	key.proto = IPPROTO_TCP;
4653130613Smlaier	if (direction == PF_IN)	{
4654130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4655130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4656130613Smlaier		key.ext.port = th->th_sport;
4657130613Smlaier		key.gwy.port = th->th_dport;
4658130613Smlaier	} else {
4659130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4660130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4661130613Smlaier		key.lan.port = th->th_sport;
4662130613Smlaier		key.ext.port = th->th_dport;
4663130613Smlaier	}
4664126258Smlaier
4665126258Smlaier	STATE_LOOKUP();
4666126258Smlaier
4667126258Smlaier	if (direction == (*state)->direction) {
4668126258Smlaier		src = &(*state)->src;
4669126258Smlaier		dst = &(*state)->dst;
4670126258Smlaier	} else {
4671126258Smlaier		src = &(*state)->dst;
4672126258Smlaier		dst = &(*state)->src;
4673126258Smlaier	}
4674126258Smlaier
4675126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4676145836Smlaier		if (direction != (*state)->direction) {
4677145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4678126258Smlaier			return (PF_SYNPROXY_DROP);
4679145836Smlaier		}
4680126258Smlaier		if (th->th_flags & TH_SYN) {
4681145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4682145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4683126258Smlaier				return (PF_DROP);
4684145836Smlaier			}
4685162238Scsjp#ifdef __FreeBSD__
4686162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4687162238Scsjp#else
4688126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4689162238Scsjp#endif
4690126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4691126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4692145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4693171168Smlaier			    0, NULL, NULL);
4694145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4695126258Smlaier			return (PF_SYNPROXY_DROP);
4696126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4697126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4698145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4699145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4700126258Smlaier			return (PF_DROP);
4701145836Smlaier		} else if ((*state)->src_node != NULL &&
4702145836Smlaier		    pf_src_connlimit(state)) {
4703145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4704145836Smlaier			return (PF_DROP);
4705145836Smlaier		} else
4706126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4707126258Smlaier	}
4708126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4709126258Smlaier		struct pf_state_host *src, *dst;
4710126258Smlaier
4711126258Smlaier		if (direction == PF_OUT) {
4712126258Smlaier			src = &(*state)->gwy;
4713126258Smlaier			dst = &(*state)->ext;
4714126258Smlaier		} else {
4715126258Smlaier			src = &(*state)->ext;
4716126258Smlaier			dst = &(*state)->lan;
4717126258Smlaier		}
4718126258Smlaier		if (direction == (*state)->direction) {
4719126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4720126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4721145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4722145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4723126258Smlaier				return (PF_DROP);
4724145836Smlaier			}
4725126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4726126258Smlaier			if ((*state)->dst.seqhi == 1)
4727145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4728162238Scsjp#ifdef __FreeBSD__
4729162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4730162238Scsjp			    &src->addr,
4731162238Scsjp#else
4732126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4733162238Scsjp#endif
4734126258Smlaier			    &dst->addr, src->port, dst->port,
4735130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4736171168Smlaier			    (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
4737145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4738126258Smlaier			return (PF_SYNPROXY_DROP);
4739126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4740126258Smlaier		    (TH_SYN|TH_ACK)) ||
4741145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4742145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4743126258Smlaier			return (PF_DROP);
4744145836Smlaier		} else {
4745126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4746126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4747162238Scsjp#ifdef __FreeBSD__
4748162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4749162238Scsjp#else
4750126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4751162238Scsjp#endif
4752126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4753126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4754145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4755171168Smlaier			    (*state)->tag, NULL, NULL);
4756162238Scsjp#ifdef __FreeBSD__
4757162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4758162238Scsjp			    &src->addr,
4759162238Scsjp#else
4760126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4761162238Scsjp#endif
4762126258Smlaier			    &dst->addr, src->port, dst->port,
4763126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4764145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4765171168Smlaier			    0, NULL, NULL);
4766126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4767126258Smlaier			    (*state)->src.seqlo;
4768126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4769126258Smlaier			    (*state)->dst.seqlo;
4770126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4771145875Smlaier			    (*state)->dst.max_win;
4772145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4773145836Smlaier			    (*state)->src.max_win;
4774126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4775126258Smlaier			(*state)->src.state = (*state)->dst.state =
4776126258Smlaier			    TCPS_ESTABLISHED;
4777145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4778126258Smlaier			return (PF_SYNPROXY_DROP);
4779126258Smlaier		}
4780126258Smlaier	}
4781126258Smlaier
4782126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4783126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4784126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4785126258Smlaier	} else
4786126258Smlaier		sws = dws = 0;
4787126258Smlaier
4788126258Smlaier	/*
4789126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4790126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4791126258Smlaier	 *	tcp_filtering.ps
4792126258Smlaier	 */
4793126258Smlaier
4794145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4795126258Smlaier	if (src->seqlo == 0) {
4796126258Smlaier		/* First packet from this end. Set its state */
4797126258Smlaier
4798126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4799126258Smlaier		    src->scrub == NULL) {
4800126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4801126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4802126258Smlaier				return (PF_DROP);
4803126258Smlaier			}
4804126258Smlaier		}
4805126258Smlaier
4806126258Smlaier		/* Deferred generation of sequence number modulator */
4807126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4808171168Smlaier#ifdef __FreeBSD__
4809171168Smlaier			while ((src->seqdiff = pf_new_isn(*state) - seq) == 0)
4810126258Smlaier				;
4811171168Smlaier#else
4812171168Smlaier			while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
4813171168Smlaier				;
4814171168Smlaier#endif
4815126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4816126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4817126258Smlaier			    src->seqdiff), 0);
4818126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4819126258Smlaier			copyback = 1;
4820126258Smlaier		} else {
4821126258Smlaier			ack = ntohl(th->th_ack);
4822126258Smlaier		}
4823126258Smlaier
4824126258Smlaier		end = seq + pd->p_len;
4825126258Smlaier		if (th->th_flags & TH_SYN) {
4826126258Smlaier			end++;
4827126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4828126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4829126258Smlaier				    pd->af);
4830126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4831126258Smlaier					/* Remove scale factor from initial
4832126258Smlaier					 * window */
4833126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4834126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4835126258Smlaier					    >> sws;
4836126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4837126258Smlaier				} else {
4838126258Smlaier					/* fixup other window */
4839126258Smlaier					dst->max_win <<= dst->wscale &
4840126258Smlaier					    PF_WSCALE_MASK;
4841126258Smlaier					/* in case of a retrans SYN|ACK */
4842126258Smlaier					dst->wscale = 0;
4843126258Smlaier				}
4844126258Smlaier			}
4845126258Smlaier		}
4846126258Smlaier		if (th->th_flags & TH_FIN)
4847126258Smlaier			end++;
4848126258Smlaier
4849126258Smlaier		src->seqlo = seq;
4850126258Smlaier		if (src->state < TCPS_SYN_SENT)
4851126258Smlaier			src->state = TCPS_SYN_SENT;
4852126258Smlaier
4853126258Smlaier		/*
4854126258Smlaier		 * May need to slide the window (seqhi may have been set by
4855126258Smlaier		 * the crappy stack check or if we picked up the connection
4856126258Smlaier		 * after establishment)
4857126258Smlaier		 */
4858126258Smlaier		if (src->seqhi == 1 ||
4859126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4860126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4861126258Smlaier		if (win > src->max_win)
4862126258Smlaier			src->max_win = win;
4863126258Smlaier
4864126258Smlaier	} else {
4865126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4866126258Smlaier		if (src->seqdiff) {
4867126258Smlaier			/* Modulate sequence numbers */
4868126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4869126258Smlaier			    src->seqdiff), 0);
4870126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4871126258Smlaier			copyback = 1;
4872126258Smlaier		}
4873126258Smlaier		end = seq + pd->p_len;
4874126258Smlaier		if (th->th_flags & TH_SYN)
4875126258Smlaier			end++;
4876126258Smlaier		if (th->th_flags & TH_FIN)
4877126258Smlaier			end++;
4878126258Smlaier	}
4879126258Smlaier
4880126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4881126258Smlaier		/* Let it pass through the ack skew check */
4882126258Smlaier		ack = dst->seqlo;
4883126258Smlaier	} else if ((ack == 0 &&
4884126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4885126258Smlaier	    /* broken tcp stacks do not set ack */
4886126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4887126258Smlaier		/*
4888126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4889126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4890126258Smlaier		 */
4891126258Smlaier		ack = dst->seqlo;
4892126258Smlaier	}
4893126258Smlaier
4894126258Smlaier	if (seq == end) {
4895126258Smlaier		/* Ease sequencing restrictions on no data packets */
4896126258Smlaier		seq = src->seqlo;
4897126258Smlaier		end = seq;
4898126258Smlaier	}
4899126258Smlaier
4900126258Smlaier	ackskew = dst->seqlo - ack;
4901126258Smlaier
4902171168Smlaier
4903171168Smlaier	/*
4904171168Smlaier	 * Need to demodulate the sequence numbers in any TCP SACK options
4905171168Smlaier	 * (Selective ACK). We could optionally validate the SACK values
4906171168Smlaier	 * against the current ACK window, either forwards or backwards, but
4907171168Smlaier	 * I'm not confident that SACK has been implemented properly
4908171168Smlaier	 * everywhere. It wouldn't surprise me if several stacks accidently
4909171168Smlaier	 * SACK too far backwards of previously ACKed data. There really aren't
4910171168Smlaier	 * any security implications of bad SACKing unless the target stack
4911171168Smlaier	 * doesn't validate the option length correctly. Someone trying to
4912171168Smlaier	 * spoof into a TCP connection won't bother blindly sending SACK
4913171168Smlaier	 * options anyway.
4914171168Smlaier	 */
4915171168Smlaier	if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
4916171168Smlaier		if (pf_modulate_sack(m, off, pd, th, dst))
4917171168Smlaier			copyback = 1;
4918171168Smlaier	}
4919171168Smlaier
4920171168Smlaier
4921126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4922126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4923126258Smlaier	    /* Last octet inside other's window space */
4924126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4925126258Smlaier	    /* Retrans: not more than one window back */
4926126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4927126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4928145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4929126258Smlaier	    /* Acking not more than one window forward */
4930145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4931171168Smlaier	    (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
4932171168Smlaier	    /* Require an exact/+1 sequence match on resets when possible */
4933126258Smlaier
4934145836Smlaier		if (dst->scrub || src->scrub) {
4935145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4936145836Smlaier			    *state, src, dst, &copyback))
4937145836Smlaier				return (PF_DROP);
4938145836Smlaier		}
4939145836Smlaier
4940126258Smlaier		/* update max window */
4941126258Smlaier		if (src->max_win < win)
4942126258Smlaier			src->max_win = win;
4943126258Smlaier		/* synchronize sequencing */
4944126258Smlaier		if (SEQ_GT(end, src->seqlo))
4945126258Smlaier			src->seqlo = end;
4946126258Smlaier		/* slide the window of what the other end can send */
4947126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4948126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4949126258Smlaier
4950126258Smlaier
4951126258Smlaier		/* update states */
4952126258Smlaier		if (th->th_flags & TH_SYN)
4953126258Smlaier			if (src->state < TCPS_SYN_SENT)
4954126258Smlaier				src->state = TCPS_SYN_SENT;
4955126258Smlaier		if (th->th_flags & TH_FIN)
4956126258Smlaier			if (src->state < TCPS_CLOSING)
4957126258Smlaier				src->state = TCPS_CLOSING;
4958126258Smlaier		if (th->th_flags & TH_ACK) {
4959145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4960126258Smlaier				dst->state = TCPS_ESTABLISHED;
4961145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4962145836Smlaier				    (*state)->src_node != NULL &&
4963145836Smlaier				    pf_src_connlimit(state)) {
4964145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4965145836Smlaier					return (PF_DROP);
4966145836Smlaier				}
4967145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4968126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4969126258Smlaier		}
4970126258Smlaier		if (th->th_flags & TH_RST)
4971126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4972126258Smlaier
4973126258Smlaier		/* update expire time */
4974126261Smlaier		(*state)->expire = time_second;
4975126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4976126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4977126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4978171168Smlaier		else if (src->state >= TCPS_CLOSING &&
4979171168Smlaier		    dst->state >= TCPS_CLOSING)
4980126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4981126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4982126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4983126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4984126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4985126258Smlaier		    dst->state >= TCPS_CLOSING)
4986126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4987126258Smlaier		else
4988126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4989126258Smlaier
4990126258Smlaier		/* Fall through to PASS packet */
4991126258Smlaier
4992126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4993126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4994126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4995126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4996126258Smlaier	    /* Within a window forward of the originating packet */
4997126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4998126258Smlaier	    /* Within a window backward of the originating packet */
4999126258Smlaier
5000126258Smlaier		/*
5001126258Smlaier		 * This currently handles three situations:
5002126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
5003126258Smlaier		 *     replies.
5004126258Smlaier		 *  2) When PF catches an already established stream (the
5005126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
5006126258Smlaier		 *     changed...)
5007126258Smlaier		 *  3) Packets get funky immediately after the connection
5008126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
5009126258Smlaier		 *     that web servers like to spew after a close)
5010126258Smlaier		 *
5011126258Smlaier		 * This must be a little more careful than the above code
5012126258Smlaier		 * since packet floods will also be caught here. We don't
5013126258Smlaier		 * update the TTL here to mitigate the damage of a packet
5014126258Smlaier		 * flood and so the same code can handle awkward establishment
5015126258Smlaier		 * and a loosened connection close.
5016126258Smlaier		 * In the establishment case, a correct peer response will
5017126258Smlaier		 * validate the connection, go through the normal state code
5018126258Smlaier		 * and keep updating the state TTL.
5019126258Smlaier		 */
5020126258Smlaier
5021126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
5022126258Smlaier			printf("pf: loose state match: ");
5023126258Smlaier			pf_print_state(*state);
5024126258Smlaier			pf_print_flags(th->th_flags);
5025171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5026171168Smlaier			    "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
5027171168Smlaier#ifdef __FreeBSD__
5028171168Smlaier			    ackskew, (unsigned long long)(*state)->packets[0],
5029171168Smlaier			    (unsigned long long)(*state)->packets[1]);
5030171168Smlaier#else
5031171168Smlaier			    ackskew, (*state)->packets[0],
5032171168Smlaier			    (*state)->packets[1]);
5033171168Smlaier#endif
5034126258Smlaier		}
5035126258Smlaier
5036145836Smlaier		if (dst->scrub || src->scrub) {
5037145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
5038145836Smlaier			    *state, src, dst, &copyback))
5039145836Smlaier				return (PF_DROP);
5040145836Smlaier		}
5041145836Smlaier
5042126258Smlaier		/* update max window */
5043126258Smlaier		if (src->max_win < win)
5044126258Smlaier			src->max_win = win;
5045126258Smlaier		/* synchronize sequencing */
5046126258Smlaier		if (SEQ_GT(end, src->seqlo))
5047126258Smlaier			src->seqlo = end;
5048126258Smlaier		/* slide the window of what the other end can send */
5049126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
5050126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
5051126258Smlaier
5052126258Smlaier		/*
5053126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
5054126258Smlaier		 * SYN and not an already established connection.
5055126258Smlaier		 */
5056126258Smlaier
5057126258Smlaier		if (th->th_flags & TH_FIN)
5058126258Smlaier			if (src->state < TCPS_CLOSING)
5059126258Smlaier				src->state = TCPS_CLOSING;
5060126258Smlaier		if (th->th_flags & TH_RST)
5061126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
5062126258Smlaier
5063126258Smlaier		/* Fall through to PASS packet */
5064126258Smlaier
5065126258Smlaier	} else {
5066126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
5067126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
5068126258Smlaier			/* Send RST for state mismatches during handshake */
5069145836Smlaier			if (!(th->th_flags & TH_RST))
5070162238Scsjp#ifdef __FreeBSD__
5071162238Scsjp				pf_send_tcp(m, (*state)->rule.ptr, pd->af,
5072162238Scsjp#else
5073126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
5074162238Scsjp#endif
5075126258Smlaier				    pd->dst, pd->src, th->th_dport,
5076145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
5077145836Smlaier				    TH_RST, 0, 0,
5078171168Smlaier				    (*state)->rule.ptr->return_ttl, 1, 0,
5079145836Smlaier				    pd->eh, kif->pfik_ifp);
5080126258Smlaier			src->seqlo = 0;
5081126258Smlaier			src->seqhi = 1;
5082126258Smlaier			src->max_win = 1;
5083126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
5084126258Smlaier			printf("pf: BAD state: ");
5085126258Smlaier			pf_print_state(*state);
5086126258Smlaier			pf_print_flags(th->th_flags);
5087171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5088171168Smlaier			    "pkts=%llu:%llu dir=%s,%s\n",
5089171168Smlaier			    seq, orig_seq, ack, pd->p_len, ackskew,
5090171168Smlaier#ifdef __FreeBSD__
5091171168Smlaier			    (unsigned long long)(*state)->packets[0],
5092171168Smlaier			    (unsigned long long)(*state)->packets[1],
5093171168Smlaier#else
5094126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
5095171168Smlaier#endif
5096126258Smlaier			    direction == PF_IN ? "in" : "out",
5097126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
5098126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
5099126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
5100126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
5101126258Smlaier			    ' ': '2',
5102126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
5103126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
5104126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
5105126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
5106126258Smlaier		}
5107145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
5108126258Smlaier		return (PF_DROP);
5109126258Smlaier	}
5110126258Smlaier
5111126258Smlaier	/* Any packets which have gotten here are to be passed */
5112126258Smlaier
5113126258Smlaier	/* translate source/destination address, if necessary */
5114126258Smlaier	if (STATE_TRANSLATE(*state)) {
5115126258Smlaier		if (direction == PF_OUT)
5116126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
5117126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
5118126258Smlaier			    (*state)->gwy.port, 0, pd->af);
5119126258Smlaier		else
5120126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
5121126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
5122126258Smlaier			    (*state)->lan.port, 0, pd->af);
5123126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5124126258Smlaier	} else if (copyback) {
5125126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
5126126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5127126258Smlaier	}
5128126258Smlaier
5129126258Smlaier	return (PF_PASS);
5130126258Smlaier}
5131126258Smlaier
5132126258Smlaierint
5133130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
5134130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
5135126258Smlaier{
5136126258Smlaier	struct pf_state_peer	*src, *dst;
5137171168Smlaier	struct pf_state_cmp	 key;
5138126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
5139126258Smlaier
5140126258Smlaier	key.af = pd->af;
5141126258Smlaier	key.proto = IPPROTO_UDP;
5142130613Smlaier	if (direction == PF_IN)	{
5143130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5144130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5145130613Smlaier		key.ext.port = uh->uh_sport;
5146130613Smlaier		key.gwy.port = uh->uh_dport;
5147130613Smlaier	} else {
5148130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5149130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5150130613Smlaier		key.lan.port = uh->uh_sport;
5151130613Smlaier		key.ext.port = uh->uh_dport;
5152130613Smlaier	}
5153126258Smlaier
5154126258Smlaier	STATE_LOOKUP();
5155126258Smlaier
5156126258Smlaier	if (direction == (*state)->direction) {
5157126258Smlaier		src = &(*state)->src;
5158126258Smlaier		dst = &(*state)->dst;
5159126258Smlaier	} else {
5160126258Smlaier		src = &(*state)->dst;
5161126258Smlaier		dst = &(*state)->src;
5162126258Smlaier	}
5163126258Smlaier
5164126258Smlaier	/* update states */
5165126258Smlaier	if (src->state < PFUDPS_SINGLE)
5166126258Smlaier		src->state = PFUDPS_SINGLE;
5167126258Smlaier	if (dst->state == PFUDPS_SINGLE)
5168126258Smlaier		dst->state = PFUDPS_MULTIPLE;
5169126258Smlaier
5170126258Smlaier	/* update expire time */
5171126261Smlaier	(*state)->expire = time_second;
5172126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
5173126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
5174126258Smlaier	else
5175126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
5176126258Smlaier
5177126258Smlaier	/* translate source/destination address, if necessary */
5178126258Smlaier	if (STATE_TRANSLATE(*state)) {
5179126258Smlaier		if (direction == PF_OUT)
5180126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
5181126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
5182126258Smlaier			    (*state)->gwy.port, 1, pd->af);
5183126258Smlaier		else
5184126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
5185126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
5186126258Smlaier			    (*state)->lan.port, 1, pd->af);
5187126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
5188126258Smlaier	}
5189126258Smlaier
5190126258Smlaier	return (PF_PASS);
5191126258Smlaier}
5192126258Smlaier
5193126258Smlaierint
5194130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
5195145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
5196126258Smlaier{
5197126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
5198127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
5199127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
5200127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
5201130613Smlaier	int		 state_icmp = 0;
5202171168Smlaier	struct pf_state_cmp key;
5203126258Smlaier
5204126258Smlaier	switch (pd->proto) {
5205126258Smlaier#ifdef INET
5206126258Smlaier	case IPPROTO_ICMP:
5207126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
5208126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
5209126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
5210126258Smlaier
5211126258Smlaier		if (icmptype == ICMP_UNREACH ||
5212126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
5213126258Smlaier		    icmptype == ICMP_REDIRECT ||
5214126258Smlaier		    icmptype == ICMP_TIMXCEED ||
5215126258Smlaier		    icmptype == ICMP_PARAMPROB)
5216126258Smlaier			state_icmp++;
5217126258Smlaier		break;
5218126258Smlaier#endif /* INET */
5219126258Smlaier#ifdef INET6
5220126258Smlaier	case IPPROTO_ICMPV6:
5221126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
5222126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
5223126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
5224126258Smlaier
5225126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
5226126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
5227126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
5228126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
5229126258Smlaier			state_icmp++;
5230126258Smlaier		break;
5231126258Smlaier#endif /* INET6 */
5232126258Smlaier	}
5233126258Smlaier
5234126258Smlaier	if (!state_icmp) {
5235126258Smlaier
5236126258Smlaier		/*
5237126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
5238126258Smlaier		 * Search for an ICMP state.
5239126258Smlaier		 */
5240126258Smlaier		key.af = pd->af;
5241126258Smlaier		key.proto = pd->proto;
5242130613Smlaier		if (direction == PF_IN)	{
5243130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
5244130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5245149884Smlaier			key.ext.port = 0;
5246130613Smlaier			key.gwy.port = icmpid;
5247130613Smlaier		} else {
5248130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
5249130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
5250130613Smlaier			key.lan.port = icmpid;
5251149884Smlaier			key.ext.port = 0;
5252130613Smlaier		}
5253126258Smlaier
5254126258Smlaier		STATE_LOOKUP();
5255126258Smlaier
5256126261Smlaier		(*state)->expire = time_second;
5257126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
5258126258Smlaier
5259126258Smlaier		/* translate source/destination address, if necessary */
5260149884Smlaier		if (STATE_TRANSLATE(*state)) {
5261126258Smlaier			if (direction == PF_OUT) {
5262126258Smlaier				switch (pd->af) {
5263126258Smlaier#ifdef INET
5264126258Smlaier				case AF_INET:
5265126258Smlaier					pf_change_a(&saddr->v4.s_addr,
5266126258Smlaier					    pd->ip_sum,
5267126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
5268149884Smlaier					pd->hdr.icmp->icmp_cksum =
5269149884Smlaier					    pf_cksum_fixup(
5270149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5271149884Smlaier					    (*state)->gwy.port, 0);
5272149884Smlaier					pd->hdr.icmp->icmp_id =
5273149884Smlaier					    (*state)->gwy.port;
5274149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5275149893Smlaier					    (caddr_t)pd->hdr.icmp);
5276126258Smlaier					break;
5277126258Smlaier#endif /* INET */
5278126258Smlaier#ifdef INET6
5279126258Smlaier				case AF_INET6:
5280126258Smlaier					pf_change_a6(saddr,
5281126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5282126258Smlaier					    &(*state)->gwy.addr, 0);
5283126258Smlaier					m_copyback(m, off,
5284126258Smlaier					    sizeof(struct icmp6_hdr),
5285126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5286126258Smlaier					break;
5287126258Smlaier#endif /* INET6 */
5288126258Smlaier				}
5289126258Smlaier			} else {
5290126258Smlaier				switch (pd->af) {
5291126258Smlaier#ifdef INET
5292126258Smlaier				case AF_INET:
5293126258Smlaier					pf_change_a(&daddr->v4.s_addr,
5294126258Smlaier					    pd->ip_sum,
5295126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
5296149884Smlaier					pd->hdr.icmp->icmp_cksum =
5297149884Smlaier					    pf_cksum_fixup(
5298149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5299149884Smlaier					    (*state)->lan.port, 0);
5300149884Smlaier					pd->hdr.icmp->icmp_id =
5301149884Smlaier					    (*state)->lan.port;
5302149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5303149893Smlaier					    (caddr_t)pd->hdr.icmp);
5304126258Smlaier					break;
5305126258Smlaier#endif /* INET */
5306126258Smlaier#ifdef INET6
5307126258Smlaier				case AF_INET6:
5308126258Smlaier					pf_change_a6(daddr,
5309126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5310126258Smlaier					    &(*state)->lan.addr, 0);
5311126258Smlaier					m_copyback(m, off,
5312126258Smlaier					    sizeof(struct icmp6_hdr),
5313126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5314126258Smlaier					break;
5315126258Smlaier#endif /* INET6 */
5316126258Smlaier				}
5317126258Smlaier			}
5318126258Smlaier		}
5319126258Smlaier
5320126258Smlaier		return (PF_PASS);
5321126258Smlaier
5322126258Smlaier	} else {
5323126258Smlaier		/*
5324126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
5325126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
5326126258Smlaier		 */
5327126258Smlaier
5328126258Smlaier		struct pf_pdesc	pd2;
5329126258Smlaier#ifdef INET
5330126258Smlaier		struct ip	h2;
5331126258Smlaier#endif /* INET */
5332126258Smlaier#ifdef INET6
5333126258Smlaier		struct ip6_hdr	h2_6;
5334126258Smlaier		int		terminal = 0;
5335126258Smlaier#endif /* INET6 */
5336127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
5337127629Smlaier		int		off2 = 0;	/* make the compiler happy */
5338126258Smlaier
5339126258Smlaier		pd2.af = pd->af;
5340126258Smlaier		switch (pd->af) {
5341126258Smlaier#ifdef INET
5342126258Smlaier		case AF_INET:
5343126258Smlaier			/* offset of h2 in mbuf chain */
5344126258Smlaier			ipoff2 = off + ICMP_MINLEN;
5345126258Smlaier
5346126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
5347145836Smlaier			    NULL, reason, pd2.af)) {
5348126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5349126258Smlaier				    ("pf: ICMP error message too short "
5350126258Smlaier				    "(ip)\n"));
5351126258Smlaier				return (PF_DROP);
5352126258Smlaier			}
5353126258Smlaier			/*
5354126258Smlaier			 * ICMP error messages don't refer to non-first
5355126258Smlaier			 * fragments
5356126258Smlaier			 */
5357145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
5358145836Smlaier				REASON_SET(reason, PFRES_FRAG);
5359126258Smlaier				return (PF_DROP);
5360145836Smlaier			}
5361126258Smlaier
5362126258Smlaier			/* offset of protocol header that follows h2 */
5363126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
5364126258Smlaier
5365126258Smlaier			pd2.proto = h2.ip_p;
5366126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
5367126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
5368126258Smlaier			pd2.ip_sum = &h2.ip_sum;
5369126258Smlaier			break;
5370126258Smlaier#endif /* INET */
5371126258Smlaier#ifdef INET6
5372126258Smlaier		case AF_INET6:
5373126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
5374126258Smlaier
5375126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
5376145836Smlaier			    NULL, reason, pd2.af)) {
5377126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5378126258Smlaier				    ("pf: ICMP error message too short "
5379126258Smlaier				    "(ip6)\n"));
5380126258Smlaier				return (PF_DROP);
5381126258Smlaier			}
5382126258Smlaier			pd2.proto = h2_6.ip6_nxt;
5383126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
5384126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
5385126258Smlaier			pd2.ip_sum = NULL;
5386126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
5387126258Smlaier			do {
5388126258Smlaier				switch (pd2.proto) {
5389126258Smlaier				case IPPROTO_FRAGMENT:
5390126258Smlaier					/*
5391126258Smlaier					 * ICMPv6 error messages for
5392126258Smlaier					 * non-first fragments
5393126258Smlaier					 */
5394145836Smlaier					REASON_SET(reason, PFRES_FRAG);
5395126258Smlaier					return (PF_DROP);
5396126258Smlaier				case IPPROTO_AH:
5397126258Smlaier				case IPPROTO_HOPOPTS:
5398126258Smlaier				case IPPROTO_ROUTING:
5399126258Smlaier				case IPPROTO_DSTOPTS: {
5400126258Smlaier					/* get next header and header length */
5401126258Smlaier					struct ip6_ext opt6;
5402126258Smlaier
5403126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5404145836Smlaier					    sizeof(opt6), NULL, reason,
5405145836Smlaier					    pd2.af)) {
5406126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5407126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5408126258Smlaier						return (PF_DROP);
5409126258Smlaier					}
5410126258Smlaier					if (pd2.proto == IPPROTO_AH)
5411126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5412126258Smlaier					else
5413126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5414126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5415126258Smlaier					/* goto the next header */
5416126258Smlaier					break;
5417126258Smlaier				}
5418126258Smlaier				default:
5419126258Smlaier					terminal++;
5420126258Smlaier					break;
5421126258Smlaier				}
5422126258Smlaier			} while (!terminal);
5423126258Smlaier			break;
5424126258Smlaier#endif /* INET6 */
5425171168Smlaier#ifdef __FreeBSD__
5426171168Smlaier		default:
5427171168Smlaier			panic("AF not supported: %d", pd->af);
5428171168Smlaier#endif
5429126258Smlaier		}
5430126258Smlaier
5431126258Smlaier		switch (pd2.proto) {
5432126258Smlaier		case IPPROTO_TCP: {
5433126258Smlaier			struct tcphdr		 th;
5434126258Smlaier			u_int32_t		 seq;
5435126258Smlaier			struct pf_state_peer	*src, *dst;
5436126258Smlaier			u_int8_t		 dws;
5437128129Smlaier			int			 copyback = 0;
5438126258Smlaier
5439126258Smlaier			/*
5440126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5441126258Smlaier			 * expected. Don't access any TCP header fields after
5442126258Smlaier			 * th_seq, an ackskew test is not possible.
5443126258Smlaier			 */
5444145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5445145836Smlaier			    pd2.af)) {
5446126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5447126258Smlaier				    ("pf: ICMP error message too short "
5448126258Smlaier				    "(tcp)\n"));
5449126258Smlaier				return (PF_DROP);
5450126258Smlaier			}
5451126258Smlaier
5452126258Smlaier			key.af = pd2.af;
5453126258Smlaier			key.proto = IPPROTO_TCP;
5454130613Smlaier			if (direction == PF_IN)	{
5455130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5456130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5457130613Smlaier				key.ext.port = th.th_dport;
5458130613Smlaier				key.gwy.port = th.th_sport;
5459130613Smlaier			} else {
5460130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5461130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5462130613Smlaier				key.lan.port = th.th_dport;
5463130613Smlaier				key.ext.port = th.th_sport;
5464130613Smlaier			}
5465126258Smlaier
5466126258Smlaier			STATE_LOOKUP();
5467126258Smlaier
5468126258Smlaier			if (direction == (*state)->direction) {
5469126258Smlaier				src = &(*state)->dst;
5470126258Smlaier				dst = &(*state)->src;
5471126258Smlaier			} else {
5472126258Smlaier				src = &(*state)->src;
5473126258Smlaier				dst = &(*state)->dst;
5474126258Smlaier			}
5475126258Smlaier
5476171929Sdhartmei			if (src->wscale && dst->wscale)
5477126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5478126258Smlaier			else
5479126258Smlaier				dws = 0;
5480126258Smlaier
5481126258Smlaier			/* Demodulate sequence number */
5482126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5483128129Smlaier			if (src->seqdiff) {
5484128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5485126258Smlaier				    htonl(seq), 0);
5486128129Smlaier				copyback = 1;
5487128129Smlaier			}
5488126258Smlaier
5489126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5490126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5491126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5492126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5493126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5494126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5495126258Smlaier					printf(" -> ");
5496126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5497126258Smlaier					printf(" state: ");
5498126258Smlaier					pf_print_state(*state);
5499126258Smlaier					printf(" seq=%u\n", seq);
5500126258Smlaier				}
5501145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5502126258Smlaier				return (PF_DROP);
5503126258Smlaier			}
5504126258Smlaier
5505126258Smlaier			if (STATE_TRANSLATE(*state)) {
5506126258Smlaier				if (direction == PF_IN) {
5507126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5508128129Smlaier					    daddr, &(*state)->lan.addr,
5509126258Smlaier					    (*state)->lan.port, NULL,
5510126258Smlaier					    pd2.ip_sum, icmpsum,
5511126258Smlaier					    pd->ip_sum, 0, pd2.af);
5512126258Smlaier				} else {
5513126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5514126258Smlaier					    saddr, &(*state)->gwy.addr,
5515126258Smlaier					    (*state)->gwy.port, NULL,
5516126258Smlaier					    pd2.ip_sum, icmpsum,
5517126258Smlaier					    pd->ip_sum, 0, pd2.af);
5518126258Smlaier				}
5519128129Smlaier				copyback = 1;
5520128129Smlaier			}
5521128129Smlaier
5522128129Smlaier			if (copyback) {
5523126258Smlaier				switch (pd2.af) {
5524126258Smlaier#ifdef INET
5525126258Smlaier				case AF_INET:
5526126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5527126261Smlaier					    (caddr_t)pd->hdr.icmp);
5528126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5529126261Smlaier					    (caddr_t)&h2);
5530126258Smlaier					break;
5531126258Smlaier#endif /* INET */
5532126258Smlaier#ifdef INET6
5533126258Smlaier				case AF_INET6:
5534126258Smlaier					m_copyback(m, off,
5535126258Smlaier					    sizeof(struct icmp6_hdr),
5536126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5537126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5538126261Smlaier					    (caddr_t)&h2_6);
5539126258Smlaier					break;
5540126258Smlaier#endif /* INET6 */
5541126258Smlaier				}
5542126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5543126258Smlaier			}
5544126258Smlaier
5545126258Smlaier			return (PF_PASS);
5546126258Smlaier			break;
5547126258Smlaier		}
5548126258Smlaier		case IPPROTO_UDP: {
5549126258Smlaier			struct udphdr		uh;
5550126258Smlaier
5551126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5552145836Smlaier			    NULL, reason, pd2.af)) {
5553126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5554126258Smlaier				    ("pf: ICMP error message too short "
5555126258Smlaier				    "(udp)\n"));
5556126258Smlaier				return (PF_DROP);
5557126258Smlaier			}
5558126258Smlaier
5559126258Smlaier			key.af = pd2.af;
5560126258Smlaier			key.proto = IPPROTO_UDP;
5561130613Smlaier			if (direction == PF_IN)	{
5562130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5563130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5564130613Smlaier				key.ext.port = uh.uh_dport;
5565130613Smlaier				key.gwy.port = uh.uh_sport;
5566130613Smlaier			} else {
5567130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5568130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5569130613Smlaier				key.lan.port = uh.uh_dport;
5570130613Smlaier				key.ext.port = uh.uh_sport;
5571130613Smlaier			}
5572126258Smlaier
5573126258Smlaier			STATE_LOOKUP();
5574126258Smlaier
5575126258Smlaier			if (STATE_TRANSLATE(*state)) {
5576126258Smlaier				if (direction == PF_IN) {
5577126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5578126258Smlaier					    daddr, &(*state)->lan.addr,
5579126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5580126258Smlaier					    pd2.ip_sum, icmpsum,
5581126258Smlaier					    pd->ip_sum, 1, pd2.af);
5582126258Smlaier				} else {
5583126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5584126258Smlaier					    saddr, &(*state)->gwy.addr,
5585126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5586126258Smlaier					    pd2.ip_sum, icmpsum,
5587126258Smlaier					    pd->ip_sum, 1, pd2.af);
5588126258Smlaier				}
5589126258Smlaier				switch (pd2.af) {
5590126258Smlaier#ifdef INET
5591126258Smlaier				case AF_INET:
5592126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5593126261Smlaier					    (caddr_t)pd->hdr.icmp);
5594126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5595126261Smlaier					    (caddr_t)&h2);
5596126258Smlaier					break;
5597126258Smlaier#endif /* INET */
5598126258Smlaier#ifdef INET6
5599126258Smlaier				case AF_INET6:
5600126258Smlaier					m_copyback(m, off,
5601126258Smlaier					    sizeof(struct icmp6_hdr),
5602126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5603126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5604126261Smlaier					    (caddr_t)&h2_6);
5605126258Smlaier					break;
5606126258Smlaier#endif /* INET6 */
5607126258Smlaier				}
5608126261Smlaier				m_copyback(m, off2, sizeof(uh),
5609126261Smlaier				    (caddr_t)&uh);
5610126258Smlaier			}
5611126258Smlaier
5612126258Smlaier			return (PF_PASS);
5613126258Smlaier			break;
5614126258Smlaier		}
5615126258Smlaier#ifdef INET
5616126258Smlaier		case IPPROTO_ICMP: {
5617126258Smlaier			struct icmp		iih;
5618126258Smlaier
5619126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5620145836Smlaier			    NULL, reason, pd2.af)) {
5621126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5622126258Smlaier				    ("pf: ICMP error message too short i"
5623126258Smlaier				    "(icmp)\n"));
5624126258Smlaier				return (PF_DROP);
5625126258Smlaier			}
5626126258Smlaier
5627126258Smlaier			key.af = pd2.af;
5628126258Smlaier			key.proto = IPPROTO_ICMP;
5629130613Smlaier			if (direction == PF_IN)	{
5630130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5631130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5632149884Smlaier				key.ext.port = 0;
5633130613Smlaier				key.gwy.port = iih.icmp_id;
5634130613Smlaier			} else {
5635130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5636130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5637130613Smlaier				key.lan.port = iih.icmp_id;
5638149884Smlaier				key.ext.port = 0;
5639130613Smlaier			}
5640126258Smlaier
5641126258Smlaier			STATE_LOOKUP();
5642126258Smlaier
5643126258Smlaier			if (STATE_TRANSLATE(*state)) {
5644126258Smlaier				if (direction == PF_IN) {
5645126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5646126258Smlaier					    daddr, &(*state)->lan.addr,
5647126258Smlaier					    (*state)->lan.port, NULL,
5648126258Smlaier					    pd2.ip_sum, icmpsum,
5649126258Smlaier					    pd->ip_sum, 0, AF_INET);
5650126258Smlaier				} else {
5651126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5652126258Smlaier					    saddr, &(*state)->gwy.addr,
5653126258Smlaier					    (*state)->gwy.port, NULL,
5654126258Smlaier					    pd2.ip_sum, icmpsum,
5655126258Smlaier					    pd->ip_sum, 0, AF_INET);
5656126258Smlaier				}
5657126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5658126261Smlaier				    (caddr_t)pd->hdr.icmp);
5659126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5660126261Smlaier				    (caddr_t)&h2);
5661126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5662126261Smlaier				    (caddr_t)&iih);
5663126258Smlaier			}
5664126258Smlaier
5665126258Smlaier			return (PF_PASS);
5666126258Smlaier			break;
5667126258Smlaier		}
5668126258Smlaier#endif /* INET */
5669126258Smlaier#ifdef INET6
5670126258Smlaier		case IPPROTO_ICMPV6: {
5671126258Smlaier			struct icmp6_hdr	iih;
5672126258Smlaier
5673126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5674145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5675126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5676126258Smlaier				    ("pf: ICMP error message too short "
5677126258Smlaier				    "(icmp6)\n"));
5678126258Smlaier				return (PF_DROP);
5679126258Smlaier			}
5680126258Smlaier
5681126258Smlaier			key.af = pd2.af;
5682126258Smlaier			key.proto = IPPROTO_ICMPV6;
5683130613Smlaier			if (direction == PF_IN)	{
5684130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5685130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5686149884Smlaier				key.ext.port = 0;
5687130613Smlaier				key.gwy.port = iih.icmp6_id;
5688130613Smlaier			} else {
5689130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5690130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5691130613Smlaier				key.lan.port = iih.icmp6_id;
5692149884Smlaier				key.ext.port = 0;
5693130613Smlaier			}
5694126258Smlaier
5695126258Smlaier			STATE_LOOKUP();
5696126258Smlaier
5697126258Smlaier			if (STATE_TRANSLATE(*state)) {
5698126258Smlaier				if (direction == PF_IN) {
5699126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5700126258Smlaier					    daddr, &(*state)->lan.addr,
5701126258Smlaier					    (*state)->lan.port, NULL,
5702126258Smlaier					    pd2.ip_sum, icmpsum,
5703126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5704126258Smlaier				} else {
5705126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5706126258Smlaier					    saddr, &(*state)->gwy.addr,
5707126258Smlaier					    (*state)->gwy.port, NULL,
5708126258Smlaier					    pd2.ip_sum, icmpsum,
5709126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5710126258Smlaier				}
5711126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5712126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5713126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5714126261Smlaier				    (caddr_t)&h2_6);
5715126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5716126261Smlaier				    (caddr_t)&iih);
5717126258Smlaier			}
5718126258Smlaier
5719126258Smlaier			return (PF_PASS);
5720126258Smlaier			break;
5721126258Smlaier		}
5722126258Smlaier#endif /* INET6 */
5723126258Smlaier		default: {
5724126258Smlaier			key.af = pd2.af;
5725126258Smlaier			key.proto = pd2.proto;
5726130613Smlaier			if (direction == PF_IN)	{
5727130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5728130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5729130613Smlaier				key.ext.port = 0;
5730130613Smlaier				key.gwy.port = 0;
5731130613Smlaier			} else {
5732130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5733130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5734130613Smlaier				key.lan.port = 0;
5735130613Smlaier				key.ext.port = 0;
5736130613Smlaier			}
5737126258Smlaier
5738126258Smlaier			STATE_LOOKUP();
5739126258Smlaier
5740126258Smlaier			if (STATE_TRANSLATE(*state)) {
5741126258Smlaier				if (direction == PF_IN) {
5742126258Smlaier					pf_change_icmp(pd2.src, NULL,
5743126258Smlaier					    daddr, &(*state)->lan.addr,
5744126258Smlaier					    0, NULL,
5745126258Smlaier					    pd2.ip_sum, icmpsum,
5746126258Smlaier					    pd->ip_sum, 0, pd2.af);
5747126258Smlaier				} else {
5748126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5749126258Smlaier					    saddr, &(*state)->gwy.addr,
5750126258Smlaier					    0, NULL,
5751126258Smlaier					    pd2.ip_sum, icmpsum,
5752126258Smlaier					    pd->ip_sum, 0, pd2.af);
5753126258Smlaier				}
5754126258Smlaier				switch (pd2.af) {
5755126258Smlaier#ifdef INET
5756126258Smlaier				case AF_INET:
5757126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5758126261Smlaier					    (caddr_t)pd->hdr.icmp);
5759126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5760126261Smlaier					    (caddr_t)&h2);
5761126258Smlaier					break;
5762126258Smlaier#endif /* INET */
5763126258Smlaier#ifdef INET6
5764126258Smlaier				case AF_INET6:
5765126258Smlaier					m_copyback(m, off,
5766126258Smlaier					    sizeof(struct icmp6_hdr),
5767126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5768126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5769126261Smlaier					    (caddr_t)&h2_6);
5770126258Smlaier					break;
5771126258Smlaier#endif /* INET6 */
5772126258Smlaier				}
5773126258Smlaier			}
5774126258Smlaier
5775126258Smlaier			return (PF_PASS);
5776126258Smlaier			break;
5777126258Smlaier		}
5778126258Smlaier		}
5779126258Smlaier	}
5780126258Smlaier}
5781126258Smlaier
5782126258Smlaierint
5783130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5784126258Smlaier    struct pf_pdesc *pd)
5785126258Smlaier{
5786126258Smlaier	struct pf_state_peer	*src, *dst;
5787171168Smlaier	struct pf_state_cmp	 key;
5788126258Smlaier
5789126258Smlaier	key.af = pd->af;
5790126258Smlaier	key.proto = pd->proto;
5791130613Smlaier	if (direction == PF_IN)	{
5792130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5793130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5794130613Smlaier		key.ext.port = 0;
5795130613Smlaier		key.gwy.port = 0;
5796130613Smlaier	} else {
5797130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5798130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5799130613Smlaier		key.lan.port = 0;
5800130613Smlaier		key.ext.port = 0;
5801130613Smlaier	}
5802126258Smlaier
5803126258Smlaier	STATE_LOOKUP();
5804126258Smlaier
5805126258Smlaier	if (direction == (*state)->direction) {
5806126258Smlaier		src = &(*state)->src;
5807126258Smlaier		dst = &(*state)->dst;
5808126258Smlaier	} else {
5809126258Smlaier		src = &(*state)->dst;
5810126258Smlaier		dst = &(*state)->src;
5811126258Smlaier	}
5812126258Smlaier
5813126258Smlaier	/* update states */
5814126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5815126258Smlaier		src->state = PFOTHERS_SINGLE;
5816126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5817126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5818126258Smlaier
5819126258Smlaier	/* update expire time */
5820126261Smlaier	(*state)->expire = time_second;
5821126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5822126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5823126258Smlaier	else
5824126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5825126258Smlaier
5826126258Smlaier	/* translate source/destination address, if necessary */
5827126258Smlaier	if (STATE_TRANSLATE(*state)) {
5828126258Smlaier		if (direction == PF_OUT)
5829126258Smlaier			switch (pd->af) {
5830126258Smlaier#ifdef INET
5831126258Smlaier			case AF_INET:
5832126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5833126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5834126258Smlaier				    0);
5835126258Smlaier				break;
5836126258Smlaier#endif /* INET */
5837126258Smlaier#ifdef INET6
5838126258Smlaier			case AF_INET6:
5839126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5840126258Smlaier				break;
5841126258Smlaier#endif /* INET6 */
5842126258Smlaier			}
5843126258Smlaier		else
5844126258Smlaier			switch (pd->af) {
5845126258Smlaier#ifdef INET
5846126258Smlaier			case AF_INET:
5847126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5848126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5849126258Smlaier				    0);
5850126258Smlaier				break;
5851126258Smlaier#endif /* INET */
5852126258Smlaier#ifdef INET6
5853126258Smlaier			case AF_INET6:
5854126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5855126258Smlaier				break;
5856126258Smlaier#endif /* INET6 */
5857126258Smlaier			}
5858126258Smlaier	}
5859126258Smlaier
5860126258Smlaier	return (PF_PASS);
5861126258Smlaier}
5862126258Smlaier
5863126258Smlaier/*
5864126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5865126258Smlaier * h must be at "ipoff" on the mbuf chain.
5866126258Smlaier */
5867126258Smlaiervoid *
5868126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5869126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5870126258Smlaier{
5871126258Smlaier	switch (af) {
5872126258Smlaier#ifdef INET
5873126258Smlaier	case AF_INET: {
5874126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5875126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5876126258Smlaier
5877126258Smlaier		if (fragoff) {
5878126258Smlaier			if (fragoff >= len)
5879126258Smlaier				ACTION_SET(actionp, PF_PASS);
5880126258Smlaier			else {
5881126258Smlaier				ACTION_SET(actionp, PF_DROP);
5882126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5883126258Smlaier			}
5884126258Smlaier			return (NULL);
5885126258Smlaier		}
5886130613Smlaier		if (m->m_pkthdr.len < off + len ||
5887130613Smlaier		    ntohs(h->ip_len) < off + len) {
5888126258Smlaier			ACTION_SET(actionp, PF_DROP);
5889126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5890126258Smlaier			return (NULL);
5891126258Smlaier		}
5892126258Smlaier		break;
5893126258Smlaier	}
5894126258Smlaier#endif /* INET */
5895126258Smlaier#ifdef INET6
5896126258Smlaier	case AF_INET6: {
5897126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5898126258Smlaier
5899126258Smlaier		if (m->m_pkthdr.len < off + len ||
5900126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5901126258Smlaier		    (unsigned)(off + len)) {
5902126258Smlaier			ACTION_SET(actionp, PF_DROP);
5903126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5904126258Smlaier			return (NULL);
5905126258Smlaier		}
5906126258Smlaier		break;
5907126258Smlaier	}
5908126258Smlaier#endif /* INET6 */
5909126258Smlaier	}
5910126258Smlaier	m_copydata(m, off, len, p);
5911126258Smlaier	return (p);
5912126258Smlaier}
5913126258Smlaier
5914126258Smlaierint
5915171168Smlaierpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
5916126258Smlaier{
5917126258Smlaier	struct sockaddr_in	*dst;
5918171168Smlaier	int			 ret = 1;
5919171168Smlaier	int			 check_mpath;
5920171168Smlaier#ifndef __FreeBSD__
5921171168Smlaier	extern int		 ipmultipath;
5922171168Smlaier#endif
5923145836Smlaier#ifdef INET6
5924171168Smlaier#ifndef __FreeBSD__
5925171168Smlaier	extern int		 ip6_multipath;
5926171168Smlaier#endif
5927145836Smlaier	struct sockaddr_in6	*dst6;
5928145836Smlaier	struct route_in6	 ro;
5929145836Smlaier#else
5930126258Smlaier	struct route		 ro;
5931145836Smlaier#endif
5932171168Smlaier	struct radix_node	*rn;
5933171168Smlaier	struct rtentry		*rt;
5934171168Smlaier	struct ifnet		*ifp;
5935126258Smlaier
5936171168Smlaier	check_mpath = 0;
5937126258Smlaier	bzero(&ro, sizeof(ro));
5938145836Smlaier	switch (af) {
5939145836Smlaier	case AF_INET:
5940145836Smlaier		dst = satosin(&ro.ro_dst);
5941145836Smlaier		dst->sin_family = AF_INET;
5942145836Smlaier		dst->sin_len = sizeof(*dst);
5943145836Smlaier		dst->sin_addr = addr->v4;
5944171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
5945171168Smlaier		if (ipmultipath)
5946171168Smlaier			check_mpath = 1;
5947171168Smlaier#endif
5948145836Smlaier		break;
5949145836Smlaier#ifdef INET6
5950145836Smlaier	case AF_INET6:
5951145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5952145836Smlaier		dst6->sin6_family = AF_INET6;
5953145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5954145836Smlaier		dst6->sin6_addr = addr->v6;
5955171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
5956171168Smlaier		if (ip6_multipath)
5957171168Smlaier			check_mpath = 1;
5958171168Smlaier#endif
5959145836Smlaier		break;
5960145836Smlaier#endif /* INET6 */
5961145836Smlaier	default:
5962145836Smlaier		return (0);
5963145836Smlaier	}
5964145836Smlaier
5965171168Smlaier	/* Skip checks for ipsec interfaces */
5966171168Smlaier	if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
5967171168Smlaier		goto out;
5968171168Smlaier
5969127145Smlaier#ifdef __FreeBSD__
5970178888Sjulian/* XXX MRT not always INET */ /* stick with table 0 though */
5971178888Sjulian	if (af == AF_INET)
5972178888Sjulian		in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0);
5973178888Sjulian	else
5974178888Sjulian		rtalloc_ign((struct route *)&ro, RTF_CLONING);
5975126261Smlaier#else /* ! __FreeBSD__ */
5976145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5977126261Smlaier#endif
5978126258Smlaier
5979126258Smlaier	if (ro.ro_rt != NULL) {
5980171168Smlaier		/* No interface given, this is a no-route check */
5981171168Smlaier		if (kif == NULL)
5982171168Smlaier			goto out;
5983171168Smlaier
5984171168Smlaier		if (kif->pfik_ifp == NULL) {
5985171168Smlaier			ret = 0;
5986171168Smlaier			goto out;
5987171168Smlaier		}
5988171168Smlaier
5989171168Smlaier		/* Perform uRPF check if passed input interface */
5990171168Smlaier		ret = 0;
5991171168Smlaier		rn = (struct radix_node *)ro.ro_rt;
5992171168Smlaier		do {
5993171168Smlaier			rt = (struct rtentry *)rn;
5994171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */
5995171168Smlaier			if (rt->rt_ifp->if_type == IFT_CARP)
5996171168Smlaier				ifp = rt->rt_ifp->if_carpdev;
5997171168Smlaier			else
5998171168Smlaier#endif
5999171168Smlaier				ifp = rt->rt_ifp;
6000171168Smlaier
6001171168Smlaier			if (kif->pfik_ifp == ifp)
6002171168Smlaier				ret = 1;
6003171168Smlaier#ifdef __FreeBSD__ /* MULTIPATH_ROUTING */
6004171168Smlaier			rn = NULL;
6005171168Smlaier#else
6006171168Smlaier			rn = rn_mpath_next(rn);
6007171168Smlaier#endif
6008171168Smlaier		} while (check_mpath == 1 && rn != NULL && ret == 0);
6009171168Smlaier	} else
6010171168Smlaier		ret = 0;
6011171168Smlaierout:
6012171168Smlaier	if (ro.ro_rt != NULL)
6013126258Smlaier		RTFREE(ro.ro_rt);
6014171168Smlaier	return (ret);
6015145836Smlaier}
6016145836Smlaier
6017145836Smlaierint
6018145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
6019145836Smlaier{
6020145836Smlaier	struct sockaddr_in	*dst;
6021145836Smlaier#ifdef INET6
6022145836Smlaier	struct sockaddr_in6	*dst6;
6023145836Smlaier	struct route_in6	 ro;
6024145836Smlaier#else
6025145836Smlaier	struct route		 ro;
6026145836Smlaier#endif
6027145836Smlaier	int			 ret = 0;
6028145836Smlaier
6029145836Smlaier	bzero(&ro, sizeof(ro));
6030145836Smlaier	switch (af) {
6031145836Smlaier	case AF_INET:
6032145836Smlaier		dst = satosin(&ro.ro_dst);
6033145836Smlaier		dst->sin_family = AF_INET;
6034145836Smlaier		dst->sin_len = sizeof(*dst);
6035145836Smlaier		dst->sin_addr = addr->v4;
6036145836Smlaier		break;
6037145836Smlaier#ifdef INET6
6038145836Smlaier	case AF_INET6:
6039145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
6040145836Smlaier		dst6->sin6_family = AF_INET6;
6041145836Smlaier		dst6->sin6_len = sizeof(*dst6);
6042145836Smlaier		dst6->sin6_addr = addr->v6;
6043145836Smlaier		break;
6044145836Smlaier#endif /* INET6 */
6045145836Smlaier	default:
6046145836Smlaier		return (0);
6047145836Smlaier	}
6048145836Smlaier
6049145836Smlaier#ifdef __FreeBSD__
6050145836Smlaier# ifdef RTF_PRCLONING
6051145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
6052145836Smlaier# else /* !RTF_PRCLONING */
6053178888Sjulian	if (af == AF_INET)
6054178888Sjulian		in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0);
6055178888Sjulian	else
6056178888Sjulian		rtalloc_ign((struct route *)&ro, RTF_CLONING);
6057145836Smlaier# endif
6058145836Smlaier#else /* ! __FreeBSD__ */
6059145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
6060145836Smlaier#endif
6061145836Smlaier
6062145836Smlaier	if (ro.ro_rt != NULL) {
6063145836Smlaier#ifdef __FreeBSD__
6064145836Smlaier		/* XXX_IMPORT: later */
6065145836Smlaier#else
6066145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
6067145836Smlaier			ret = 1;
6068145836Smlaier#endif
6069145836Smlaier		RTFREE(ro.ro_rt);
6070145836Smlaier	}
6071145836Smlaier
6072126258Smlaier	return (ret);
6073126258Smlaier}
6074126258Smlaier
6075126258Smlaier#ifdef INET
6076126261Smlaier
6077126258Smlaiervoid
6078126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6079171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6080126258Smlaier{
6081126258Smlaier	struct mbuf		*m0, *m1;
6082126258Smlaier	struct route		 iproute;
6083171168Smlaier	struct route		*ro = NULL;
6084126258Smlaier	struct sockaddr_in	*dst;
6085126258Smlaier	struct ip		*ip;
6086126258Smlaier	struct ifnet		*ifp = NULL;
6087126258Smlaier	struct pf_addr		 naddr;
6088130613Smlaier	struct pf_src_node	*sn = NULL;
6089126258Smlaier	int			 error = 0;
6090127145Smlaier#ifdef __FreeBSD__
6091126261Smlaier	int sw_csum;
6092126261Smlaier#endif
6093171168Smlaier#ifdef IPSEC
6094171168Smlaier	struct m_tag		*mtag;
6095171168Smlaier#endif /* IPSEC */
6096126258Smlaier
6097126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6098126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6099126258Smlaier		panic("pf_route: invalid parameters");
6100126258Smlaier
6101171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6102171168Smlaier		m0 = *m;
6103171168Smlaier		*m = NULL;
6104171168Smlaier		goto bad;
6105132303Smlaier	}
6106132303Smlaier
6107126258Smlaier	if (r->rt == PF_DUPTO) {
6108127145Smlaier#ifdef __FreeBSD__
6109132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6110126261Smlaier#else
6111132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6112126261Smlaier#endif
6113126258Smlaier			return;
6114126258Smlaier	} else {
6115126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6116126258Smlaier			return;
6117126258Smlaier		m0 = *m;
6118126258Smlaier	}
6119126258Smlaier
6120145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
6121145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6122145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6123145836Smlaier		goto bad;
6124145836Smlaier	}
6125145836Smlaier
6126126258Smlaier	ip = mtod(m0, struct ip *);
6127126258Smlaier
6128126258Smlaier	ro = &iproute;
6129126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6130126258Smlaier	dst = satosin(&ro->ro_dst);
6131126258Smlaier	dst->sin_family = AF_INET;
6132126258Smlaier	dst->sin_len = sizeof(*dst);
6133126258Smlaier	dst->sin_addr = ip->ip_dst;
6134126258Smlaier
6135126258Smlaier	if (r->rt == PF_FASTROUTE) {
6136178888Sjulian		in_rtalloc(ro, 0);
6137126258Smlaier		if (ro->ro_rt == 0) {
6138126258Smlaier			ipstat.ips_noroute++;
6139126258Smlaier			goto bad;
6140126258Smlaier		}
6141126258Smlaier
6142126258Smlaier		ifp = ro->ro_rt->rt_ifp;
6143126258Smlaier		ro->ro_rt->rt_use++;
6144126258Smlaier
6145126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
6146126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
6147126258Smlaier	} else {
6148145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
6149145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6150145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
6151145836Smlaier			goto bad;
6152145836Smlaier		}
6153126258Smlaier		if (s == NULL) {
6154130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
6155130613Smlaier			    &naddr, NULL, &sn);
6156126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
6157126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
6158130613Smlaier			ifp = r->rpool.cur->kif ?
6159130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
6160126258Smlaier		} else {
6161126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
6162126258Smlaier				dst->sin_addr.s_addr =
6163126258Smlaier				    s->rt_addr.v4.s_addr;
6164130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6165126258Smlaier		}
6166126258Smlaier	}
6167126258Smlaier	if (ifp == NULL)
6168126258Smlaier		goto bad;
6169126258Smlaier
6170130639Smlaier	if (oifp != ifp) {
6171127145Smlaier#ifdef __FreeBSD__
6172126261Smlaier		PF_UNLOCK();
6173145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6174126261Smlaier			PF_LOCK();
6175126261Smlaier			goto bad;
6176126261Smlaier		} else if (m0 == NULL) {
6177126261Smlaier			PF_LOCK();
6178126261Smlaier			goto done;
6179126261Smlaier		}
6180126261Smlaier		PF_LOCK();
6181126261Smlaier#else
6182145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6183126258Smlaier			goto bad;
6184126258Smlaier		else if (m0 == NULL)
6185126258Smlaier			goto done;
6186126261Smlaier#endif
6187145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
6188145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6189145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6190145836Smlaier			goto bad;
6191145836Smlaier		}
6192126258Smlaier		ip = mtod(m0, struct ip *);
6193126258Smlaier	}
6194126258Smlaier
6195127145Smlaier#ifdef __FreeBSD__
6196126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
6197126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
6198126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
6199126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
6200126261Smlaier		/*
6201126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
6202126261Smlaier		 */
6203126261Smlaier		NTOHS(ip->ip_len);
6204126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
6205126261Smlaier		in_delayed_cksum(m0);
6206126261Smlaier		HTONS(ip->ip_len);
6207126261Smlaier		HTONS(ip->ip_off);
6208126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
6209126261Smlaier	}
6210126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
6211126261Smlaier
6212126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
6213126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
6214126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
6215126261Smlaier		/*
6216126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
6217126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
6218126261Smlaier		 */
6219126261Smlaier		ip->ip_sum = 0;
6220126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
6221126261Smlaier			/* From KAME */
6222126261Smlaier			if (ip->ip_v == IPVERSION &&
6223126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
6224126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
6225126261Smlaier			} else {
6226126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6227126261Smlaier			}
6228126261Smlaier		}
6229126261Smlaier		PF_UNLOCK();
6230126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
6231126261Smlaier		PF_LOCK();
6232126261Smlaier		goto done;
6233126261Smlaier	}
6234126261Smlaier
6235126261Smlaier#else
6236126258Smlaier	/* Copied from ip_output. */
6237130613Smlaier#ifdef IPSEC
6238130613Smlaier	/*
6239130613Smlaier	 * If deferred crypto processing is needed, check that the
6240130613Smlaier	 * interface supports it.
6241130613Smlaier	 */
6242130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
6243130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
6244130613Smlaier		/* Notify IPsec to do its own crypto. */
6245130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
6246130613Smlaier		goto bad;
6247130613Smlaier	}
6248130613Smlaier#endif /* IPSEC */
6249130613Smlaier
6250130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
6251171168Smlaier	if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
6252130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
6253130613Smlaier		    ifp->if_bridge != NULL) {
6254130613Smlaier			in_delayed_cksum(m0);
6255171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
6256130613Smlaier		}
6257171168Smlaier	} else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
6258130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
6259130613Smlaier		    ifp->if_bridge != NULL) {
6260130613Smlaier			in_delayed_cksum(m0);
6261171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
6262130613Smlaier		}
6263130613Smlaier	}
6264130613Smlaier
6265126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
6266126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
6267126258Smlaier		    ifp->if_bridge == NULL) {
6268171168Smlaier			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
6269126258Smlaier			ipstat.ips_outhwcsum++;
6270126258Smlaier		} else {
6271126258Smlaier			ip->ip_sum = 0;
6272126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6273126258Smlaier		}
6274126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
6275171168Smlaier		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
6276126258Smlaier			tcpstat.tcps_outhwcsum++;
6277171168Smlaier		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
6278126258Smlaier			udpstat.udps_outhwcsum++;
6279126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
6280126258Smlaier		goto done;
6281126258Smlaier	}
6282126261Smlaier#endif
6283126258Smlaier	/*
6284126258Smlaier	 * Too large for interface; fragment if possible.
6285126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
6286126258Smlaier	 */
6287126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
6288126258Smlaier		ipstat.ips_cantfrag++;
6289126258Smlaier		if (r->rt != PF_DUPTO) {
6290127145Smlaier#ifdef __FreeBSD__
6291126261Smlaier			/* icmp_error() expects host byte ordering */
6292126261Smlaier			NTOHS(ip->ip_len);
6293126261Smlaier			NTOHS(ip->ip_off);
6294126261Smlaier			PF_UNLOCK();
6295126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6296145886Smlaier			    ifp->if_mtu);
6297145874Smlaier			PF_LOCK();
6298145874Smlaier#else
6299145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6300171168Smlaier			    ifp->if_mtu);
6301126261Smlaier#endif
6302126258Smlaier			goto done;
6303126258Smlaier		} else
6304126258Smlaier			goto bad;
6305126258Smlaier	}
6306126258Smlaier
6307126258Smlaier	m1 = m0;
6308127145Smlaier#ifdef __FreeBSD__
6309126261Smlaier	/*
6310126261Smlaier	 * XXX: is cheaper + less error prone than own function
6311126261Smlaier	 */
6312126261Smlaier	NTOHS(ip->ip_len);
6313126261Smlaier	NTOHS(ip->ip_off);
6314126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
6315126261Smlaier#else
6316126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
6317126261Smlaier#endif
6318127531Smlaier	if (error) {
6319127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
6320127531Smlaier		m0 = NULL;
6321126261Smlaier#endif
6322126258Smlaier		goto bad;
6323127531Smlaier	}
6324126258Smlaier
6325126258Smlaier	for (m0 = m1; m0; m0 = m1) {
6326126258Smlaier		m1 = m0->m_nextpkt;
6327126258Smlaier		m0->m_nextpkt = 0;
6328127145Smlaier#ifdef __FreeBSD__
6329126261Smlaier		if (error == 0) {
6330126261Smlaier			PF_UNLOCK();
6331126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6332126261Smlaier			    NULL);
6333126261Smlaier			PF_LOCK();
6334126261Smlaier		} else
6335126261Smlaier#else
6336126258Smlaier		if (error == 0)
6337126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6338126258Smlaier			    NULL);
6339126258Smlaier		else
6340126261Smlaier#endif
6341126258Smlaier			m_freem(m0);
6342126258Smlaier	}
6343126258Smlaier
6344126258Smlaier	if (error == 0)
6345126258Smlaier		ipstat.ips_fragmented++;
6346126258Smlaier
6347126258Smlaierdone:
6348126258Smlaier	if (r->rt != PF_DUPTO)
6349126258Smlaier		*m = NULL;
6350126258Smlaier	if (ro == &iproute && ro->ro_rt)
6351126258Smlaier		RTFREE(ro->ro_rt);
6352126258Smlaier	return;
6353126258Smlaier
6354126258Smlaierbad:
6355126258Smlaier	m_freem(m0);
6356126258Smlaier	goto done;
6357126258Smlaier}
6358126258Smlaier#endif /* INET */
6359126258Smlaier
6360126258Smlaier#ifdef INET6
6361126258Smlaiervoid
6362126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6363171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6364126258Smlaier{
6365126258Smlaier	struct mbuf		*m0;
6366126258Smlaier	struct route_in6	 ip6route;
6367126258Smlaier	struct route_in6	*ro;
6368126258Smlaier	struct sockaddr_in6	*dst;
6369126258Smlaier	struct ip6_hdr		*ip6;
6370126258Smlaier	struct ifnet		*ifp = NULL;
6371126258Smlaier	struct pf_addr		 naddr;
6372130613Smlaier	struct pf_src_node	*sn = NULL;
6373126258Smlaier	int			 error = 0;
6374126258Smlaier
6375126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6376126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6377126258Smlaier		panic("pf_route6: invalid parameters");
6378126258Smlaier
6379171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6380171168Smlaier		m0 = *m;
6381171168Smlaier		*m = NULL;
6382171168Smlaier		goto bad;
6383132303Smlaier	}
6384132303Smlaier
6385126258Smlaier	if (r->rt == PF_DUPTO) {
6386127145Smlaier#ifdef __FreeBSD__
6387132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6388126261Smlaier#else
6389132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6390126261Smlaier#endif
6391126258Smlaier			return;
6392126258Smlaier	} else {
6393126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6394126258Smlaier			return;
6395126258Smlaier		m0 = *m;
6396126258Smlaier	}
6397126258Smlaier
6398145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
6399145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6400145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6401145836Smlaier		goto bad;
6402145836Smlaier	}
6403126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
6404126258Smlaier
6405126258Smlaier	ro = &ip6route;
6406126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6407126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
6408126258Smlaier	dst->sin6_family = AF_INET6;
6409126258Smlaier	dst->sin6_len = sizeof(*dst);
6410126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
6411126258Smlaier
6412171168Smlaier	/* Cheat. XXX why only in the v6 case??? */
6413126258Smlaier	if (r->rt == PF_FASTROUTE) {
6414127145Smlaier#ifdef __FreeBSD__
6415132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
6416126261Smlaier		PF_UNLOCK();
6417126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6418126261Smlaier		PF_LOCK();
6419126261Smlaier#else
6420132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
6421132280Smlaier		if (mtag == NULL)
6422132280Smlaier			goto bad;
6423132280Smlaier		m_tag_prepend(m0, mtag);
6424171168Smlaier		pd->pf_mtag->flags |= PF_TAG_GENERATED;
6425126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
6426126261Smlaier#endif
6427126258Smlaier		return;
6428126258Smlaier	}
6429126258Smlaier
6430145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6431145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6432145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6433145836Smlaier		goto bad;
6434145836Smlaier	}
6435126258Smlaier	if (s == NULL) {
6436130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6437130613Smlaier		    &naddr, NULL, &sn);
6438126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6439126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6440126258Smlaier			    &naddr, AF_INET6);
6441130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6442126258Smlaier	} else {
6443126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6444126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6445126258Smlaier			    &s->rt_addr, AF_INET6);
6446130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6447126258Smlaier	}
6448126258Smlaier	if (ifp == NULL)
6449126258Smlaier		goto bad;
6450126258Smlaier
6451126258Smlaier	if (oifp != ifp) {
6452127145Smlaier#ifdef __FreeBSD__
6453132303Smlaier		PF_UNLOCK();
6454145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6455126261Smlaier			PF_LOCK();
6456132303Smlaier			goto bad;
6457132303Smlaier		} else if (m0 == NULL) {
6458132303Smlaier			PF_LOCK();
6459132303Smlaier			goto done;
6460132303Smlaier		}
6461132303Smlaier		PF_LOCK();
6462126261Smlaier#else
6463145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6464132303Smlaier			goto bad;
6465132303Smlaier		else if (m0 == NULL)
6466132303Smlaier			goto done;
6467126261Smlaier#endif
6468145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6469145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6470145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6471145836Smlaier			goto bad;
6472145836Smlaier		}
6473132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6474126258Smlaier	}
6475126258Smlaier
6476126258Smlaier	/*
6477126258Smlaier	 * If the packet is too large for the outgoing interface,
6478126258Smlaier	 * send back an icmp6 error.
6479126258Smlaier	 */
6480171168Smlaier	if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
6481126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6482126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6483127145Smlaier#ifdef __FreeBSD__
6484126261Smlaier		PF_UNLOCK();
6485126261Smlaier#endif
6486126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
6487127145Smlaier#ifdef __FreeBSD__
6488126261Smlaier		PF_LOCK();
6489126261Smlaier#endif
6490126258Smlaier	} else {
6491126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6492127145Smlaier#ifdef __FreeBSD__
6493126261Smlaier		if (r->rt != PF_DUPTO) {
6494126261Smlaier			PF_UNLOCK();
6495126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6496126261Smlaier			PF_LOCK();
6497126261Smlaier		 } else
6498126261Smlaier#else
6499126258Smlaier		if (r->rt != PF_DUPTO)
6500126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6501126258Smlaier		else
6502126261Smlaier#endif
6503126258Smlaier			goto bad;
6504126258Smlaier	}
6505126258Smlaier
6506126258Smlaierdone:
6507126258Smlaier	if (r->rt != PF_DUPTO)
6508126258Smlaier		*m = NULL;
6509126258Smlaier	return;
6510126258Smlaier
6511126258Smlaierbad:
6512126258Smlaier	m_freem(m0);
6513126258Smlaier	goto done;
6514126258Smlaier}
6515126258Smlaier#endif /* INET6 */
6516126258Smlaier
6517126258Smlaier
6518127145Smlaier#ifdef __FreeBSD__
6519126258Smlaier/*
6520132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6521137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6522132566Smlaier *   ti(4), txp(4), xl(4)
6523132566Smlaier *
6524132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6525132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6526132566Smlaier *   csum_data
6527132566Smlaier * CSUM_DATA_VALID :
6528132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6529132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6530132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6531132566Smlaier *
6532132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6533132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6534132566Smlaier * TCP/UDP layer.
6535132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6536126261Smlaier */
6537126261Smlaierint
6538126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6539126261Smlaier{
6540126261Smlaier	u_int16_t sum = 0;
6541126261Smlaier	int hw_assist = 0;
6542126261Smlaier	struct ip *ip;
6543126261Smlaier
6544126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6545126261Smlaier		return (1);
6546126261Smlaier	if (m->m_pkthdr.len < off + len)
6547126261Smlaier		return (1);
6548126261Smlaier
6549126261Smlaier	switch (p) {
6550126261Smlaier	case IPPROTO_TCP:
6551126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6552126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6553126261Smlaier				sum = m->m_pkthdr.csum_data;
6554126261Smlaier			} else {
6555126261Smlaier				ip = mtod(m, struct ip *);
6556126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6557135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6558135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6559126261Smlaier			}
6560126261Smlaier			sum ^= 0xffff;
6561126261Smlaier			++hw_assist;
6562126261Smlaier		}
6563126261Smlaier		break;
6564126261Smlaier	case IPPROTO_UDP:
6565126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6566126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6567126261Smlaier				sum = m->m_pkthdr.csum_data;
6568126261Smlaier			} else {
6569126261Smlaier				ip = mtod(m, struct ip *);
6570126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6571126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6572126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6573126261Smlaier			}
6574126261Smlaier			sum ^= 0xffff;
6575126261Smlaier			++hw_assist;
6576126261Smlaier                }
6577126261Smlaier		break;
6578126261Smlaier	case IPPROTO_ICMP:
6579126261Smlaier#ifdef INET6
6580126261Smlaier	case IPPROTO_ICMPV6:
6581126261Smlaier#endif /* INET6 */
6582126261Smlaier		break;
6583126261Smlaier	default:
6584126261Smlaier		return (1);
6585126261Smlaier	}
6586126261Smlaier
6587126261Smlaier	if (!hw_assist) {
6588126261Smlaier		switch (af) {
6589126261Smlaier		case AF_INET:
6590126261Smlaier			if (p == IPPROTO_ICMP) {
6591126261Smlaier				if (m->m_len < off)
6592126261Smlaier					return (1);
6593126261Smlaier				m->m_data += off;
6594126261Smlaier				m->m_len -= off;
6595126261Smlaier				sum = in_cksum(m, len);
6596126261Smlaier				m->m_data -= off;
6597126261Smlaier				m->m_len += off;
6598126261Smlaier			} else {
6599126261Smlaier				if (m->m_len < sizeof(struct ip))
6600126261Smlaier					return (1);
6601126261Smlaier				sum = in4_cksum(m, p, off, len);
6602126261Smlaier			}
6603126261Smlaier			break;
6604126261Smlaier#ifdef INET6
6605126261Smlaier		case AF_INET6:
6606126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6607126261Smlaier				return (1);
6608126261Smlaier			sum = in6_cksum(m, p, off, len);
6609126261Smlaier			break;
6610126261Smlaier#endif /* INET6 */
6611126261Smlaier		default:
6612126261Smlaier			return (1);
6613126261Smlaier		}
6614126261Smlaier	}
6615126261Smlaier	if (sum) {
6616126261Smlaier		switch (p) {
6617126261Smlaier		case IPPROTO_TCP:
6618126261Smlaier			tcpstat.tcps_rcvbadsum++;
6619126261Smlaier			break;
6620126261Smlaier		case IPPROTO_UDP:
6621126261Smlaier			udpstat.udps_badsum++;
6622126261Smlaier			break;
6623126261Smlaier		case IPPROTO_ICMP:
6624126261Smlaier			icmpstat.icps_checksum++;
6625126261Smlaier			break;
6626126261Smlaier#ifdef INET6
6627126261Smlaier		case IPPROTO_ICMPV6:
6628126261Smlaier			icmp6stat.icp6s_checksum++;
6629126261Smlaier			break;
6630126261Smlaier#endif /* INET6 */
6631126261Smlaier		}
6632126261Smlaier		return (1);
6633132566Smlaier	} else {
6634132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6635132566Smlaier			m->m_pkthdr.csum_flags |=
6636132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6637132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6638132566Smlaier		}
6639126261Smlaier	}
6640126261Smlaier	return (0);
6641126261Smlaier}
6642171168Smlaier#else /* !__FreeBSD__ */
6643126261Smlaier/*
6644126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6645126258Smlaier *   off is the offset where the protocol header starts
6646126258Smlaier *   len is the total length of protocol header plus payload
6647126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6648126258Smlaier */
6649126258Smlaierint
6650130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6651130613Smlaier    sa_family_t af)
6652126258Smlaier{
6653126258Smlaier	u_int16_t flag_ok, flag_bad;
6654126258Smlaier	u_int16_t sum;
6655126258Smlaier
6656126258Smlaier	switch (p) {
6657126258Smlaier	case IPPROTO_TCP:
6658126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6659126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6660126258Smlaier		break;
6661126258Smlaier	case IPPROTO_UDP:
6662126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6663126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6664126258Smlaier		break;
6665126258Smlaier	case IPPROTO_ICMP:
6666126258Smlaier#ifdef INET6
6667126258Smlaier	case IPPROTO_ICMPV6:
6668126258Smlaier#endif /* INET6 */
6669126258Smlaier		flag_ok = flag_bad = 0;
6670126258Smlaier		break;
6671126258Smlaier	default:
6672126258Smlaier		return (1);
6673126258Smlaier	}
6674171168Smlaier	if (m->m_pkthdr.csum_flags & flag_ok)
6675126258Smlaier		return (0);
6676171168Smlaier	if (m->m_pkthdr.csum_flags & flag_bad)
6677126258Smlaier		return (1);
6678126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6679126258Smlaier		return (1);
6680126258Smlaier	if (m->m_pkthdr.len < off + len)
6681126258Smlaier		return (1);
6682145836Smlaier	switch (af) {
6683145836Smlaier#ifdef INET
6684126258Smlaier	case AF_INET:
6685126258Smlaier		if (p == IPPROTO_ICMP) {
6686126258Smlaier			if (m->m_len < off)
6687126258Smlaier				return (1);
6688126258Smlaier			m->m_data += off;
6689126258Smlaier			m->m_len -= off;
6690126258Smlaier			sum = in_cksum(m, len);
6691126258Smlaier			m->m_data -= off;
6692126258Smlaier			m->m_len += off;
6693126258Smlaier		} else {
6694126258Smlaier			if (m->m_len < sizeof(struct ip))
6695126258Smlaier				return (1);
6696126258Smlaier			sum = in4_cksum(m, p, off, len);
6697126258Smlaier		}
6698126258Smlaier		break;
6699145836Smlaier#endif /* INET */
6700126258Smlaier#ifdef INET6
6701126258Smlaier	case AF_INET6:
6702126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6703126258Smlaier			return (1);
6704126258Smlaier		sum = in6_cksum(m, p, off, len);
6705126258Smlaier		break;
6706126258Smlaier#endif /* INET6 */
6707126258Smlaier	default:
6708126258Smlaier		return (1);
6709126258Smlaier	}
6710126258Smlaier	if (sum) {
6711171168Smlaier		m->m_pkthdr.csum_flags |= flag_bad;
6712126258Smlaier		switch (p) {
6713126258Smlaier		case IPPROTO_TCP:
6714126258Smlaier			tcpstat.tcps_rcvbadsum++;
6715126258Smlaier			break;
6716126258Smlaier		case IPPROTO_UDP:
6717126258Smlaier			udpstat.udps_badsum++;
6718126258Smlaier			break;
6719126258Smlaier		case IPPROTO_ICMP:
6720126258Smlaier			icmpstat.icps_checksum++;
6721126258Smlaier			break;
6722126258Smlaier#ifdef INET6
6723126258Smlaier		case IPPROTO_ICMPV6:
6724126258Smlaier			icmp6stat.icp6s_checksum++;
6725126258Smlaier			break;
6726126258Smlaier#endif /* INET6 */
6727126258Smlaier		}
6728126258Smlaier		return (1);
6729126258Smlaier	}
6730171168Smlaier	m->m_pkthdr.csum_flags |= flag_ok;
6731126258Smlaier	return (0);
6732126258Smlaier}
6733171168Smlaier#endif /* __FreeBSD__ */
6734126258Smlaier
6735126258Smlaier#ifdef INET
6736126258Smlaierint
6737135920Smlaier#ifdef __FreeBSD__
6738145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6739145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6740135920Smlaier#else
6741145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6742145836Smlaier    struct ether_header *eh)
6743135920Smlaier#endif
6744126258Smlaier{
6745130613Smlaier	struct pfi_kif		*kif;
6746130613Smlaier	u_short			 action, reason = 0, log = 0;
6747130613Smlaier	struct mbuf		*m = *m0;
6748130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6749130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6750130613Smlaier	struct pf_state		*s = NULL;
6751130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6752130613Smlaier	struct pf_pdesc		 pd;
6753130613Smlaier	int			 off, dirndx, pqid = 0;
6754126258Smlaier
6755127145Smlaier#ifdef __FreeBSD__
6756126261Smlaier	PF_LOCK();
6757126261Smlaier#endif
6758171168Smlaier	if (!pf_status.running)
6759127145Smlaier#ifdef __FreeBSD__
6760171168Smlaier	{
6761126261Smlaier		PF_UNLOCK();
6762126261Smlaier#endif
6763171168Smlaier		return (PF_PASS);
6764171168Smlaier#ifdef __FreeBSD__
6765126261Smlaier	}
6766171168Smlaier#endif
6767126258Smlaier
6768171168Smlaier	memset(&pd, 0, sizeof(pd));
6769171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
6770145836Smlaier#ifdef __FreeBSD__
6771171168Smlaier		PF_UNLOCK();
6772171168Smlaier#endif
6773171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6774171168Smlaier		    ("pf_test: pf_get_mtag returned NULL\n"));
6775171168Smlaier		return (PF_DROP);
6776171168Smlaier	}
6777171168Smlaier#ifdef __FreeBSD__
6778171168Smlaier	if (m->m_flags & M_SKIP_FIREWALL) {
6779171168Smlaier		PF_UNLOCK();
6780171168Smlaier		return (PF_PASS);
6781171168Smlaier	}
6782171168Smlaier#else
6783171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
6784171168Smlaier		return (PF_PASS);
6785171168Smlaier#endif
6786171168Smlaier
6787171168Smlaier#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
6794171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
6795130613Smlaier	if (kif == NULL) {
6796130613Smlaier#ifdef __FreeBSD__
6797130613Smlaier		PF_UNLOCK();
6798130613Smlaier#endif
6799145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6800145836Smlaier		    ("pf_test: 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)
6815126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6816145836Smlaier#endif /* DIAGNOSTIC */
6817145836Smlaier#endif /* __FreeBSD__ */
6818126258Smlaier
6819126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6820126258Smlaier		action = PF_DROP;
6821126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6822126258Smlaier		log = 1;
6823126258Smlaier		goto done;
6824126258Smlaier	}
6825126258Smlaier
6826126258Smlaier	/* We do IP header normalization and packet reassembly here */
6827145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6828126258Smlaier		action = PF_DROP;
6829126258Smlaier		goto done;
6830126258Smlaier	}
6831126258Smlaier	m = *m0;
6832126258Smlaier	h = mtod(m, struct ip *);
6833126258Smlaier
6834126258Smlaier	off = h->ip_hl << 2;
6835126258Smlaier	if (off < (int)sizeof(*h)) {
6836126258Smlaier		action = PF_DROP;
6837126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6838126258Smlaier		log = 1;
6839126258Smlaier		goto done;
6840126258Smlaier	}
6841126258Smlaier
6842126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6843126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6844130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6845126258Smlaier	pd.ip_sum = &h->ip_sum;
6846126258Smlaier	pd.proto = h->ip_p;
6847126258Smlaier	pd.af = AF_INET;
6848126258Smlaier	pd.tos = h->ip_tos;
6849126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6850145836Smlaier	pd.eh = eh;
6851126258Smlaier
6852126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6853126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6854130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6855126258Smlaier		    &pd, &a, &ruleset);
6856126258Smlaier		goto done;
6857126258Smlaier	}
6858126258Smlaier
6859126258Smlaier	switch (h->ip_p) {
6860126258Smlaier
6861126258Smlaier	case IPPROTO_TCP: {
6862126258Smlaier		struct tcphdr	th;
6863126258Smlaier
6864126258Smlaier		pd.hdr.tcp = &th;
6865126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6866126258Smlaier		    &action, &reason, AF_INET)) {
6867126258Smlaier			log = action != PF_PASS;
6868126258Smlaier			goto done;
6869126258Smlaier		}
6870126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6871126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6872171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6873126258Smlaier			action = PF_DROP;
6874126258Smlaier			goto done;
6875126258Smlaier		}
6876126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6877126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6878126258Smlaier			pqid = 1;
6879130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6880126258Smlaier		if (action == PF_DROP)
6881130613Smlaier			goto done;
6882130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6883126258Smlaier		    &reason);
6884126258Smlaier		if (action == PF_PASS) {
6885130613Smlaier#if NPFSYNC
6886130613Smlaier			pfsync_update_state(s);
6887145836Smlaier#endif /* NPFSYNC */
6888126258Smlaier			r = s->rule.ptr;
6889130613Smlaier			a = s->anchor.ptr;
6890126258Smlaier			log = s->log;
6891126258Smlaier		} else if (s == NULL)
6892135920Smlaier#ifdef __FreeBSD__
6893130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6894145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6895135920Smlaier#else
6896135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6897145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6898135920Smlaier#endif
6899126258Smlaier		break;
6900126258Smlaier	}
6901126258Smlaier
6902126258Smlaier	case IPPROTO_UDP: {
6903126258Smlaier		struct udphdr	uh;
6904126258Smlaier
6905126258Smlaier		pd.hdr.udp = &uh;
6906126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6907126258Smlaier		    &action, &reason, AF_INET)) {
6908126258Smlaier			log = action != PF_PASS;
6909126258Smlaier			goto done;
6910126258Smlaier		}
6911126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6912126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6913126258Smlaier			action = PF_DROP;
6914171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6915126258Smlaier			goto done;
6916126258Smlaier		}
6917130613Smlaier		if (uh.uh_dport == 0 ||
6918130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6919130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6920130613Smlaier			action = PF_DROP;
6921171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
6922130613Smlaier			goto done;
6923130613Smlaier		}
6924130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6925126258Smlaier		if (action == PF_PASS) {
6926130613Smlaier#if NPFSYNC
6927130613Smlaier			pfsync_update_state(s);
6928145836Smlaier#endif /* NPFSYNC */
6929126258Smlaier			r = s->rule.ptr;
6930126258Smlaier			a = s->anchor.ptr;
6931126258Smlaier			log = s->log;
6932126258Smlaier		} else if (s == NULL)
6933135920Smlaier#ifdef __FreeBSD__
6934130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6935145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6936135920Smlaier#else
6937135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6938145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6939135920Smlaier#endif
6940126258Smlaier		break;
6941126258Smlaier	}
6942126258Smlaier
6943126258Smlaier	case IPPROTO_ICMP: {
6944126258Smlaier		struct icmp	ih;
6945126258Smlaier
6946126258Smlaier		pd.hdr.icmp = &ih;
6947126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6948126258Smlaier		    &action, &reason, AF_INET)) {
6949126258Smlaier			log = action != PF_PASS;
6950126258Smlaier			goto done;
6951126258Smlaier		}
6952126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6953126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6954126258Smlaier			action = PF_DROP;
6955171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6956126258Smlaier			goto done;
6957126258Smlaier		}
6958145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6959145836Smlaier		    &reason);
6960126258Smlaier		if (action == PF_PASS) {
6961130613Smlaier#if NPFSYNC
6962130613Smlaier			pfsync_update_state(s);
6963145836Smlaier#endif /* NPFSYNC */
6964126258Smlaier			r = s->rule.ptr;
6965126258Smlaier			a = s->anchor.ptr;
6966126258Smlaier			log = s->log;
6967126258Smlaier		} else if (s == NULL)
6968145836Smlaier#ifdef __FreeBSD__
6969130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6970145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6971145836Smlaier#else
6972145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6973145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6974145836Smlaier#endif
6975126258Smlaier		break;
6976126258Smlaier	}
6977126258Smlaier
6978126258Smlaier	default:
6979130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6980126258Smlaier		if (action == PF_PASS) {
6981130613Smlaier#if NPFSYNC
6982130613Smlaier			pfsync_update_state(s);
6983145836Smlaier#endif /* NPFSYNC */
6984126258Smlaier			r = s->rule.ptr;
6985126258Smlaier			a = s->anchor.ptr;
6986126258Smlaier			log = s->log;
6987126258Smlaier		} else if (s == NULL)
6988145836Smlaier#ifdef __FreeBSD__
6989130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6990145836Smlaier			    &pd, &a, &ruleset, NULL);
6991145836Smlaier#else
6992145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6993145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
6994145836Smlaier#endif
6995126258Smlaier		break;
6996126258Smlaier	}
6997126258Smlaier
6998126258Smlaierdone:
6999126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
7000126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
7001126258Smlaier		action = PF_DROP;
7002145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
7003126258Smlaier		log = 1;
7004126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
7005126258Smlaier		    ("pf: dropping packet with ip options\n"));
7006126258Smlaier	}
7007126258Smlaier
7008171168Smlaier	if ((s && s->tag) || r->rtableid)
7009171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7010145836Smlaier
7011126258Smlaier#ifdef ALTQ
7012126258Smlaier	if (action == PF_PASS && r->qid) {
7013171168Smlaier		if (pqid || (pd.tos & IPTOS_LOWDELAY))
7014171168Smlaier			pd.pf_mtag->qid = r->pqid;
7015171168Smlaier		else
7016171168Smlaier			pd.pf_mtag->qid = r->qid;
7017171168Smlaier		/* add hints for ecn */
7018171168Smlaier		pd.pf_mtag->af = AF_INET;
7019171168Smlaier		pd.pf_mtag->hdr = h;
7020126258Smlaier	}
7021145836Smlaier#endif /* ALTQ */
7022126258Smlaier
7023130613Smlaier	/*
7024130613Smlaier	 * connections redirected to loopback should not match sockets
7025130613Smlaier	 * bound specifically to loopback due to security implications,
7026130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
7027130613Smlaier	 */
7028130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7029130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7030130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7031130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7032171168Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
7033171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7034171168Smlaier
7035171168Smlaier	if (log) {
7036171168Smlaier		struct pf_rule *lr;
7037171168Smlaier
7038171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7039171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7040171168Smlaier			lr = s->nat_rule.ptr;
7041171168Smlaier		else
7042171168Smlaier			lr = r;
7043171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
7044171168Smlaier		    &pd);
7045130613Smlaier	}
7046130613Smlaier
7047130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7048130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
7049130613Smlaier
7050130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7051171168Smlaier		dirndx = (dir == PF_OUT);
7052171168Smlaier		r->packets[dirndx]++;
7053171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7054130613Smlaier		if (a != NULL) {
7055171168Smlaier			a->packets[dirndx]++;
7056171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7057130613Smlaier		}
7058130613Smlaier		if (s != NULL) {
7059130613Smlaier			if (s->nat_rule.ptr != NULL) {
7060171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7061171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7062130613Smlaier			}
7063130613Smlaier			if (s->src_node != NULL) {
7064171168Smlaier				s->src_node->packets[dirndx]++;
7065171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7066130613Smlaier			}
7067130613Smlaier			if (s->nat_src_node != NULL) {
7068171168Smlaier				s->nat_src_node->packets[dirndx]++;
7069171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7070130613Smlaier			}
7071171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7072171168Smlaier			s->packets[dirndx]++;
7073171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7074130613Smlaier		}
7075130613Smlaier		tr = r;
7076130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7077130613Smlaier		if (nr != NULL) {
7078130613Smlaier			struct pf_addr *x;
7079130613Smlaier			/*
7080130613Smlaier			 * XXX: we need to make sure that the addresses
7081130613Smlaier			 * passed to pfr_update_stats() are the same than
7082130613Smlaier			 * the addresses used during matching (pfr_match)
7083130613Smlaier			 */
7084130613Smlaier			if (r == &pf_default_rule) {
7085130613Smlaier				tr = nr;
7086130613Smlaier				x = (s == NULL || s->direction == dir) ?
7087130613Smlaier				    &pd.baddr : &pd.naddr;
7088130613Smlaier			} else
7089130613Smlaier				x = (s == NULL || s->direction == dir) ?
7090130613Smlaier				    &pd.naddr : &pd.baddr;
7091130613Smlaier			if (x == &pd.baddr || s == NULL) {
7092130613Smlaier				/* we need to change the address */
7093130613Smlaier				if (dir == PF_OUT)
7094130613Smlaier					pd.src = x;
7095130613Smlaier				else
7096130613Smlaier					pd.dst = x;
7097130613Smlaier			}
7098130613Smlaier		}
7099130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7100130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7101130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7102130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7103145836Smlaier			    tr->src.neg);
7104130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7105130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7106130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7107130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7108145836Smlaier			    tr->dst.neg);
7109130613Smlaier	}
7110130613Smlaier
7111130613Smlaier
7112126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7113126258Smlaier		m_freem(*m0);
7114126258Smlaier		*m0 = NULL;
7115126258Smlaier		action = PF_PASS;
7116126258Smlaier	} else if (r->rt)
7117126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
7118171168Smlaier		pf_route(m0, r, dir, ifp, s, &pd);
7119126258Smlaier
7120127145Smlaier#ifdef __FreeBSD__
7121126261Smlaier	PF_UNLOCK();
7122126261Smlaier#endif
7123126261Smlaier
7124126258Smlaier	return (action);
7125126258Smlaier}
7126126258Smlaier#endif /* INET */
7127126258Smlaier
7128126258Smlaier#ifdef INET6
7129126258Smlaierint
7130135920Smlaier#ifdef __FreeBSD__
7131145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7132145836Smlaier    struct ether_header *eh, struct inpcb *inp)
7133135920Smlaier#else
7134145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7135145836Smlaier    struct ether_header *eh)
7136135920Smlaier#endif
7137126258Smlaier{
7138130613Smlaier	struct pfi_kif		*kif;
7139130613Smlaier	u_short			 action, reason = 0, log = 0;
7140171168Smlaier	struct mbuf		*m = *m0, *n = NULL;
7141171168Smlaier	struct ip6_hdr		*h;
7142130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
7143130613Smlaier	struct pf_state		*s = NULL;
7144130613Smlaier	struct pf_ruleset	*ruleset = NULL;
7145130613Smlaier	struct pf_pdesc		 pd;
7146169843Sdhartmei	int			 off, terminal = 0, dirndx, rh_cnt = 0;
7147126258Smlaier
7148127145Smlaier#ifdef __FreeBSD__
7149126261Smlaier	PF_LOCK();
7150126261Smlaier#endif
7151126261Smlaier
7152171168Smlaier	if (!pf_status.running)
7153127145Smlaier#ifdef __FreeBSD__
7154171168Smlaier	{
7155126261Smlaier		PF_UNLOCK();
7156126261Smlaier#endif
7157126258Smlaier		return (PF_PASS);
7158171168Smlaier#ifdef __FreeBSD__
7159126261Smlaier	}
7160171168Smlaier#endif
7161126258Smlaier
7162171168Smlaier	memset(&pd, 0, sizeof(pd));
7163171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
7164145836Smlaier#ifdef __FreeBSD__
7165171168Smlaier		PF_UNLOCK();
7166171168Smlaier#endif
7167171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7168171168Smlaier		    ("pf_test6: pf_get_mtag returned NULL\n"));
7169171168Smlaier		return (PF_DROP);
7170171168Smlaier	}
7171171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
7172171168Smlaier		return (PF_PASS);
7173171168Smlaier
7174171168Smlaier#ifdef __FreeBSD__
7175145836Smlaier	/* XXX_IMPORT: later */
7176145836Smlaier#else
7177145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
7178145836Smlaier		ifp = ifp->if_carpdev;
7179145836Smlaier#endif
7180145836Smlaier
7181171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
7182130613Smlaier	if (kif == NULL) {
7183130613Smlaier#ifdef __FreeBSD__
7184130613Smlaier		PF_UNLOCK();
7185130613Smlaier#endif
7186145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7187145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
7188130613Smlaier		return (PF_DROP);
7189130613Smlaier	}
7190145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
7191145836Smlaier#ifdef __FreeBSD__
7192145836Smlaier		PF_UNLOCK();
7193145836Smlaier#endif
7194145836Smlaier		return (PF_PASS);
7195145836Smlaier	}
7196130613Smlaier
7197130613Smlaier#ifdef __FreeBSD__
7198126261Smlaier	M_ASSERTPKTHDR(m);
7199126261Smlaier#else
7200126258Smlaier#ifdef DIAGNOSTIC
7201126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
7202145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
7203145836Smlaier#endif /* DIAGNOSTIC */
7204126258Smlaier#endif
7205126258Smlaier
7206171168Smlaier#ifdef __FreeBSD__
7207171168Smlaier	h = NULL;	/* make the compiler happy */
7208171168Smlaier#endif
7209171168Smlaier
7210126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
7211126258Smlaier		action = PF_DROP;
7212126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
7213126258Smlaier		log = 1;
7214126258Smlaier		goto done;
7215126258Smlaier	}
7216126258Smlaier
7217126258Smlaier	/* We do IP header normalization and packet reassembly here */
7218145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
7219126258Smlaier		action = PF_DROP;
7220126258Smlaier		goto done;
7221126258Smlaier	}
7222126258Smlaier	m = *m0;
7223126258Smlaier	h = mtod(m, struct ip6_hdr *);
7224126258Smlaier
7225169843Sdhartmei#if 1
7226169843Sdhartmei	/*
7227169843Sdhartmei	 * we do not support jumbogram yet.  if we keep going, zero ip6_plen
7228169843Sdhartmei	 * will do something bad, so drop the packet for now.
7229169843Sdhartmei	 */
7230169843Sdhartmei	if (htons(h->ip6_plen) == 0) {
7231169843Sdhartmei		action = PF_DROP;
7232169843Sdhartmei		REASON_SET(&reason, PFRES_NORM);	/*XXX*/
7233169843Sdhartmei		goto done;
7234169843Sdhartmei	}
7235169843Sdhartmei#endif
7236169843Sdhartmei
7237126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
7238126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
7239130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
7240126258Smlaier	pd.ip_sum = NULL;
7241126258Smlaier	pd.af = AF_INET6;
7242126258Smlaier	pd.tos = 0;
7243126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
7244145836Smlaier	pd.eh = eh;
7245126258Smlaier
7246126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
7247126258Smlaier	pd.proto = h->ip6_nxt;
7248126258Smlaier	do {
7249126258Smlaier		switch (pd.proto) {
7250126258Smlaier		case IPPROTO_FRAGMENT:
7251130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
7252126258Smlaier			    &pd, &a, &ruleset);
7253126258Smlaier			if (action == PF_DROP)
7254126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
7255126258Smlaier			goto done;
7256169843Sdhartmei		case IPPROTO_ROUTING: {
7257169843Sdhartmei			struct ip6_rthdr rthdr;
7258169843Sdhartmei
7259169843Sdhartmei			if (rh_cnt++) {
7260169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7261169843Sdhartmei				    ("pf: IPv6 more than one rthdr\n"));
7262169843Sdhartmei				action = PF_DROP;
7263169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7264169843Sdhartmei				log = 1;
7265169843Sdhartmei				goto done;
7266169843Sdhartmei			}
7267169843Sdhartmei			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
7268169843Sdhartmei			    &reason, pd.af)) {
7269169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7270169843Sdhartmei				    ("pf: IPv6 short rthdr\n"));
7271169843Sdhartmei				action = PF_DROP;
7272169843Sdhartmei				REASON_SET(&reason, PFRES_SHORT);
7273169843Sdhartmei				log = 1;
7274169843Sdhartmei				goto done;
7275169843Sdhartmei			}
7276169843Sdhartmei			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
7277169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7278169843Sdhartmei				    ("pf: IPv6 rthdr0\n"));
7279169843Sdhartmei				action = PF_DROP;
7280169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7281169843Sdhartmei				log = 1;
7282169843Sdhartmei				goto done;
7283169843Sdhartmei			}
7284169843Sdhartmei			/* fallthrough */
7285169843Sdhartmei		}
7286126258Smlaier		case IPPROTO_AH:
7287126258Smlaier		case IPPROTO_HOPOPTS:
7288126258Smlaier		case IPPROTO_DSTOPTS: {
7289126258Smlaier			/* get next header and header length */
7290126258Smlaier			struct ip6_ext	opt6;
7291126258Smlaier
7292126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
7293145836Smlaier			    NULL, &reason, pd.af)) {
7294126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
7295126258Smlaier				    ("pf: IPv6 short opt\n"));
7296126258Smlaier				action = PF_DROP;
7297126258Smlaier				log = 1;
7298126258Smlaier				goto done;
7299126258Smlaier			}
7300126258Smlaier			if (pd.proto == IPPROTO_AH)
7301126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
7302126258Smlaier			else
7303126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
7304126258Smlaier			pd.proto = opt6.ip6e_nxt;
7305126258Smlaier			/* goto the next header */
7306126258Smlaier			break;
7307126258Smlaier		}
7308126258Smlaier		default:
7309126258Smlaier			terminal++;
7310126258Smlaier			break;
7311126258Smlaier		}
7312126258Smlaier	} while (!terminal);
7313126258Smlaier
7314171168Smlaier	/* if there's no routing header, use unmodified mbuf for checksumming */
7315171168Smlaier	if (!n)
7316171168Smlaier		n = m;
7317171168Smlaier
7318126258Smlaier	switch (pd.proto) {
7319126258Smlaier
7320126258Smlaier	case IPPROTO_TCP: {
7321126258Smlaier		struct tcphdr	th;
7322126258Smlaier
7323126258Smlaier		pd.hdr.tcp = &th;
7324126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
7325126258Smlaier		    &action, &reason, AF_INET6)) {
7326126258Smlaier			log = action != PF_PASS;
7327126258Smlaier			goto done;
7328126258Smlaier		}
7329171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7330138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7331138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
7332126258Smlaier			action = PF_DROP;
7333145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7334126258Smlaier			goto done;
7335126258Smlaier		}
7336126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
7337130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
7338126258Smlaier		if (action == PF_DROP)
7339130613Smlaier			goto done;
7340130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
7341126258Smlaier		    &reason);
7342126258Smlaier		if (action == PF_PASS) {
7343130613Smlaier#if NPFSYNC
7344130613Smlaier			pfsync_update_state(s);
7345145836Smlaier#endif /* NPFSYNC */
7346126258Smlaier			r = s->rule.ptr;
7347130613Smlaier			a = s->anchor.ptr;
7348126258Smlaier			log = s->log;
7349126258Smlaier		} else if (s == NULL)
7350135920Smlaier#ifdef __FreeBSD__
7351130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7352145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7353135920Smlaier#else
7354135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7355145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7356135920Smlaier#endif
7357126258Smlaier		break;
7358126258Smlaier	}
7359126258Smlaier
7360126258Smlaier	case IPPROTO_UDP: {
7361126258Smlaier		struct udphdr	uh;
7362126258Smlaier
7363126258Smlaier		pd.hdr.udp = &uh;
7364126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
7365126258Smlaier		    &action, &reason, AF_INET6)) {
7366126258Smlaier			log = action != PF_PASS;
7367126258Smlaier			goto done;
7368126258Smlaier		}
7369171168Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
7370138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7371138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
7372126258Smlaier			action = PF_DROP;
7373145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7374126258Smlaier			goto done;
7375126258Smlaier		}
7376130613Smlaier		if (uh.uh_dport == 0 ||
7377130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
7378130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
7379130613Smlaier			action = PF_DROP;
7380171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
7381130613Smlaier			goto done;
7382130613Smlaier		}
7383130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
7384126258Smlaier		if (action == PF_PASS) {
7385130613Smlaier#if NPFSYNC
7386130613Smlaier			pfsync_update_state(s);
7387145836Smlaier#endif /* NPFSYNC */
7388126258Smlaier			r = s->rule.ptr;
7389130613Smlaier			a = s->anchor.ptr;
7390126258Smlaier			log = s->log;
7391126258Smlaier		} else if (s == NULL)
7392135920Smlaier#ifdef __FreeBSD__
7393130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7394145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7395135920Smlaier#else
7396135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7397145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7398135920Smlaier#endif
7399126258Smlaier		break;
7400126258Smlaier	}
7401126258Smlaier
7402126258Smlaier	case IPPROTO_ICMPV6: {
7403126258Smlaier		struct icmp6_hdr	ih;
7404126258Smlaier
7405126258Smlaier		pd.hdr.icmp6 = &ih;
7406126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
7407126258Smlaier		    &action, &reason, AF_INET6)) {
7408126258Smlaier			log = action != PF_PASS;
7409126258Smlaier			goto done;
7410126258Smlaier		}
7411171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7412145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7413138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
7414126258Smlaier			action = PF_DROP;
7415145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7416126258Smlaier			goto done;
7417126258Smlaier		}
7418130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
7419145836Smlaier		    m, off, h, &pd, &reason);
7420126258Smlaier		if (action == PF_PASS) {
7421130613Smlaier#if NPFSYNC
7422130613Smlaier			pfsync_update_state(s);
7423145836Smlaier#endif /* NPFSYNC */
7424126258Smlaier			r = s->rule.ptr;
7425130613Smlaier			a = s->anchor.ptr;
7426126258Smlaier			log = s->log;
7427126258Smlaier		} else if (s == NULL)
7428145836Smlaier#ifdef __FreeBSD__
7429130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7430145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
7431145836Smlaier#else
7432145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7433145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7434145836Smlaier#endif
7435126258Smlaier		break;
7436126258Smlaier	}
7437126258Smlaier
7438126258Smlaier	default:
7439130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
7440130613Smlaier		if (action == PF_PASS) {
7441145836Smlaier#if NPFSYNC
7442145836Smlaier			pfsync_update_state(s);
7443145836Smlaier#endif /* NPFSYNC */
7444130613Smlaier			r = s->rule.ptr;
7445130613Smlaier			a = s->anchor.ptr;
7446130613Smlaier			log = s->log;
7447130613Smlaier		} else if (s == NULL)
7448145836Smlaier#ifdef __FreeBSD__
7449130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7450145836Smlaier			    &pd, &a, &ruleset, NULL);
7451145836Smlaier#else
7452145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7453145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
7454145836Smlaier#endif
7455126258Smlaier		break;
7456126258Smlaier	}
7457126258Smlaier
7458126258Smlaierdone:
7459169843Sdhartmei	/* handle dangerous IPv6 extension headers. */
7460169843Sdhartmei	if (action == PF_PASS && rh_cnt &&
7461169843Sdhartmei	    !((s && s->allow_opts) || r->allow_opts)) {
7462169843Sdhartmei		action = PF_DROP;
7463169843Sdhartmei		REASON_SET(&reason, PFRES_IPOPTIONS);
7464169843Sdhartmei		log = 1;
7465169843Sdhartmei		DPFPRINTF(PF_DEBUG_MISC,
7466169843Sdhartmei		    ("pf: dropping packet with dangerous v6 headers\n"));
7467169843Sdhartmei	}
7468126258Smlaier
7469171168Smlaier	if ((s && s->tag) || r->rtableid)
7470171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7471145836Smlaier
7472126258Smlaier#ifdef ALTQ
7473126258Smlaier	if (action == PF_PASS && r->qid) {
7474171168Smlaier		if (pd.tos & IPTOS_LOWDELAY)
7475171168Smlaier			pd.pf_mtag->qid = r->pqid;
7476171168Smlaier		else
7477171168Smlaier			pd.pf_mtag->qid = r->qid;
7478171168Smlaier		/* add hints for ecn */
7479171168Smlaier		pd.pf_mtag->af = AF_INET6;
7480171168Smlaier		pd.pf_mtag->hdr = h;
7481126258Smlaier	}
7482145836Smlaier#endif /* ALTQ */
7483126258Smlaier
7484130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7485130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7486130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7487130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7488171168Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
7489171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7490171168Smlaier
7491171168Smlaier	if (log) {
7492171168Smlaier		struct pf_rule *lr;
7493171168Smlaier
7494171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7495171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7496171168Smlaier			lr = s->nat_rule.ptr;
7497171168Smlaier		else
7498171168Smlaier			lr = r;
7499171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
7500171168Smlaier		    &pd);
7501130613Smlaier	}
7502130613Smlaier
7503130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7504130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7505130613Smlaier
7506130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7507171168Smlaier		dirndx = (dir == PF_OUT);
7508171168Smlaier		r->packets[dirndx]++;
7509171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7510130613Smlaier		if (a != NULL) {
7511171168Smlaier			a->packets[dirndx]++;
7512171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7513130613Smlaier		}
7514130613Smlaier		if (s != NULL) {
7515130613Smlaier			if (s->nat_rule.ptr != NULL) {
7516171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7517171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7518130613Smlaier			}
7519130613Smlaier			if (s->src_node != NULL) {
7520171168Smlaier				s->src_node->packets[dirndx]++;
7521171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7522130613Smlaier			}
7523130613Smlaier			if (s->nat_src_node != NULL) {
7524171168Smlaier				s->nat_src_node->packets[dirndx]++;
7525171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7526130613Smlaier			}
7527171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7528171168Smlaier			s->packets[dirndx]++;
7529171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7530130613Smlaier		}
7531130613Smlaier		tr = r;
7532130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7533130613Smlaier		if (nr != NULL) {
7534130613Smlaier			struct pf_addr *x;
7535130613Smlaier			/*
7536130613Smlaier			 * XXX: we need to make sure that the addresses
7537130613Smlaier			 * passed to pfr_update_stats() are the same than
7538130613Smlaier			 * the addresses used during matching (pfr_match)
7539130613Smlaier			 */
7540130613Smlaier			if (r == &pf_default_rule) {
7541130613Smlaier				tr = nr;
7542130613Smlaier				x = (s == NULL || s->direction == dir) ?
7543130613Smlaier				    &pd.baddr : &pd.naddr;
7544130613Smlaier			} else {
7545130613Smlaier				x = (s == NULL || s->direction == dir) ?
7546130613Smlaier				    &pd.naddr : &pd.baddr;
7547130613Smlaier			}
7548130613Smlaier			if (x == &pd.baddr || s == NULL) {
7549130613Smlaier				if (dir == PF_OUT)
7550130613Smlaier					pd.src = x;
7551130613Smlaier				else
7552130613Smlaier					pd.dst = x;
7553130613Smlaier			}
7554130613Smlaier		}
7555130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7556130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7557130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7558130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7559145836Smlaier			    tr->src.neg);
7560130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7561130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7562130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7563130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7564145836Smlaier			    tr->dst.neg);
7565130613Smlaier	}
7566130613Smlaier
7567130613Smlaier
7568126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7569126258Smlaier		m_freem(*m0);
7570126258Smlaier		*m0 = NULL;
7571126258Smlaier		action = PF_PASS;
7572126258Smlaier	} else if (r->rt)
7573126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7574171168Smlaier		pf_route6(m0, r, dir, ifp, s, &pd);
7575126258Smlaier
7576127145Smlaier#ifdef __FreeBSD__
7577126261Smlaier	PF_UNLOCK();
7578126261Smlaier#endif
7579126258Smlaier	return (action);
7580126258Smlaier}
7581126258Smlaier#endif /* INET6 */
7582145836Smlaier
7583145836Smlaierint
7584145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7585145836Smlaier{
7586145836Smlaier#ifdef __FreeBSD__
7587145836Smlaier	/* XXX_IMPORT: later */
7588145836Smlaier	return (0);
7589145836Smlaier#else
7590145836Smlaier	if (ifq->ifq_congestion)
7591145836Smlaier		return (1);
7592145836Smlaier	else
7593145836Smlaier		return (0);
7594145836Smlaier#endif
7595145836Smlaier}
7596