pf.c revision 196372
1171168Smlaier/*	$OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */
2181295Smlaier/* add:	$OpenBSD: pf.c,v 1.559 2007/09/18 18:45:59 markus Exp $ */
3126258Smlaier
4126258Smlaier/*
5126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
6130613Smlaier * Copyright (c) 2002,2003 Henning Brauer
7126258Smlaier * All rights reserved.
8126258Smlaier *
9126258Smlaier * Redistribution and use in source and binary forms, with or without
10126258Smlaier * modification, are permitted provided that the following conditions
11126258Smlaier * are met:
12126258Smlaier *
13126258Smlaier *    - Redistributions of source code must retain the above copyright
14126258Smlaier *      notice, this list of conditions and the following disclaimer.
15126258Smlaier *    - Redistributions in binary form must reproduce the above
16126258Smlaier *      copyright notice, this list of conditions and the following
17126258Smlaier *      disclaimer in the documentation and/or other materials provided
18126258Smlaier *      with the distribution.
19126258Smlaier *
20126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
32126258Smlaier *
33126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
34126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
35126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
36126258Smlaier *
37126258Smlaier */
38126258Smlaier
39127145Smlaier#ifdef __FreeBSD__
40126261Smlaier#include "opt_inet.h"
41126261Smlaier#include "opt_inet6.h"
42171168Smlaier
43171168Smlaier#include <sys/cdefs.h>
44171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf.c 196372 2009-08-19 00:10:10Z mlaier $");
45126261Smlaier#endif
46126261Smlaier
47127145Smlaier#ifdef __FreeBSD__
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;
974196372Smlaier#ifdef __FreeBSD__
975196372Smlaier	int locked;
976196372Smlaier#endif
977171168Smlaier
978171168Smlaier	for (;;) {
979171168Smlaier		tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
980171168Smlaier
981127145Smlaier#ifdef __FreeBSD__
982171168Smlaier		sx_slock(&pf_consistency_lock);
983171168Smlaier		PF_LOCK();
984196372Smlaier		locked = 0;
985126258Smlaier
986171168Smlaier		if (pf_end_threads) {
987196372Smlaier			PF_UNLOCK();
988196372Smlaier			sx_sunlock(&pf_consistency_lock);
989196372Smlaier			sx_xlock(&pf_consistency_lock);
990196372Smlaier			PF_LOCK();
991196372Smlaier			pf_purge_expired_states(pf_status.states, 1);
992171168Smlaier			pf_purge_expired_fragments();
993196372Smlaier			pf_purge_expired_src_nodes(1);
994171168Smlaier			pf_end_threads++;
995171168Smlaier
996196372Smlaier			sx_xunlock(&pf_consistency_lock);
997171168Smlaier			PF_UNLOCK();
998171168Smlaier			wakeup(pf_purge_thread);
999172836Sjulian			kproc_exit(0);
1000171168Smlaier		}
1001126261Smlaier#endif
1002171168Smlaier		s = splsoftnet();
1003126258Smlaier
1004171168Smlaier		/* process a fraction of the state table every second */
1005196372Smlaier#ifdef __FreeBSD__
1006196372Smlaier		if(!pf_purge_expired_states(1 + (pf_status.states
1007196372Smlaier		    / pf_default_rule.timeout[PFTM_INTERVAL]), 0)) {
1008196372Smlaier			PF_UNLOCK();
1009196372Smlaier			sx_sunlock(&pf_consistency_lock);
1010196372Smlaier			sx_xlock(&pf_consistency_lock);
1011196372Smlaier			PF_LOCK();
1012196372Smlaier			locked = 1;
1013196372Smlaier
1014196372Smlaier			pf_purge_expired_states(1 + (pf_status.states
1015196372Smlaier			    / pf_default_rule.timeout[PFTM_INTERVAL]), 1);
1016196372Smlaier		}
1017196372Smlaier#else
1018171168Smlaier		pf_purge_expired_states(1 + (pf_status.states
1019171168Smlaier		    / pf_default_rule.timeout[PFTM_INTERVAL]));
1020196372Smlaier#endif
1021171168Smlaier
1022171168Smlaier		/* purge other expired types every PFTM_INTERVAL seconds */
1023171168Smlaier		if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
1024171168Smlaier			pf_purge_expired_fragments();
1025196372Smlaier			if (!pf_purge_expired_src_nodes(locked)) {
1026196372Smlaier				PF_UNLOCK();
1027196372Smlaier				sx_sunlock(&pf_consistency_lock);
1028196372Smlaier				sx_xlock(&pf_consistency_lock);
1029196372Smlaier				PF_LOCK();
1030196372Smlaier				locked = 1;
1031196372Smlaier				pf_purge_expired_src_nodes(1);
1032196372Smlaier			}
1033171168Smlaier			nloops = 0;
1034171168Smlaier		}
1035171168Smlaier
1036171168Smlaier		splx(s);
1037127145Smlaier#ifdef __FreeBSD__
1038171168Smlaier		PF_UNLOCK();
1039196372Smlaier		if (locked)
1040196372Smlaier			sx_xunlock(&pf_consistency_lock);
1041196372Smlaier		else
1042196372Smlaier			sx_sunlock(&pf_consistency_lock);
1043126261Smlaier#endif
1044171168Smlaier	}
1045126258Smlaier}
1046126258Smlaier
1047126258Smlaieru_int32_t
1048126258Smlaierpf_state_expires(const struct pf_state *state)
1049126258Smlaier{
1050126258Smlaier	u_int32_t	timeout;
1051126258Smlaier	u_int32_t	start;
1052126258Smlaier	u_int32_t	end;
1053126258Smlaier	u_int32_t	states;
1054126258Smlaier
1055126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1056126258Smlaier	if (state->timeout == PFTM_PURGE)
1057126261Smlaier		return (time_second);
1058126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1059126258Smlaier		return (0);
1060127145Smlaier#ifdef __FreeBSD__
1061171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED,
1062171168Smlaier	    ("pf_state_expires: timeout == PFTM_UNLINKED"));
1063126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1064126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1065126261Smlaier#else
1066171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED);
1067126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1068126261Smlaier#endif
1069126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1070126258Smlaier	if (!timeout)
1071126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1072126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1073126258Smlaier	if (start) {
1074126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1075126258Smlaier		states = state->rule.ptr->states;
1076126258Smlaier	} else {
1077126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1078126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1079126258Smlaier		states = pf_status.states;
1080126258Smlaier	}
1081126258Smlaier	if (end && states > start && start < end) {
1082126258Smlaier		if (states < end)
1083126258Smlaier			return (state->expire + timeout * (end - states) /
1084126258Smlaier			    (end - start));
1085126258Smlaier		else
1086126261Smlaier			return (time_second);
1087126258Smlaier	}
1088126258Smlaier	return (state->expire + timeout);
1089126258Smlaier}
1090126258Smlaier
1091196372Smlaier#ifdef __FreeBSD__
1092196372Smlaierint
1093196372Smlaierpf_purge_expired_src_nodes(int waslocked)
1094196372Smlaier#else
1095126258Smlaiervoid
1096171168Smlaierpf_purge_expired_src_nodes(int waslocked)
1097196372Smlaier#endif
1098126258Smlaier{
1099130613Smlaier	 struct pf_src_node		*cur, *next;
1100171168Smlaier	 int				 locked = waslocked;
1101126258Smlaier
1102130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1103130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1104126258Smlaier
1105130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1106171168Smlaier			 if (! locked) {
1107171168Smlaier#ifdef __FreeBSD__
1108196372Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock))
1109196372Smlaier				 	return (0);
1110171168Smlaier#else
1111171168Smlaier				 rw_enter_write(&pf_consistency_lock);
1112171168Smlaier#endif
1113171168Smlaier			 	 next = RB_NEXT(pf_src_tree,
1114171168Smlaier				     &tree_src_tracking, cur);
1115171168Smlaier				 locked = 1;
1116171168Smlaier			 }
1117130613Smlaier			 if (cur->rule.ptr != NULL) {
1118130613Smlaier				 cur->rule.ptr->src_nodes--;
1119130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1120130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1121130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1122130613Smlaier			 }
1123130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1124130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1125130613Smlaier			 pf_status.src_nodes--;
1126130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1127130613Smlaier		 }
1128130613Smlaier	 }
1129171168Smlaier
1130171168Smlaier	 if (locked && !waslocked)
1131171168Smlaier#ifdef __FreeBSD__
1132171168Smlaier		sx_downgrade(&pf_consistency_lock);
1133171168Smlaier#else
1134171168Smlaier		rw_exit_write(&pf_consistency_lock);
1135171168Smlaier#endif
1136196372Smlaier
1137196372Smlaier#ifdef __FreeBSD__
1138196372Smlaier	return (1);
1139196372Smlaier#endif
1140130613Smlaier}
1141126258Smlaier
1142130613Smlaiervoid
1143130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1144130613Smlaier{
1145130613Smlaier	u_int32_t timeout;
1146126258Smlaier
1147130613Smlaier	if (s->src_node != NULL) {
1148145836Smlaier		if (s->proto == IPPROTO_TCP) {
1149171168Smlaier			if (s->src.tcp_est)
1150145836Smlaier				--s->src_node->conn;
1151145836Smlaier		}
1152130613Smlaier		if (--s->src_node->states <= 0) {
1153130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1154130613Smlaier			if (!timeout)
1155130613Smlaier				timeout =
1156130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1157130613Smlaier			s->src_node->expire = time_second + timeout;
1158130613Smlaier		}
1159130613Smlaier	}
1160130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1161130613Smlaier		if (--s->nat_src_node->states <= 0) {
1162130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1163130613Smlaier			if (!timeout)
1164130613Smlaier				timeout =
1165130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1166130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1167130613Smlaier		}
1168130613Smlaier	}
1169130613Smlaier	s->src_node = s->nat_src_node = NULL;
1170130613Smlaier}
1171126258Smlaier
1172171168Smlaier/* callers should be at splsoftnet */
1173130613Smlaiervoid
1174171168Smlaierpf_unlink_state(struct pf_state *cur)
1175145836Smlaier{
1176148196Smlaier#ifdef __FreeBSD__
1177153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1178148196Smlaier		return;
1179153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1180148196Smlaier#endif
1181171168Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST) {
1182162238Scsjp#ifdef __FreeBSD__
1183162238Scsjp		pf_send_tcp(NULL, cur->rule.ptr, cur->af,
1184162238Scsjp#else
1185145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1186162238Scsjp#endif
1187145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1188145836Smlaier		    cur->ext.port, cur->lan.port,
1189145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1190171168Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
1191171168Smlaier	}
1192145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1193145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1194145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1195145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1196145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1197145836Smlaier#if NPFSYNC
1198171168Smlaier	if (cur->creatorid == pf_status.hostid)
1199171168Smlaier		pfsync_delete_state(cur);
1200145836Smlaier#endif
1201171168Smlaier	cur->timeout = PFTM_UNLINKED;
1202145836Smlaier	pf_src_tree_remove_state(cur);
1203171168Smlaier}
1204171168Smlaier
1205171168Smlaier/* callers should be at splsoftnet and hold the
1206171168Smlaier * write_lock on pf_consistency_lock */
1207171168Smlaiervoid
1208171168Smlaierpf_free_state(struct pf_state *cur)
1209171168Smlaier{
1210171168Smlaier#if NPFSYNC
1211171168Smlaier	if (pfsyncif != NULL &&
1212171168Smlaier	    (pfsyncif->sc_bulk_send_next == cur ||
1213171168Smlaier	    pfsyncif->sc_bulk_terminator == cur))
1214171168Smlaier		return;
1215171168Smlaier#endif
1216171168Smlaier#ifdef __FreeBSD__
1217171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED,
1218171168Smlaier	    ("pf_free_state: cur->timeout != PFTM_UNLINKED"));
1219171168Smlaier#else
1220171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED);
1221171168Smlaier#endif
1222145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1223145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1224145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1225145836Smlaier	if (cur->nat_rule.ptr != NULL)
1226145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1227145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1228145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1229145836Smlaier	if (cur->anchor.ptr != NULL)
1230145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1231145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1232145836Smlaier	pf_normalize_tcp_cleanup(cur);
1233171168Smlaier	pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
1234171168Smlaier	TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
1235145836Smlaier	if (cur->tag)
1236145836Smlaier		pf_tag_unref(cur->tag);
1237145836Smlaier	pool_put(&pf_state_pl, cur);
1238145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1239145836Smlaier	pf_status.states--;
1240145836Smlaier}
1241145836Smlaier
1242196372Smlaier#ifdef __FreeBSD__
1243196372Smlaierint
1244196372Smlaierpf_purge_expired_states(u_int32_t maxcheck, int waslocked)
1245196372Smlaier#else
1246145836Smlaiervoid
1247171168Smlaierpf_purge_expired_states(u_int32_t maxcheck)
1248196372Smlaier#endif
1249130613Smlaier{
1250171168Smlaier	static struct pf_state	*cur = NULL;
1251171168Smlaier	struct pf_state		*next;
1252196372Smlaier#ifdef __FreeBSD__
1253196372Smlaier	int 			 locked = waslocked;
1254196372Smlaier#else
1255171168Smlaier	int 			 locked = 0;
1256196372Smlaier#endif
1257130613Smlaier
1258171168Smlaier	while (maxcheck--) {
1259171168Smlaier		/* wrap to start of list when we hit the end */
1260171168Smlaier		if (cur == NULL) {
1261171168Smlaier			cur = TAILQ_FIRST(&state_list);
1262171168Smlaier			if (cur == NULL)
1263171168Smlaier				break;	/* list empty */
1264171168Smlaier		}
1265171168Smlaier
1266171168Smlaier		/* get next state, as cur may get deleted */
1267171168Smlaier		next = TAILQ_NEXT(cur, u.s.entry_list);
1268171168Smlaier
1269171168Smlaier		if (cur->timeout == PFTM_UNLINKED) {
1270171168Smlaier			/* free unlinked state */
1271171168Smlaier			if (! locked) {
1272171168Smlaier#ifdef __FreeBSD__
1273196372Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock))
1274196372Smlaier				 	return (0);
1275171168Smlaier#else
1276171168Smlaier				rw_enter_write(&pf_consistency_lock);
1277171168Smlaier#endif
1278171168Smlaier				locked = 1;
1279171168Smlaier			}
1280171168Smlaier			pf_free_state(cur);
1281171168Smlaier		} else if (pf_state_expires(cur) <= time_second) {
1282171168Smlaier			/* unlink and free expired state */
1283171168Smlaier			pf_unlink_state(cur);
1284171168Smlaier			if (! locked) {
1285171168Smlaier#ifdef __FreeBSD__
1286196372Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock))
1287196372Smlaier				 	return (0);
1288171168Smlaier#else
1289171168Smlaier				rw_enter_write(&pf_consistency_lock);
1290171168Smlaier#endif
1291171168Smlaier				locked = 1;
1292171168Smlaier			}
1293171168Smlaier			pf_free_state(cur);
1294171168Smlaier		}
1295171168Smlaier		cur = next;
1296126258Smlaier	}
1297171168Smlaier
1298171168Smlaier#ifdef __FreeBSD__
1299196372Smlaier	if (!waslocked && locked)
1300171168Smlaier		sx_downgrade(&pf_consistency_lock);
1301196372Smlaier
1302196372Smlaier	return (1);
1303171168Smlaier#else
1304196372Smlaier	if (locked)
1305171168Smlaier		rw_exit_write(&pf_consistency_lock);
1306171168Smlaier#endif
1307126258Smlaier}
1308126258Smlaier
1309126258Smlaierint
1310126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1311126258Smlaier{
1312126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1313126258Smlaier		return (0);
1314126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1315126258Smlaier		return (1);
1316126258Smlaier	return (0);
1317126258Smlaier}
1318126258Smlaier
1319126258Smlaiervoid
1320126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1321126258Smlaier{
1322126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1323126258Smlaier		return;
1324126258Smlaier	pfr_detach_table(aw->p.tbl);
1325126258Smlaier	aw->p.tbl = NULL;
1326126258Smlaier}
1327126258Smlaier
1328126258Smlaiervoid
1329126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1330126258Smlaier{
1331126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1332126258Smlaier
1333126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1334126258Smlaier		return;
1335126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1336126258Smlaier		kt = kt->pfrkt_root;
1337126258Smlaier	aw->p.tbl = NULL;
1338126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1339126258Smlaier		kt->pfrkt_cnt : -1;
1340126258Smlaier}
1341126258Smlaier
1342126258Smlaiervoid
1343126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1344126258Smlaier{
1345126258Smlaier	switch (af) {
1346126258Smlaier#ifdef INET
1347126258Smlaier	case AF_INET: {
1348126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1349126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1350126258Smlaier		    (a>>8)&255, a&255);
1351126258Smlaier		if (p) {
1352126258Smlaier			p = ntohs(p);
1353126258Smlaier			printf(":%u", p);
1354126258Smlaier		}
1355126258Smlaier		break;
1356126258Smlaier	}
1357126258Smlaier#endif /* INET */
1358126258Smlaier#ifdef INET6
1359126258Smlaier	case AF_INET6: {
1360126258Smlaier		u_int16_t b;
1361126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1362126258Smlaier		    maxstart = 0, maxend = 0;
1363126258Smlaier		for (i = 0; i < 8; i++) {
1364126258Smlaier			if (!addr->addr16[i]) {
1365126258Smlaier				if (curstart == 255)
1366126258Smlaier					curstart = i;
1367126258Smlaier				else
1368126258Smlaier					curend = i;
1369126258Smlaier			} else {
1370126258Smlaier				if (curstart) {
1371126258Smlaier					if ((curend - curstart) >
1372126258Smlaier					    (maxend - maxstart)) {
1373126258Smlaier						maxstart = curstart;
1374126258Smlaier						maxend = curend;
1375126258Smlaier						curstart = 255;
1376126258Smlaier					}
1377126258Smlaier				}
1378126258Smlaier			}
1379126258Smlaier		}
1380126258Smlaier		for (i = 0; i < 8; i++) {
1381126258Smlaier			if (i >= maxstart && i <= maxend) {
1382126258Smlaier				if (maxend != 7) {
1383126258Smlaier					if (i == maxstart)
1384126258Smlaier						printf(":");
1385126258Smlaier				} else {
1386126258Smlaier					if (i == maxend)
1387126258Smlaier						printf(":");
1388126258Smlaier				}
1389126258Smlaier			} else {
1390126258Smlaier				b = ntohs(addr->addr16[i]);
1391126258Smlaier				printf("%x", b);
1392126258Smlaier				if (i < 7)
1393126258Smlaier					printf(":");
1394126258Smlaier			}
1395126258Smlaier		}
1396126258Smlaier		if (p) {
1397126258Smlaier			p = ntohs(p);
1398126258Smlaier			printf("[%u]", p);
1399126258Smlaier		}
1400126258Smlaier		break;
1401126258Smlaier	}
1402126258Smlaier#endif /* INET6 */
1403126258Smlaier	}
1404126258Smlaier}
1405126258Smlaier
1406126258Smlaiervoid
1407126258Smlaierpf_print_state(struct pf_state *s)
1408126258Smlaier{
1409126258Smlaier	switch (s->proto) {
1410126258Smlaier	case IPPROTO_TCP:
1411126258Smlaier		printf("TCP ");
1412126258Smlaier		break;
1413126258Smlaier	case IPPROTO_UDP:
1414126258Smlaier		printf("UDP ");
1415126258Smlaier		break;
1416126258Smlaier	case IPPROTO_ICMP:
1417126258Smlaier		printf("ICMP ");
1418126258Smlaier		break;
1419126258Smlaier	case IPPROTO_ICMPV6:
1420126258Smlaier		printf("ICMPV6 ");
1421126258Smlaier		break;
1422126258Smlaier	default:
1423126258Smlaier		printf("%u ", s->proto);
1424126258Smlaier		break;
1425126258Smlaier	}
1426126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1427126258Smlaier	printf(" ");
1428126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1429126258Smlaier	printf(" ");
1430126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1431126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1432126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1433126258Smlaier	if (s->src.wscale && s->dst.wscale)
1434126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1435126258Smlaier	printf("]");
1436126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1437126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1438126258Smlaier	if (s->src.wscale && s->dst.wscale)
1439126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1440126258Smlaier	printf("]");
1441126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1442126258Smlaier}
1443126258Smlaier
1444126258Smlaiervoid
1445126258Smlaierpf_print_flags(u_int8_t f)
1446126258Smlaier{
1447126258Smlaier	if (f)
1448126258Smlaier		printf(" ");
1449126258Smlaier	if (f & TH_FIN)
1450126258Smlaier		printf("F");
1451126258Smlaier	if (f & TH_SYN)
1452126258Smlaier		printf("S");
1453126258Smlaier	if (f & TH_RST)
1454126258Smlaier		printf("R");
1455126258Smlaier	if (f & TH_PUSH)
1456126258Smlaier		printf("P");
1457126258Smlaier	if (f & TH_ACK)
1458126258Smlaier		printf("A");
1459126258Smlaier	if (f & TH_URG)
1460126258Smlaier		printf("U");
1461126258Smlaier	if (f & TH_ECE)
1462126258Smlaier		printf("E");
1463126258Smlaier	if (f & TH_CWR)
1464126258Smlaier		printf("W");
1465126258Smlaier}
1466126258Smlaier
1467126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1468126258Smlaier	do {							\
1469126258Smlaier		while (head[i] != cur) {			\
1470126258Smlaier			head[i]->skip[i].ptr = cur;		\
1471126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1472126258Smlaier		}						\
1473126258Smlaier	} while (0)
1474126258Smlaier
1475126258Smlaiervoid
1476126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1477126258Smlaier{
1478126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1479126258Smlaier	int i;
1480126258Smlaier
1481126258Smlaier	cur = TAILQ_FIRST(rules);
1482126258Smlaier	prev = cur;
1483126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1484126258Smlaier		head[i] = cur;
1485126258Smlaier	while (cur != NULL) {
1486126258Smlaier
1487130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1488126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1489126258Smlaier		if (cur->direction != prev->direction)
1490126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1491126258Smlaier		if (cur->af != prev->af)
1492126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1493126258Smlaier		if (cur->proto != prev->proto)
1494126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1495145836Smlaier		if (cur->src.neg != prev->src.neg ||
1496126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1497126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1498126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1499126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1500126258Smlaier		    cur->src.port_op != prev->src.port_op)
1501126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1502145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1503126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1504126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1505126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1506126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1507126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1508126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1509126258Smlaier
1510126258Smlaier		prev = cur;
1511126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1512126258Smlaier	}
1513126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1514126258Smlaier		PF_SET_SKIP_STEPS(i);
1515126258Smlaier}
1516126258Smlaier
1517126258Smlaierint
1518126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1519126258Smlaier{
1520126258Smlaier	if (aw1->type != aw2->type)
1521126258Smlaier		return (1);
1522126258Smlaier	switch (aw1->type) {
1523126258Smlaier	case PF_ADDR_ADDRMASK:
1524126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1525126258Smlaier			return (1);
1526126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1527126258Smlaier			return (1);
1528126258Smlaier		return (0);
1529126258Smlaier	case PF_ADDR_DYNIFTL:
1530130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1531126258Smlaier	case PF_ADDR_NOROUTE:
1532171168Smlaier	case PF_ADDR_URPFFAILED:
1533126258Smlaier		return (0);
1534126258Smlaier	case PF_ADDR_TABLE:
1535126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1536171168Smlaier	case PF_ADDR_RTLABEL:
1537171168Smlaier		return (aw1->v.rtlabel != aw2->v.rtlabel);
1538126258Smlaier	default:
1539126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1540126258Smlaier		return (1);
1541126258Smlaier	}
1542126258Smlaier}
1543126258Smlaier
1544126258Smlaieru_int16_t
1545126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1546126258Smlaier{
1547126258Smlaier	u_int32_t	l;
1548126258Smlaier
1549126258Smlaier	if (udp && !cksum)
1550126258Smlaier		return (0x0000);
1551126258Smlaier	l = cksum + old - new;
1552126258Smlaier	l = (l >> 16) + (l & 65535);
1553126258Smlaier	l = l & 65535;
1554126258Smlaier	if (udp && !l)
1555126258Smlaier		return (0xFFFF);
1556126258Smlaier	return (l);
1557126258Smlaier}
1558126258Smlaier
1559126258Smlaiervoid
1560126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1561126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1562126258Smlaier{
1563126258Smlaier	struct pf_addr	ao;
1564126258Smlaier	u_int16_t	po = *p;
1565126258Smlaier
1566126258Smlaier	PF_ACPY(&ao, a, af);
1567126258Smlaier	PF_ACPY(a, an, af);
1568126258Smlaier
1569126258Smlaier	*p = pn;
1570126258Smlaier
1571126258Smlaier	switch (af) {
1572126258Smlaier#ifdef INET
1573126258Smlaier	case AF_INET:
1574126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1575126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1576126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1577126258Smlaier		*p = pn;
1578126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1579126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1580126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1581126258Smlaier		    po, pn, u);
1582126258Smlaier		break;
1583126258Smlaier#endif /* INET */
1584126258Smlaier#ifdef INET6
1585126258Smlaier	case AF_INET6:
1586126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1587126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1588126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1589126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1590126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1591126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1592126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1593126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1594126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1595126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1596126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1597126258Smlaier		    po, pn, u);
1598126258Smlaier		break;
1599126258Smlaier#endif /* INET6 */
1600126258Smlaier	}
1601126258Smlaier}
1602126258Smlaier
1603126258Smlaier
1604126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1605126258Smlaiervoid
1606126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1607126258Smlaier{
1608126258Smlaier	u_int32_t	ao;
1609126258Smlaier
1610126258Smlaier	memcpy(&ao, a, sizeof(ao));
1611126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1612126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1613126258Smlaier	    ao % 65536, an % 65536, u);
1614126258Smlaier}
1615126258Smlaier
1616126258Smlaier#ifdef INET6
1617126258Smlaiervoid
1618126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1619126258Smlaier{
1620126258Smlaier	struct pf_addr	ao;
1621126258Smlaier
1622126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1623126258Smlaier	PF_ACPY(a, an, AF_INET6);
1624126258Smlaier
1625126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1626126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1627126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1628126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1629126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1630126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1631126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1632126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1633126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1634126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1635126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1636126258Smlaier}
1637126258Smlaier#endif /* INET6 */
1638126258Smlaier
1639126258Smlaiervoid
1640126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1641126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1642126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1643126258Smlaier{
1644126258Smlaier	struct pf_addr	oia, ooa;
1645126258Smlaier
1646126258Smlaier	PF_ACPY(&oia, ia, af);
1647126258Smlaier	PF_ACPY(&ooa, oa, af);
1648126258Smlaier
1649126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1650126258Smlaier	if (ip != NULL) {
1651126258Smlaier		u_int16_t	oip = *ip;
1652127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1653126258Smlaier
1654126258Smlaier		if (pc != NULL)
1655126258Smlaier			opc = *pc;
1656126258Smlaier		*ip = np;
1657126258Smlaier		if (pc != NULL)
1658126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1659126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1660126258Smlaier		if (pc != NULL)
1661126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1662126258Smlaier	}
1663126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1664126258Smlaier	PF_ACPY(ia, na, af);
1665126258Smlaier	switch (af) {
1666126258Smlaier#ifdef INET
1667126258Smlaier	case AF_INET: {
1668126258Smlaier		u_int32_t	 oh2c = *h2c;
1669126258Smlaier
1670126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1671126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1672126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1673126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1674126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1675126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1676126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1677126258Smlaier		break;
1678126258Smlaier	}
1679126258Smlaier#endif /* INET */
1680126258Smlaier#ifdef INET6
1681126258Smlaier	case AF_INET6:
1682126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1683126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1684126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1685126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1686126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1687126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1688126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1689126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1690126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1691126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1692126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1693126258Smlaier		break;
1694126258Smlaier#endif /* INET6 */
1695126258Smlaier	}
1696126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1697126258Smlaier	PF_ACPY(oa, na, af);
1698126258Smlaier	switch (af) {
1699126258Smlaier#ifdef INET
1700126258Smlaier	case AF_INET:
1701126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1702126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1703126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1704126258Smlaier		break;
1705126258Smlaier#endif /* INET */
1706126258Smlaier#ifdef INET6
1707126258Smlaier	case AF_INET6:
1708126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1709126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1710126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1711126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1712126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1713126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1714126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1715126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1716126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1717126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1718126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1719126258Smlaier		break;
1720126258Smlaier#endif /* INET6 */
1721126258Smlaier	}
1722126258Smlaier}
1723126258Smlaier
1724171168Smlaier
1725171168Smlaier/*
1726171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option
1727171168Smlaier * (credits to Krzysztof Pfaff for report and patch)
1728171168Smlaier */
1729171168Smlaierint
1730171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
1731171168Smlaier    struct tcphdr *th, struct pf_state_peer *dst)
1732171168Smlaier{
1733171168Smlaier	int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
1734171168Smlaier#ifdef __FreeBSD__
1735171168Smlaier	u_int8_t opts[TCP_MAXOLEN], *opt = opts;
1736171168Smlaier#else
1737171168Smlaier	u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
1738171168Smlaier#endif
1739171168Smlaier	int copyback = 0, i, olen;
1740171168Smlaier	struct sackblk sack;
1741171168Smlaier
1742171168Smlaier#define TCPOLEN_SACKLEN	(TCPOLEN_SACK + 2)
1743171168Smlaier	if (hlen < TCPOLEN_SACKLEN ||
1744171168Smlaier	    !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
1745171168Smlaier		return 0;
1746171168Smlaier
1747171168Smlaier	while (hlen >= TCPOLEN_SACKLEN) {
1748171168Smlaier		olen = opt[1];
1749171168Smlaier		switch (*opt) {
1750171168Smlaier		case TCPOPT_EOL:	/* FALLTHROUGH */
1751171168Smlaier		case TCPOPT_NOP:
1752171168Smlaier			opt++;
1753171168Smlaier			hlen--;
1754171168Smlaier			break;
1755171168Smlaier		case TCPOPT_SACK:
1756171168Smlaier			if (olen > hlen)
1757171168Smlaier				olen = hlen;
1758171168Smlaier			if (olen >= TCPOLEN_SACKLEN) {
1759171168Smlaier				for (i = 2; i + TCPOLEN_SACK <= olen;
1760171168Smlaier				    i += TCPOLEN_SACK) {
1761171168Smlaier					memcpy(&sack, &opt[i], sizeof(sack));
1762171168Smlaier					pf_change_a(&sack.start, &th->th_sum,
1763171168Smlaier					    htonl(ntohl(sack.start) -
1764171168Smlaier					    dst->seqdiff), 0);
1765171168Smlaier					pf_change_a(&sack.end, &th->th_sum,
1766171168Smlaier					    htonl(ntohl(sack.end) -
1767171168Smlaier					    dst->seqdiff), 0);
1768171168Smlaier					memcpy(&opt[i], &sack, sizeof(sack));
1769171168Smlaier				}
1770171168Smlaier				copyback = 1;
1771171168Smlaier			}
1772171168Smlaier			/* FALLTHROUGH */
1773171168Smlaier		default:
1774171168Smlaier			if (olen < 2)
1775171168Smlaier				olen = 2;
1776171168Smlaier			hlen -= olen;
1777171168Smlaier			opt += olen;
1778171168Smlaier		}
1779171168Smlaier	}
1780171168Smlaier
1781171168Smlaier	if (copyback)
1782171168Smlaier#ifdef __FreeBSD__
1783171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts);
1784171168Smlaier#else
1785171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, opts);
1786171168Smlaier#endif
1787171168Smlaier	return (copyback);
1788171168Smlaier}
1789171168Smlaier
1790126258Smlaiervoid
1791162238Scsjp#ifdef __FreeBSD__
1792162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
1793162238Scsjp#else
1794126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1795162238Scsjp#endif
1796126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1797126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1798145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1799171168Smlaier    u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
1800126258Smlaier{
1801126258Smlaier	struct mbuf	*m;
1802171168Smlaier	int		 len, tlen;
1803126258Smlaier#ifdef INET
1804171168Smlaier	struct ip	*h;
1805126258Smlaier#endif /* INET */
1806126258Smlaier#ifdef INET6
1807171168Smlaier	struct ip6_hdr	*h6;
1808126258Smlaier#endif /* INET6 */
1809171168Smlaier	struct tcphdr	*th;
1810171168Smlaier	char		*opt;
1811171168Smlaier	struct pf_mtag	*pf_mtag;
1812126258Smlaier
1813171168Smlaier#ifdef __FreeBSD__
1814171168Smlaier	KASSERT(
1815171168Smlaier#ifdef INET
1816171168Smlaier	    af == AF_INET
1817171168Smlaier#else
1818171168Smlaier	    0
1819171168Smlaier#endif
1820171168Smlaier	    ||
1821171168Smlaier#ifdef INET6
1822171168Smlaier	    af == AF_INET6
1823171168Smlaier#else
1824171168Smlaier	    0
1825171168Smlaier#endif
1826171168Smlaier	    , ("Unsupported AF %d", af));
1827171168Smlaier	len = 0;
1828171168Smlaier	th = NULL;
1829171168Smlaier#ifdef INET
1830171168Smlaier	h = NULL;
1831171168Smlaier#endif
1832171168Smlaier#ifdef INET6
1833171168Smlaier	h6 = NULL;
1834171168Smlaier#endif
1835171168Smlaier#endif
1836171168Smlaier
1837126258Smlaier	/* maximum segment size tcp option */
1838126258Smlaier	tlen = sizeof(struct tcphdr);
1839126258Smlaier	if (mss)
1840126258Smlaier		tlen += 4;
1841126258Smlaier
1842126258Smlaier	switch (af) {
1843126258Smlaier#ifdef INET
1844126258Smlaier	case AF_INET:
1845126258Smlaier		len = sizeof(struct ip) + tlen;
1846126258Smlaier		break;
1847126258Smlaier#endif /* INET */
1848126258Smlaier#ifdef INET6
1849126258Smlaier	case AF_INET6:
1850126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1851126258Smlaier		break;
1852126258Smlaier#endif /* INET6 */
1853126258Smlaier	}
1854126258Smlaier
1855126258Smlaier	/* create outgoing mbuf */
1856132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1857132280Smlaier	if (m == NULL)
1858132280Smlaier		return;
1859162238Scsjp#ifdef __FreeBSD__
1860162238Scsjp#ifdef MAC
1861162238Scsjp	if (replyto)
1862173102Srwatson		mac_netinet_firewall_reply(replyto, m);
1863162238Scsjp	else
1864173018Srwatson		mac_netinet_firewall_send(m);
1865162238Scsjp#else
1866162238Scsjp	(void)replyto;
1867162238Scsjp#endif
1868162238Scsjp#endif
1869171168Smlaier	if ((pf_mtag = pf_get_mtag(m)) == NULL) {
1870171168Smlaier		m_freem(m);
1871171168Smlaier		return;
1872171168Smlaier	}
1873171168Smlaier	if (tag)
1874145836Smlaier#ifdef __FreeBSD__
1875145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1876132280Smlaier#else
1877171168Smlaier		pf_mtag->flags |= PF_TAG_GENERATED;
1878171168Smlaier#endif
1879145836Smlaier
1880171168Smlaier	pf_mtag->tag = rtag;
1881171168Smlaier
1882171168Smlaier	if (r != NULL && r->rtableid >= 0)
1883178888Sjulian#ifdef __FreeBSD__
1884178888Sjulian	{
1885178888Sjulian		M_SETFIB(m, r->rtableid);
1886178888Sjulian#endif
1887171168Smlaier		pf_mtag->rtableid = r->rtableid;
1888178888Sjulian#ifdef __FreeBSD__
1889178888Sjulian	}
1890178888Sjulian#endif
1891126258Smlaier#ifdef ALTQ
1892126258Smlaier	if (r != NULL && r->qid) {
1893171168Smlaier		pf_mtag->qid = r->qid;
1894171168Smlaier		/* add hints for ecn */
1895171168Smlaier		pf_mtag->af = af;
1896171168Smlaier		pf_mtag->hdr = mtod(m, struct ip *);
1897126258Smlaier	}
1898145836Smlaier#endif /* ALTQ */
1899126258Smlaier	m->m_data += max_linkhdr;
1900126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1901126258Smlaier	m->m_pkthdr.rcvif = NULL;
1902126258Smlaier	bzero(m->m_data, len);
1903126258Smlaier	switch (af) {
1904126258Smlaier#ifdef INET
1905126258Smlaier	case AF_INET:
1906126258Smlaier		h = mtod(m, struct ip *);
1907126258Smlaier
1908126258Smlaier		/* IP header fields included in the TCP checksum */
1909126258Smlaier		h->ip_p = IPPROTO_TCP;
1910126258Smlaier		h->ip_len = htons(tlen);
1911126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1912126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1913126258Smlaier
1914126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1915126258Smlaier		break;
1916126258Smlaier#endif /* INET */
1917126258Smlaier#ifdef INET6
1918126258Smlaier	case AF_INET6:
1919126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1920126258Smlaier
1921126258Smlaier		/* IP header fields included in the TCP checksum */
1922126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1923126258Smlaier		h6->ip6_plen = htons(tlen);
1924126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1925126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1926126258Smlaier
1927126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1928126258Smlaier		break;
1929126258Smlaier#endif /* INET6 */
1930126258Smlaier	}
1931126258Smlaier
1932126258Smlaier	/* TCP header */
1933126258Smlaier	th->th_sport = sport;
1934126258Smlaier	th->th_dport = dport;
1935126258Smlaier	th->th_seq = htonl(seq);
1936126258Smlaier	th->th_ack = htonl(ack);
1937126258Smlaier	th->th_off = tlen >> 2;
1938126258Smlaier	th->th_flags = flags;
1939126258Smlaier	th->th_win = htons(win);
1940126258Smlaier
1941126258Smlaier	if (mss) {
1942126258Smlaier		opt = (char *)(th + 1);
1943126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1944126258Smlaier		opt[1] = 4;
1945126258Smlaier		HTONS(mss);
1946126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1947126258Smlaier	}
1948126258Smlaier
1949126258Smlaier	switch (af) {
1950126258Smlaier#ifdef INET
1951126258Smlaier	case AF_INET:
1952126258Smlaier		/* TCP checksum */
1953126258Smlaier		th->th_sum = in_cksum(m, len);
1954126258Smlaier
1955126258Smlaier		/* Finish the IP header */
1956126258Smlaier		h->ip_v = 4;
1957126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1958126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1959127145Smlaier#ifdef __FreeBSD__
1960181803Sbz		h->ip_off = V_path_mtu_discovery ? IP_DF : 0;
1961130613Smlaier		h->ip_len = len;
1962126261Smlaier#else
1963126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1964130613Smlaier		h->ip_len = htons(len);
1965126261Smlaier#endif
1966181803Sbz		h->ip_ttl = ttl ? ttl : V_ip_defttl;
1967126258Smlaier		h->ip_sum = 0;
1968145836Smlaier		if (eh == NULL) {
1969127145Smlaier#ifdef __FreeBSD__
1970145836Smlaier			PF_UNLOCK();
1971145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1972145836Smlaier			    (void *)NULL, (void *)NULL);
1973145836Smlaier			PF_LOCK();
1974126261Smlaier#else /* ! __FreeBSD__ */
1975145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1976145836Smlaier			    (void *)NULL, (void *)NULL);
1977126261Smlaier#endif
1978145836Smlaier		} else {
1979145836Smlaier			struct route		 ro;
1980145836Smlaier			struct rtentry		 rt;
1981145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1982145836Smlaier
1983145836Smlaier			if (ifp == NULL) {
1984145836Smlaier				m_freem(m);
1985145836Smlaier				return;
1986145836Smlaier			}
1987145836Smlaier			rt.rt_ifp = ifp;
1988145836Smlaier			ro.ro_rt = &rt;
1989145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1990145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1991145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1992145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1993145836Smlaier			e->ether_type = eh->ether_type;
1994145836Smlaier#ifdef __FreeBSD__
1995145836Smlaier			PF_UNLOCK();
1996145836Smlaier			/* XXX_IMPORT: later */
1997145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1998145836Smlaier			    (void *)NULL, (void *)NULL);
1999145836Smlaier			PF_LOCK();
2000145836Smlaier#else /* ! __FreeBSD__ */
2001145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
2002145836Smlaier			    (void *)NULL, (void *)NULL);
2003145836Smlaier#endif
2004145836Smlaier		}
2005126258Smlaier		break;
2006126258Smlaier#endif /* INET */
2007126258Smlaier#ifdef INET6
2008126258Smlaier	case AF_INET6:
2009126258Smlaier		/* TCP checksum */
2010126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
2011126258Smlaier		    sizeof(struct ip6_hdr), tlen);
2012126258Smlaier
2013126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
2014126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
2015126258Smlaier
2016127145Smlaier#ifdef __FreeBSD__
2017126261Smlaier		PF_UNLOCK();
2018126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
2019126261Smlaier		PF_LOCK();
2020126261Smlaier#else
2021126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
2022126261Smlaier#endif
2023126258Smlaier		break;
2024126258Smlaier#endif /* INET6 */
2025126258Smlaier	}
2026126258Smlaier}
2027126258Smlaier
2028126258Smlaiervoid
2029126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
2030126258Smlaier    struct pf_rule *r)
2031126258Smlaier{
2032171168Smlaier	struct pf_mtag	*pf_mtag;
2033126258Smlaier	struct mbuf	*m0;
2034127145Smlaier#ifdef __FreeBSD__
2035126261Smlaier	struct ip *ip;
2036126261Smlaier#endif
2037126258Smlaier
2038132280Smlaier#ifdef __FreeBSD__
2039132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
2040132280Smlaier	if (m0 == NULL)
2041132280Smlaier		return;
2042132280Smlaier#else
2043126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
2044171168Smlaier#endif
2045171168Smlaier	if ((pf_mtag = pf_get_mtag(m0)) == NULL)
2046126258Smlaier		return;
2047171168Smlaier#ifdef __FreeBSD__
2048171168Smlaier	/* XXX: revisit */
2049171168Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
2050171168Smlaier#else
2051171168Smlaier	pf_mtag->flags |= PF_TAG_GENERATED;
2052132280Smlaier#endif
2053126258Smlaier
2054171168Smlaier	if (r->rtableid >= 0)
2055178888Sjulian#ifdef __FreeBSD__
2056178888Sjulian	{
2057178888Sjulian		M_SETFIB(m0, r->rtableid);
2058178888Sjulian#endif
2059171168Smlaier		pf_mtag->rtableid = r->rtableid;
2060178888Sjulian#ifdef __FreeBSD__
2061178888Sjulian	}
2062178888Sjulian#endif
2063171168Smlaier
2064126258Smlaier#ifdef ALTQ
2065126258Smlaier	if (r->qid) {
2066171168Smlaier		pf_mtag->qid = r->qid;
2067171168Smlaier		/* add hints for ecn */
2068171168Smlaier		pf_mtag->af = af;
2069171168Smlaier		pf_mtag->hdr = mtod(m0, struct ip *);
2070126258Smlaier	}
2071145836Smlaier#endif /* ALTQ */
2072126258Smlaier
2073126258Smlaier	switch (af) {
2074126258Smlaier#ifdef INET
2075126258Smlaier	case AF_INET:
2076127145Smlaier#ifdef __FreeBSD__
2077126261Smlaier		/* icmp_error() expects host byte ordering */
2078126261Smlaier		ip = mtod(m0, struct ip *);
2079126261Smlaier		NTOHS(ip->ip_len);
2080126261Smlaier		NTOHS(ip->ip_off);
2081126261Smlaier		PF_UNLOCK();
2082145863Sandre		icmp_error(m0, type, code, 0, 0);
2083126261Smlaier		PF_LOCK();
2084145874Smlaier#else
2085171168Smlaier		icmp_error(m0, type, code, 0, 0);
2086126261Smlaier#endif
2087126258Smlaier		break;
2088126258Smlaier#endif /* INET */
2089126258Smlaier#ifdef INET6
2090126258Smlaier	case AF_INET6:
2091127145Smlaier#ifdef __FreeBSD__
2092126261Smlaier		PF_UNLOCK();
2093126261Smlaier#endif
2094126258Smlaier		icmp6_error(m0, type, code, 0);
2095127145Smlaier#ifdef __FreeBSD__
2096126261Smlaier		PF_LOCK();
2097126261Smlaier#endif
2098126258Smlaier		break;
2099126258Smlaier#endif /* INET6 */
2100126258Smlaier	}
2101126258Smlaier}
2102126258Smlaier
2103126258Smlaier/*
2104126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
2105126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
2106126258Smlaier * are different.
2107126258Smlaier */
2108126258Smlaierint
2109126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
2110126258Smlaier    struct pf_addr *b, sa_family_t af)
2111126258Smlaier{
2112126258Smlaier	int	match = 0;
2113126258Smlaier
2114126258Smlaier	switch (af) {
2115126258Smlaier#ifdef INET
2116126258Smlaier	case AF_INET:
2117126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
2118126258Smlaier		    (b->addr32[0] & m->addr32[0]))
2119126258Smlaier			match++;
2120126258Smlaier		break;
2121126258Smlaier#endif /* INET */
2122126258Smlaier#ifdef INET6
2123126258Smlaier	case AF_INET6:
2124126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
2125126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
2126126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
2127126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
2128126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
2129126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
2130126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
2131126258Smlaier		     (b->addr32[3] & m->addr32[3])))
2132126258Smlaier			match++;
2133126258Smlaier		break;
2134126258Smlaier#endif /* INET6 */
2135126258Smlaier	}
2136126258Smlaier	if (match) {
2137126258Smlaier		if (n)
2138126258Smlaier			return (0);
2139126258Smlaier		else
2140126258Smlaier			return (1);
2141126258Smlaier	} else {
2142126258Smlaier		if (n)
2143126258Smlaier			return (1);
2144126258Smlaier		else
2145126258Smlaier			return (0);
2146126258Smlaier	}
2147126258Smlaier}
2148126258Smlaier
2149126258Smlaierint
2150126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
2151126258Smlaier{
2152126258Smlaier	switch (op) {
2153126258Smlaier	case PF_OP_IRG:
2154126258Smlaier		return ((p > a1) && (p < a2));
2155126258Smlaier	case PF_OP_XRG:
2156126258Smlaier		return ((p < a1) || (p > a2));
2157126258Smlaier	case PF_OP_RRG:
2158126258Smlaier		return ((p >= a1) && (p <= a2));
2159126258Smlaier	case PF_OP_EQ:
2160126258Smlaier		return (p == a1);
2161126258Smlaier	case PF_OP_NE:
2162126258Smlaier		return (p != a1);
2163126258Smlaier	case PF_OP_LT:
2164126258Smlaier		return (p < a1);
2165126258Smlaier	case PF_OP_LE:
2166126258Smlaier		return (p <= a1);
2167126258Smlaier	case PF_OP_GT:
2168126258Smlaier		return (p > a1);
2169126258Smlaier	case PF_OP_GE:
2170126258Smlaier		return (p >= a1);
2171126258Smlaier	}
2172126258Smlaier	return (0); /* never reached */
2173126258Smlaier}
2174126258Smlaier
2175126258Smlaierint
2176126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
2177126258Smlaier{
2178126258Smlaier	NTOHS(a1);
2179126258Smlaier	NTOHS(a2);
2180126258Smlaier	NTOHS(p);
2181126258Smlaier	return (pf_match(op, a1, a2, p));
2182126258Smlaier}
2183126258Smlaier
2184126258Smlaierint
2185126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
2186126258Smlaier{
2187126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2188126258Smlaier		return (0);
2189126258Smlaier	return (pf_match(op, a1, a2, u));
2190126258Smlaier}
2191126258Smlaier
2192126258Smlaierint
2193126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
2194126258Smlaier{
2195126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2196126258Smlaier		return (0);
2197126258Smlaier	return (pf_match(op, a1, a2, g));
2198126258Smlaier}
2199126258Smlaier
2200171168Smlaier#ifndef __FreeBSD__
2201171168Smlaierstruct pf_mtag *
2202171168Smlaierpf_find_mtag(struct mbuf *m)
2203126258Smlaier{
2204126258Smlaier	struct m_tag	*mtag;
2205126258Smlaier
2206171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
2207126258Smlaier		return (NULL);
2208171168Smlaier
2209171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2210126258Smlaier}
2211126258Smlaier
2212171168Smlaierstruct pf_mtag *
2213171168Smlaierpf_get_mtag(struct mbuf *m)
2214126258Smlaier{
2215171168Smlaier	struct m_tag	*mtag;
2216171168Smlaier
2217171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
2218171168Smlaier		mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
2219171168Smlaier		    M_NOWAIT);
2220171168Smlaier		if (mtag == NULL)
2221171168Smlaier			return (NULL);
2222171168Smlaier		bzero(mtag + 1, sizeof(struct pf_mtag));
2223171168Smlaier		m_tag_prepend(m, mtag);
2224126258Smlaier	}
2225126258Smlaier
2226171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2227171168Smlaier}
2228171168Smlaier#endif
2229171168Smlaier
2230171168Smlaierint
2231171168Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
2232171168Smlaier    int *tag)
2233171168Smlaier{
2234171168Smlaier	if (*tag == -1)
2235171168Smlaier		*tag = pf_mtag->tag;
2236171168Smlaier
2237126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
2238126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
2239126258Smlaier}
2240126258Smlaier
2241126258Smlaierint
2242171168Smlaierpf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
2243126258Smlaier{
2244171168Smlaier	if (tag <= 0 && rtableid < 0)
2245126258Smlaier		return (0);
2246126258Smlaier
2247171168Smlaier	if (pf_mtag == NULL)
2248171168Smlaier		if ((pf_mtag = pf_get_mtag(m)) == NULL)
2249126258Smlaier			return (1);
2250171168Smlaier	if (tag > 0)
2251171168Smlaier		pf_mtag->tag = tag;
2252171168Smlaier	if (rtableid >= 0)
2253178888Sjulian#ifdef __FreeBSD__
2254178888Sjulian	{
2255178888Sjulian		M_SETFIB(m, rtableid);
2256178888Sjulian#endif
2257171168Smlaier		pf_mtag->rtableid = rtableid;
2258178888Sjulian#ifdef __FreeBSD__
2259178888Sjulian	}
2260178888Sjulian#endif
2261126258Smlaier
2262126258Smlaier	return (0);
2263126258Smlaier}
2264126258Smlaier
2265145836Smlaierstatic void
2266145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
2267171168Smlaier    struct pf_rule **r, struct pf_rule **a,  int *match)
2268145836Smlaier{
2269145836Smlaier	struct pf_anchor_stackframe	*f;
2270126258Smlaier
2271171168Smlaier	(*r)->anchor->match = 0;
2272171168Smlaier	if (match)
2273171168Smlaier		*match = 0;
2274145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
2275145836Smlaier	    sizeof(pf_anchor_stack[0])) {
2276145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
2277145836Smlaier		*r = TAILQ_NEXT(*r, entries);
2278145836Smlaier		return;
2279145836Smlaier	} else if (*depth == 0 && a != NULL)
2280145836Smlaier		*a = *r;
2281145836Smlaier	f = pf_anchor_stack + (*depth)++;
2282145836Smlaier	f->rs = *rs;
2283145836Smlaier	f->r = *r;
2284145836Smlaier	if ((*r)->anchor_wildcard) {
2285145836Smlaier		f->parent = &(*r)->anchor->children;
2286145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2287145836Smlaier		    NULL) {
2288145836Smlaier			*r = NULL;
2289145836Smlaier			return;
2290145836Smlaier		}
2291145836Smlaier		*rs = &f->child->ruleset;
2292145836Smlaier	} else {
2293145836Smlaier		f->parent = NULL;
2294145836Smlaier		f->child = NULL;
2295145836Smlaier		*rs = &(*r)->anchor->ruleset;
2296145836Smlaier	}
2297145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2298145836Smlaier}
2299126258Smlaier
2300171168Smlaierint
2301145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2302171168Smlaier    struct pf_rule **r, struct pf_rule **a, int *match)
2303145836Smlaier{
2304145836Smlaier	struct pf_anchor_stackframe	*f;
2305171168Smlaier	int quick = 0;
2306145836Smlaier
2307145836Smlaier	do {
2308145836Smlaier		if (*depth <= 0)
2309145836Smlaier			break;
2310145836Smlaier		f = pf_anchor_stack + *depth - 1;
2311145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2312171168Smlaier			if (f->child->match ||
2313171168Smlaier			    (match != NULL && *match)) {
2314171168Smlaier				f->r->anchor->match = 1;
2315171168Smlaier				*match = 0;
2316171168Smlaier			}
2317145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2318145836Smlaier			if (f->child != NULL) {
2319145836Smlaier				*rs = &f->child->ruleset;
2320145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2321145836Smlaier				if (*r == NULL)
2322145836Smlaier					continue;
2323145836Smlaier				else
2324145836Smlaier					break;
2325145836Smlaier			}
2326145836Smlaier		}
2327145836Smlaier		(*depth)--;
2328145836Smlaier		if (*depth == 0 && a != NULL)
2329145836Smlaier			*a = NULL;
2330145836Smlaier		*rs = f->rs;
2331171168Smlaier		if (f->r->anchor->match || (match  != NULL && *match))
2332171168Smlaier			quick = f->r->quick;
2333145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2334145836Smlaier	} while (*r == NULL);
2335171168Smlaier
2336171168Smlaier	return (quick);
2337145836Smlaier}
2338145836Smlaier
2339126258Smlaier#ifdef INET6
2340126258Smlaiervoid
2341126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2342126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2343126258Smlaier{
2344126258Smlaier	switch (af) {
2345126258Smlaier#ifdef INET
2346126258Smlaier	case AF_INET:
2347126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2348126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2349126258Smlaier		break;
2350126258Smlaier#endif /* INET */
2351126258Smlaier	case AF_INET6:
2352126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2353126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2354126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2355126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2356126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2357126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2358126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2359126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2360126258Smlaier		break;
2361126258Smlaier	}
2362126258Smlaier}
2363126258Smlaier
2364126258Smlaiervoid
2365130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2366126258Smlaier{
2367126258Smlaier	switch (af) {
2368126258Smlaier#ifdef INET
2369126258Smlaier	case AF_INET:
2370126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2371126258Smlaier		break;
2372126258Smlaier#endif /* INET */
2373126258Smlaier	case AF_INET6:
2374126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2375126258Smlaier			addr->addr32[3] = 0;
2376126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2377126258Smlaier				addr->addr32[2] = 0;
2378126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2379126258Smlaier					addr->addr32[1] = 0;
2380126258Smlaier					addr->addr32[0] =
2381126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2382126258Smlaier				} else
2383126258Smlaier					addr->addr32[1] =
2384126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2385126258Smlaier			} else
2386126258Smlaier				addr->addr32[2] =
2387126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2388126258Smlaier		} else
2389126258Smlaier			addr->addr32[3] =
2390126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2391126258Smlaier		break;
2392126258Smlaier	}
2393126258Smlaier}
2394126258Smlaier#endif /* INET6 */
2395126258Smlaier
2396126258Smlaier#define mix(a,b,c) \
2397126258Smlaier	do {					\
2398126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2399126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2400126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2401126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2402126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2403126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2404126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2405126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2406126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2407126258Smlaier	} while (0)
2408126258Smlaier
2409126258Smlaier/*
2410126258Smlaier * hash function based on bridge_hash in if_bridge.c
2411126258Smlaier */
2412126258Smlaiervoid
2413126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2414126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2415126258Smlaier{
2416126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2417126258Smlaier
2418126258Smlaier	switch (af) {
2419126258Smlaier#ifdef INET
2420126258Smlaier	case AF_INET:
2421126258Smlaier		a += inaddr->addr32[0];
2422126258Smlaier		b += key->key32[1];
2423126258Smlaier		mix(a, b, c);
2424126258Smlaier		hash->addr32[0] = c + key->key32[2];
2425126258Smlaier		break;
2426126258Smlaier#endif /* INET */
2427126258Smlaier#ifdef INET6
2428126258Smlaier	case AF_INET6:
2429126258Smlaier		a += inaddr->addr32[0];
2430126258Smlaier		b += inaddr->addr32[2];
2431126258Smlaier		mix(a, b, c);
2432126258Smlaier		hash->addr32[0] = c;
2433126258Smlaier		a += inaddr->addr32[1];
2434126258Smlaier		b += inaddr->addr32[3];
2435126258Smlaier		c += key->key32[1];
2436126258Smlaier		mix(a, b, c);
2437126258Smlaier		hash->addr32[1] = c;
2438126258Smlaier		a += inaddr->addr32[2];
2439126258Smlaier		b += inaddr->addr32[1];
2440126258Smlaier		c += key->key32[2];
2441126258Smlaier		mix(a, b, c);
2442126258Smlaier		hash->addr32[2] = c;
2443126258Smlaier		a += inaddr->addr32[3];
2444126258Smlaier		b += inaddr->addr32[0];
2445126258Smlaier		c += key->key32[3];
2446126258Smlaier		mix(a, b, c);
2447126258Smlaier		hash->addr32[3] = c;
2448126258Smlaier		break;
2449126258Smlaier#endif /* INET6 */
2450126258Smlaier	}
2451126258Smlaier}
2452126258Smlaier
2453126258Smlaierint
2454130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2455130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2456126258Smlaier{
2457126258Smlaier	unsigned char		 hash[16];
2458130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2459130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2460130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2461126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2462130613Smlaier	struct pf_src_node	 k;
2463126258Smlaier
2464130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2465130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2466130613Smlaier		k.af = af;
2467130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2468130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2469130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2470130613Smlaier			k.rule.ptr = r;
2471130613Smlaier		else
2472130613Smlaier			k.rule.ptr = NULL;
2473130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2474130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2475130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2476130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2477130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2478130613Smlaier				printf("pf_map_addr: src tracking maps ");
2479130613Smlaier				pf_print_host(&k.addr, 0, af);
2480130613Smlaier				printf(" to ");
2481130613Smlaier				pf_print_host(naddr, 0, af);
2482130613Smlaier				printf("\n");
2483130613Smlaier			}
2484130613Smlaier			return (0);
2485130613Smlaier		}
2486130613Smlaier	}
2487130613Smlaier
2488126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2489126258Smlaier		return (1);
2490130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2491145836Smlaier		switch (af) {
2492145836Smlaier#ifdef INET
2493145836Smlaier		case AF_INET:
2494130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2495130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2496130613Smlaier			    PF_POOL_ROUNDROBIN)
2497130613Smlaier				return (1);
2498130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2499130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2500145836Smlaier			break;
2501145836Smlaier#endif /* INET */
2502145836Smlaier#ifdef INET6
2503145836Smlaier		case AF_INET6:
2504130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2505130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2506130613Smlaier			    PF_POOL_ROUNDROBIN)
2507130613Smlaier				return (1);
2508130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2509130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2510145836Smlaier			break;
2511145836Smlaier#endif /* INET6 */
2512130613Smlaier		}
2513130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2514126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2515126258Smlaier			return (1); /* unsupported */
2516126258Smlaier	} else {
2517126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2518126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2519126258Smlaier	}
2520126258Smlaier
2521126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2522126258Smlaier	case PF_POOL_NONE:
2523126258Smlaier		PF_ACPY(naddr, raddr, af);
2524126258Smlaier		break;
2525126258Smlaier	case PF_POOL_BITMASK:
2526126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2527126258Smlaier		break;
2528126258Smlaier	case PF_POOL_RANDOM:
2529126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2530126258Smlaier			switch (af) {
2531126258Smlaier#ifdef INET
2532126258Smlaier			case AF_INET:
2533145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2534126258Smlaier				break;
2535126258Smlaier#endif /* INET */
2536126258Smlaier#ifdef INET6
2537126258Smlaier			case AF_INET6:
2538126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2539145836Smlaier					rpool->counter.addr32[3] =
2540145836Smlaier					    htonl(arc4random());
2541126258Smlaier				else
2542126258Smlaier					break;
2543126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2544145836Smlaier					rpool->counter.addr32[2] =
2545145836Smlaier					    htonl(arc4random());
2546126258Smlaier				else
2547126258Smlaier					break;
2548126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2549145836Smlaier					rpool->counter.addr32[1] =
2550145836Smlaier					    htonl(arc4random());
2551126258Smlaier				else
2552126258Smlaier					break;
2553126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2554145836Smlaier					rpool->counter.addr32[0] =
2555145836Smlaier					    htonl(arc4random());
2556126258Smlaier				break;
2557126258Smlaier#endif /* INET6 */
2558126258Smlaier			}
2559126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2560126258Smlaier			PF_ACPY(init_addr, naddr, af);
2561126258Smlaier
2562126258Smlaier		} else {
2563126258Smlaier			PF_AINC(&rpool->counter, af);
2564126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2565126258Smlaier		}
2566126258Smlaier		break;
2567126258Smlaier	case PF_POOL_SRCHASH:
2568126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2569126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2570126258Smlaier		break;
2571126258Smlaier	case PF_POOL_ROUNDROBIN:
2572126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2573126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2574126258Smlaier			    &rpool->tblidx, &rpool->counter,
2575126258Smlaier			    &raddr, &rmask, af))
2576126258Smlaier				goto get_addr;
2577130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2578130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2579130613Smlaier			    &rpool->tblidx, &rpool->counter,
2580130613Smlaier			    &raddr, &rmask, af))
2581130613Smlaier				goto get_addr;
2582126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2583126258Smlaier			goto get_addr;
2584126258Smlaier
2585126258Smlaier	try_next:
2586126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2587126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2588126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2589126258Smlaier			rpool->tblidx = -1;
2590126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2591126258Smlaier			    &rpool->tblidx, &rpool->counter,
2592126258Smlaier			    &raddr, &rmask, af)) {
2593130613Smlaier				/* table contains no address of type 'af' */
2594126258Smlaier				if (rpool->cur != acur)
2595126258Smlaier					goto try_next;
2596126258Smlaier				return (1);
2597126258Smlaier			}
2598130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2599130613Smlaier			rpool->tblidx = -1;
2600130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2601130613Smlaier			    &rpool->tblidx, &rpool->counter,
2602130613Smlaier			    &raddr, &rmask, af)) {
2603130613Smlaier				/* table contains no address of type 'af' */
2604130613Smlaier				if (rpool->cur != acur)
2605130613Smlaier					goto try_next;
2606130613Smlaier				return (1);
2607130613Smlaier			}
2608126258Smlaier		} else {
2609126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2610126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2611126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2612126258Smlaier		}
2613126258Smlaier
2614126258Smlaier	get_addr:
2615126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2616139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2617139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2618126258Smlaier		PF_AINC(&rpool->counter, af);
2619126258Smlaier		break;
2620126258Smlaier	}
2621130613Smlaier	if (*sn != NULL)
2622130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2623126258Smlaier
2624126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2625126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2626130613Smlaier		printf("pf_map_addr: selected address ");
2627126258Smlaier		pf_print_host(naddr, 0, af);
2628126258Smlaier		printf("\n");
2629126258Smlaier	}
2630126258Smlaier
2631126258Smlaier	return (0);
2632126258Smlaier}
2633126258Smlaier
2634126258Smlaierint
2635130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2636126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2637130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2638130613Smlaier    struct pf_src_node **sn)
2639126258Smlaier{
2640171168Smlaier	struct pf_state_cmp	key;
2641126258Smlaier	struct pf_addr		init_addr;
2642126258Smlaier	u_int16_t		cut;
2643126258Smlaier
2644126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2645130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2646126258Smlaier		return (1);
2647126258Smlaier
2648149884Smlaier	if (proto == IPPROTO_ICMP) {
2649149884Smlaier		low = 1;
2650149884Smlaier		high = 65535;
2651149884Smlaier	}
2652149884Smlaier
2653126258Smlaier	do {
2654126258Smlaier		key.af = af;
2655126258Smlaier		key.proto = proto;
2656130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2657130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2658130613Smlaier		key.ext.port = dport;
2659126258Smlaier
2660126258Smlaier		/*
2661126258Smlaier		 * port search; start random, step;
2662126258Smlaier		 * similar 2 portloop in in_pcbbind
2663126258Smlaier		 */
2664149884Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
2665149884Smlaier		    proto == IPPROTO_ICMP)) {
2666139045Sdhartmei			key.gwy.port = dport;
2667130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2668126258Smlaier				return (0);
2669126258Smlaier		} else if (low == 0 && high == 0) {
2670130613Smlaier			key.gwy.port = *nport;
2671130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2672126258Smlaier				return (0);
2673126258Smlaier		} else if (low == high) {
2674130613Smlaier			key.gwy.port = htons(low);
2675130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2676126258Smlaier				*nport = htons(low);
2677126258Smlaier				return (0);
2678126258Smlaier			}
2679126258Smlaier		} else {
2680126258Smlaier			u_int16_t tmp;
2681126258Smlaier
2682126258Smlaier			if (low > high) {
2683126258Smlaier				tmp = low;
2684126258Smlaier				low = high;
2685126258Smlaier				high = tmp;
2686126258Smlaier			}
2687126258Smlaier			/* low < high */
2688145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2689126258Smlaier			/* low <= cut <= high */
2690126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2691130613Smlaier				key.gwy.port = htons(tmp);
2692130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2693126258Smlaier				    NULL) {
2694126258Smlaier					*nport = htons(tmp);
2695126258Smlaier					return (0);
2696126258Smlaier				}
2697126258Smlaier			}
2698126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2699130613Smlaier				key.gwy.port = htons(tmp);
2700130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2701126258Smlaier				    NULL) {
2702126258Smlaier					*nport = htons(tmp);
2703126258Smlaier					return (0);
2704126258Smlaier				}
2705126258Smlaier			}
2706126258Smlaier		}
2707126258Smlaier
2708130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2709126258Smlaier		case PF_POOL_RANDOM:
2710126258Smlaier		case PF_POOL_ROUNDROBIN:
2711130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2712126258Smlaier				return (1);
2713126258Smlaier			break;
2714126258Smlaier		case PF_POOL_NONE:
2715126258Smlaier		case PF_POOL_SRCHASH:
2716126258Smlaier		case PF_POOL_BITMASK:
2717126258Smlaier		default:
2718126258Smlaier			return (1);
2719126258Smlaier		}
2720126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2721126258Smlaier
2722126258Smlaier	return (1);					/* none available */
2723126258Smlaier}
2724126258Smlaier
2725126258Smlaierstruct pf_rule *
2726126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2727130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2728126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2729126258Smlaier{
2730145836Smlaier	struct pf_rule		*r, *rm = NULL;
2731126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2732145836Smlaier	int			 tag = -1;
2733171168Smlaier	int			 rtableid = -1;
2734145836Smlaier	int			 asd = 0;
2735126258Smlaier
2736126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2737126258Smlaier	while (r && rm == NULL) {
2738126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2739126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2740126258Smlaier
2741126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2742126258Smlaier			src = &r->dst;
2743126258Smlaier			if (r->rpool.cur != NULL)
2744126258Smlaier				xdst = &r->rpool.cur->addr;
2745126258Smlaier		} else {
2746126258Smlaier			src = &r->src;
2747126258Smlaier			dst = &r->dst;
2748126258Smlaier		}
2749126258Smlaier
2750126258Smlaier		r->evaluations++;
2751171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
2752126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2753126258Smlaier		else if (r->direction && r->direction != direction)
2754126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2755126258Smlaier		else if (r->af && r->af != pd->af)
2756126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2757126258Smlaier		else if (r->proto && r->proto != pd->proto)
2758126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2759171168Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
2760171168Smlaier		    src->neg, kif))
2761126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2762126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2763126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2764126258Smlaier		    src->port[0], src->port[1], sport))
2765126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2766126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2767126258Smlaier		else if (dst != NULL &&
2768171168Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
2769126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2770171168Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
2771171168Smlaier		    0, NULL))
2772126258Smlaier			r = TAILQ_NEXT(r, entries);
2773126258Smlaier		else if (dst != NULL && dst->port_op &&
2774126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2775126258Smlaier		    dst->port[1], dport))
2776126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2777171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
2778145836Smlaier			r = TAILQ_NEXT(r, entries);
2779126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2780126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2781126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2782126258Smlaier			r = TAILQ_NEXT(r, entries);
2783145836Smlaier		else {
2784145836Smlaier			if (r->tag)
2785145836Smlaier				tag = r->tag;
2786171168Smlaier			if (r->rtableid >= 0)
2787171168Smlaier				rtableid = r->rtableid;
2788145836Smlaier			if (r->anchor == NULL) {
2789126258Smlaier				rm = r;
2790145836Smlaier			} else
2791171168Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num,
2792171168Smlaier				    &r, NULL, NULL);
2793145836Smlaier		}
2794145836Smlaier		if (r == NULL)
2795171168Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
2796171168Smlaier			    NULL, NULL);
2797126258Smlaier	}
2798171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
2799145836Smlaier		return (NULL);
2800126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2801126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2802126258Smlaier		return (NULL);
2803126258Smlaier	return (rm);
2804126258Smlaier}
2805126258Smlaier
2806126258Smlaierstruct pf_rule *
2807126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2808130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2809126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2810126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2811126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2812126258Smlaier{
2813126258Smlaier	struct pf_rule	*r = NULL;
2814126258Smlaier
2815126258Smlaier	if (direction == PF_OUT) {
2816130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2817126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2818126258Smlaier		if (r == NULL)
2819130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2820126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2821126258Smlaier	} else {
2822130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2823126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2824126258Smlaier		if (r == NULL)
2825130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2826126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2827126258Smlaier	}
2828126258Smlaier
2829126258Smlaier	if (r != NULL) {
2830126258Smlaier		switch (r->action) {
2831126258Smlaier		case PF_NONAT:
2832126258Smlaier		case PF_NOBINAT:
2833126258Smlaier		case PF_NORDR:
2834126258Smlaier			return (NULL);
2835126258Smlaier		case PF_NAT:
2836130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2837126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2838130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2839126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2840126258Smlaier				    ("pf: NAT proxy port allocation "
2841126258Smlaier				    "(%u-%u) failed\n",
2842126258Smlaier				    r->rpool.proxy_port[0],
2843126258Smlaier				    r->rpool.proxy_port[1]));
2844126258Smlaier				return (NULL);
2845126258Smlaier			}
2846126258Smlaier			break;
2847126258Smlaier		case PF_BINAT:
2848126258Smlaier			switch (direction) {
2849126258Smlaier			case PF_OUT:
2850130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2851145836Smlaier					switch (pd->af) {
2852145836Smlaier#ifdef INET
2853145836Smlaier					case AF_INET:
2854130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2855130613Smlaier						    pfid_acnt4 < 1)
2856130613Smlaier							return (NULL);
2857130613Smlaier						PF_POOLMASK(naddr,
2858130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2859130613Smlaier						    pfid_addr4,
2860130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2861130613Smlaier						    pfid_mask4,
2862130613Smlaier						    saddr, AF_INET);
2863145836Smlaier						break;
2864145836Smlaier#endif /* INET */
2865145836Smlaier#ifdef INET6
2866145836Smlaier					case AF_INET6:
2867130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2868130613Smlaier						    pfid_acnt6 < 1)
2869130613Smlaier							return (NULL);
2870130613Smlaier						PF_POOLMASK(naddr,
2871130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2872130613Smlaier						    pfid_addr6,
2873130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2874130613Smlaier						    pfid_mask6,
2875130613Smlaier						    saddr, AF_INET6);
2876145836Smlaier						break;
2877145836Smlaier#endif /* INET6 */
2878130613Smlaier					}
2879130613Smlaier				} else
2880126258Smlaier					PF_POOLMASK(naddr,
2881126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2882126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2883126258Smlaier					    saddr, pd->af);
2884126258Smlaier				break;
2885126258Smlaier			case PF_IN:
2886138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2887145836Smlaier					switch (pd->af) {
2888145836Smlaier#ifdef INET
2889145836Smlaier					case AF_INET:
2890130613Smlaier						if (r->src.addr.p.dyn->
2891130613Smlaier						    pfid_acnt4 < 1)
2892130613Smlaier							return (NULL);
2893130613Smlaier						PF_POOLMASK(naddr,
2894130613Smlaier						    &r->src.addr.p.dyn->
2895130613Smlaier						    pfid_addr4,
2896130613Smlaier						    &r->src.addr.p.dyn->
2897130613Smlaier						    pfid_mask4,
2898130613Smlaier						    daddr, AF_INET);
2899145836Smlaier						break;
2900145836Smlaier#endif /* INET */
2901145836Smlaier#ifdef INET6
2902145836Smlaier					case AF_INET6:
2903130613Smlaier						if (r->src.addr.p.dyn->
2904130613Smlaier						    pfid_acnt6 < 1)
2905130613Smlaier							return (NULL);
2906130613Smlaier						PF_POOLMASK(naddr,
2907130613Smlaier						    &r->src.addr.p.dyn->
2908130613Smlaier						    pfid_addr6,
2909130613Smlaier						    &r->src.addr.p.dyn->
2910130613Smlaier						    pfid_mask6,
2911130613Smlaier						    daddr, AF_INET6);
2912145836Smlaier						break;
2913145836Smlaier#endif /* INET6 */
2914130613Smlaier					}
2915130613Smlaier				} else
2916126258Smlaier					PF_POOLMASK(naddr,
2917126258Smlaier					    &r->src.addr.v.a.addr,
2918126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2919126258Smlaier					    pd->af);
2920126258Smlaier				break;
2921126258Smlaier			}
2922126258Smlaier			break;
2923126258Smlaier		case PF_RDR: {
2924140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2925126258Smlaier				return (NULL);
2926149884Smlaier			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
2927149884Smlaier			    PF_POOL_BITMASK)
2928149884Smlaier				PF_POOLMASK(naddr, naddr,
2929149884Smlaier				    &r->rpool.cur->addr.v.a.mask, daddr,
2930149884Smlaier				    pd->af);
2931126258Smlaier
2932126258Smlaier			if (r->rpool.proxy_port[1]) {
2933126258Smlaier				u_int32_t	tmp_nport;
2934126258Smlaier
2935126258Smlaier				tmp_nport = ((ntohs(dport) -
2936126258Smlaier				    ntohs(r->dst.port[0])) %
2937126258Smlaier				    (r->rpool.proxy_port[1] -
2938126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2939126258Smlaier				    r->rpool.proxy_port[0];
2940126258Smlaier
2941126258Smlaier				/* wrap around if necessary */
2942126258Smlaier				if (tmp_nport > 65535)
2943126258Smlaier					tmp_nport -= 65535;
2944126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2945126258Smlaier			} else if (r->rpool.proxy_port[0])
2946126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2947126258Smlaier			break;
2948126258Smlaier		}
2949126258Smlaier		default:
2950126258Smlaier			return (NULL);
2951126258Smlaier		}
2952126258Smlaier	}
2953126258Smlaier
2954126258Smlaier	return (r);
2955126258Smlaier}
2956126258Smlaier
2957126258Smlaierint
2958135920Smlaier#ifdef __FreeBSD__
2959171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
2960135920Smlaier#else
2961171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd)
2962135920Smlaier#endif
2963126258Smlaier{
2964126258Smlaier	struct pf_addr		*saddr, *daddr;
2965126258Smlaier	u_int16_t		 sport, dport;
2966127145Smlaier#ifdef __FreeBSD__
2967126261Smlaier	struct inpcbinfo	*pi;
2968126261Smlaier#else
2969126258Smlaier	struct inpcbtable	*tb;
2970126261Smlaier#endif
2971126258Smlaier	struct inpcb		*inp;
2972126258Smlaier
2973171168Smlaier	if (pd == NULL)
2974171168Smlaier		return (-1);
2975171168Smlaier	pd->lookup.uid = UID_MAX;
2976171168Smlaier	pd->lookup.gid = GID_MAX;
2977171168Smlaier	pd->lookup.pid = NO_PID;		/* XXX: revisit */
2978135920Smlaier#ifdef __FreeBSD__
2979135920Smlaier	if (inp_arg != NULL) {
2980178325Srwatson		INP_LOCK_ASSERT(inp_arg);
2981183606Sbz		pd->lookup.uid = inp_arg->inp_cred->cr_uid;
2982183606Sbz		pd->lookup.gid = inp_arg->inp_cred->cr_groups[0];
2983183606Sbz		return (1);
2984135920Smlaier	}
2985135920Smlaier#endif
2986130613Smlaier	switch (pd->proto) {
2987126258Smlaier	case IPPROTO_TCP:
2988171168Smlaier		if (pd->hdr.tcp == NULL)
2989171168Smlaier			return (-1);
2990126258Smlaier		sport = pd->hdr.tcp->th_sport;
2991126258Smlaier		dport = pd->hdr.tcp->th_dport;
2992127145Smlaier#ifdef __FreeBSD__
2993181803Sbz		pi = &V_tcbinfo;
2994126261Smlaier#else
2995126258Smlaier		tb = &tcbtable;
2996126261Smlaier#endif
2997126258Smlaier		break;
2998126258Smlaier	case IPPROTO_UDP:
2999171168Smlaier		if (pd->hdr.udp == NULL)
3000171168Smlaier			return (-1);
3001126258Smlaier		sport = pd->hdr.udp->uh_sport;
3002126258Smlaier		dport = pd->hdr.udp->uh_dport;
3003127145Smlaier#ifdef __FreeBSD__
3004181803Sbz		pi = &V_udbinfo;
3005126261Smlaier#else
3006126258Smlaier		tb = &udbtable;
3007126261Smlaier#endif
3008126258Smlaier		break;
3009126258Smlaier	default:
3010171168Smlaier		return (-1);
3011126258Smlaier	}
3012126258Smlaier	if (direction == PF_IN) {
3013126258Smlaier		saddr = pd->src;
3014126258Smlaier		daddr = pd->dst;
3015126258Smlaier	} else {
3016126258Smlaier		u_int16_t	p;
3017126258Smlaier
3018126258Smlaier		p = sport;
3019126258Smlaier		sport = dport;
3020126258Smlaier		dport = p;
3021126258Smlaier		saddr = pd->dst;
3022126258Smlaier		daddr = pd->src;
3023126258Smlaier	}
3024130613Smlaier	switch (pd->af) {
3025145836Smlaier#ifdef INET
3026126258Smlaier	case AF_INET:
3027127145Smlaier#ifdef __FreeBSD__
3028126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
3029126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
3030126261Smlaier			dport, 0, NULL);
3031126261Smlaier		if (inp == NULL) {
3032126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
3033126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
3034126261Smlaier			if(inp == NULL) {
3035126261Smlaier				INP_INFO_RUNLOCK(pi);
3036171168Smlaier				return (-1);
3037126261Smlaier			}
3038126261Smlaier		}
3039126261Smlaier#else
3040126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
3041126258Smlaier		if (inp == NULL) {
3042130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
3043126258Smlaier			if (inp == NULL)
3044171168Smlaier				return (-1);
3045126258Smlaier		}
3046126261Smlaier#endif
3047126258Smlaier		break;
3048145836Smlaier#endif /* INET */
3049126258Smlaier#ifdef INET6
3050126258Smlaier	case AF_INET6:
3051127145Smlaier#ifdef __FreeBSD__
3052126261Smlaier		INP_INFO_RLOCK(pi);
3053126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3054126261Smlaier			&daddr->v6, dport, 0, NULL);
3055126261Smlaier		if (inp == NULL) {
3056126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3057126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
3058126261Smlaier			if (inp == NULL) {
3059126261Smlaier				INP_INFO_RUNLOCK(pi);
3060171168Smlaier				return (-1);
3061126261Smlaier			}
3062126261Smlaier		}
3063126261Smlaier#else
3064126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
3065126258Smlaier		    dport);
3066126258Smlaier		if (inp == NULL) {
3067130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
3068126258Smlaier			if (inp == NULL)
3069171168Smlaier				return (-1);
3070126258Smlaier		}
3071126261Smlaier#endif
3072126258Smlaier		break;
3073126258Smlaier#endif /* INET6 */
3074126258Smlaier
3075126258Smlaier	default:
3076171168Smlaier		return (-1);
3077126258Smlaier	}
3078127145Smlaier#ifdef __FreeBSD__
3079183606Sbz	pd->lookup.uid = inp->inp_cred->cr_uid;
3080183606Sbz	pd->lookup.gid = inp->inp_cred->cr_groups[0];
3081178325Srwatson	INP_INFO_RUNLOCK(pi);
3082126261Smlaier#else
3083171168Smlaier	pd->lookup.uid = inp->inp_socket->so_euid;
3084171168Smlaier	pd->lookup.gid = inp->inp_socket->so_egid;
3085171168Smlaier	pd->lookup.pid = inp->inp_socket->so_cpid;
3086126261Smlaier#endif
3087126258Smlaier	return (1);
3088126258Smlaier}
3089126258Smlaier
3090126258Smlaieru_int8_t
3091126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3092126258Smlaier{
3093126258Smlaier	int		 hlen;
3094126258Smlaier	u_int8_t	 hdr[60];
3095126258Smlaier	u_int8_t	*opt, optlen;
3096126258Smlaier	u_int8_t	 wscale = 0;
3097126258Smlaier
3098126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
3099126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3100126258Smlaier		return (0);
3101126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3102126258Smlaier		return (0);
3103126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3104126258Smlaier	hlen -= sizeof(struct tcphdr);
3105126258Smlaier	while (hlen >= 3) {
3106126258Smlaier		switch (*opt) {
3107126258Smlaier		case TCPOPT_EOL:
3108126258Smlaier		case TCPOPT_NOP:
3109126258Smlaier			++opt;
3110126258Smlaier			--hlen;
3111126258Smlaier			break;
3112126258Smlaier		case TCPOPT_WINDOW:
3113126258Smlaier			wscale = opt[2];
3114126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
3115126258Smlaier				wscale = TCP_MAX_WINSHIFT;
3116126258Smlaier			wscale |= PF_WSCALE_FLAG;
3117130613Smlaier			/* FALLTHROUGH */
3118126258Smlaier		default:
3119126258Smlaier			optlen = opt[1];
3120126258Smlaier			if (optlen < 2)
3121126258Smlaier				optlen = 2;
3122126258Smlaier			hlen -= optlen;
3123126258Smlaier			opt += optlen;
3124130613Smlaier			break;
3125126258Smlaier		}
3126126258Smlaier	}
3127126258Smlaier	return (wscale);
3128126258Smlaier}
3129126258Smlaier
3130126258Smlaieru_int16_t
3131126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3132126258Smlaier{
3133126258Smlaier	int		 hlen;
3134126258Smlaier	u_int8_t	 hdr[60];
3135126258Smlaier	u_int8_t	*opt, optlen;
3136181803Sbz	u_int16_t	 mss = V_tcp_mssdflt;
3137126258Smlaier
3138126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
3139126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3140126258Smlaier		return (0);
3141126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3142126258Smlaier		return (0);
3143126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3144126258Smlaier	hlen -= sizeof(struct tcphdr);
3145126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
3146126258Smlaier		switch (*opt) {
3147126258Smlaier		case TCPOPT_EOL:
3148126258Smlaier		case TCPOPT_NOP:
3149126258Smlaier			++opt;
3150126258Smlaier			--hlen;
3151126258Smlaier			break;
3152126258Smlaier		case TCPOPT_MAXSEG:
3153126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
3154145030Sglebius			NTOHS(mss);
3155130613Smlaier			/* FALLTHROUGH */
3156126258Smlaier		default:
3157126258Smlaier			optlen = opt[1];
3158126258Smlaier			if (optlen < 2)
3159126258Smlaier				optlen = 2;
3160126258Smlaier			hlen -= optlen;
3161126258Smlaier			opt += optlen;
3162130613Smlaier			break;
3163126258Smlaier		}
3164126258Smlaier	}
3165126258Smlaier	return (mss);
3166126258Smlaier}
3167126258Smlaier
3168126258Smlaieru_int16_t
3169126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
3170126258Smlaier{
3171126258Smlaier#ifdef INET
3172126258Smlaier	struct sockaddr_in	*dst;
3173126258Smlaier	struct route		 ro;
3174126258Smlaier#endif /* INET */
3175126258Smlaier#ifdef INET6
3176126258Smlaier	struct sockaddr_in6	*dst6;
3177126258Smlaier	struct route_in6	 ro6;
3178126258Smlaier#endif /* INET6 */
3179126258Smlaier	struct rtentry		*rt = NULL;
3180127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
3181181803Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3182126258Smlaier
3183126258Smlaier	switch (af) {
3184126258Smlaier#ifdef INET
3185126258Smlaier	case AF_INET:
3186126258Smlaier		hlen = sizeof(struct ip);
3187126258Smlaier		bzero(&ro, sizeof(ro));
3188126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
3189126258Smlaier		dst->sin_family = AF_INET;
3190126258Smlaier		dst->sin_len = sizeof(*dst);
3191126258Smlaier		dst->sin_addr = addr->v4;
3192127145Smlaier#ifdef __FreeBSD__
3193126261Smlaier#ifdef RTF_PRCLONING
3194126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
3195126261Smlaier#else /* !RTF_PRCLONING */
3196186119Sqingli		in_rtalloc_ign(&ro, 0, 0);
3197126261Smlaier#endif
3198126261Smlaier#else /* ! __FreeBSD__ */
3199126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
3200126261Smlaier#endif
3201126258Smlaier		rt = ro.ro_rt;
3202126258Smlaier		break;
3203126258Smlaier#endif /* INET */
3204126258Smlaier#ifdef INET6
3205126258Smlaier	case AF_INET6:
3206126258Smlaier		hlen = sizeof(struct ip6_hdr);
3207126258Smlaier		bzero(&ro6, sizeof(ro6));
3208126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
3209126258Smlaier		dst6->sin6_family = AF_INET6;
3210126258Smlaier		dst6->sin6_len = sizeof(*dst6);
3211126258Smlaier		dst6->sin6_addr = addr->v6;
3212127145Smlaier#ifdef __FreeBSD__
3213126261Smlaier#ifdef RTF_PRCLONING
3214126261Smlaier		rtalloc_ign((struct route *)&ro6,
3215126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
3216126261Smlaier#else /* !RTF_PRCLONING */
3217186119Sqingli		rtalloc_ign((struct route *)&ro6, 0);
3218126261Smlaier#endif
3219126261Smlaier#else /* ! __FreeBSD__ */
3220126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
3221126261Smlaier#endif
3222126258Smlaier		rt = ro6.ro_rt;
3223126258Smlaier		break;
3224126258Smlaier#endif /* INET6 */
3225126258Smlaier	}
3226126258Smlaier
3227126258Smlaier	if (rt && rt->rt_ifp) {
3228126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
3229181803Sbz		mss = max(V_tcp_mssdflt, mss);
3230126258Smlaier		RTFREE(rt);
3231126258Smlaier	}
3232126258Smlaier	mss = min(mss, offer);
3233126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
3234126258Smlaier	return (mss);
3235126258Smlaier}
3236126258Smlaier
3237126258Smlaiervoid
3238126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
3239126258Smlaier{
3240126258Smlaier	struct pf_rule *r = s->rule.ptr;
3241126258Smlaier
3242130613Smlaier	s->rt_kif = NULL;
3243126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
3244126258Smlaier		return;
3245126258Smlaier	switch (s->af) {
3246126258Smlaier#ifdef INET
3247126258Smlaier	case AF_INET:
3248130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
3249130613Smlaier		    &s->nat_src_node);
3250130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3251126258Smlaier		break;
3252126258Smlaier#endif /* INET */
3253126258Smlaier#ifdef INET6
3254126258Smlaier	case AF_INET6:
3255130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
3256130613Smlaier		    &s->nat_src_node);
3257130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3258126258Smlaier		break;
3259126258Smlaier#endif /* INET6 */
3260126258Smlaier	}
3261126258Smlaier}
3262126258Smlaier
3263126258Smlaierint
3264126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
3265130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3266135920Smlaier#ifdef __FreeBSD__
3267135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3268145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3269135920Smlaier#else
3270145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3271145836Smlaier    struct ifqueue *ifq)
3272135920Smlaier#endif
3273126258Smlaier{
3274130613Smlaier	struct pf_rule		*nr = NULL;
3275126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3276126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3277126258Smlaier	u_int16_t		 bport, nport = 0;
3278126258Smlaier	sa_family_t		 af = pd->af;
3279126258Smlaier	struct pf_rule		*r, *a = NULL;
3280126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3281130613Smlaier	struct pf_src_node	*nsn = NULL;
3282126258Smlaier	u_short			 reason;
3283126258Smlaier	int			 rewrite = 0;
3284171168Smlaier	int			 tag = -1, rtableid = -1;
3285181803Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3286145836Smlaier	int			 asd = 0;
3287171168Smlaier	int			 match = 0;
3288126258Smlaier
3289145836Smlaier	if (pf_check_congestion(ifq)) {
3290145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3291145836Smlaier		return (PF_DROP);
3292145836Smlaier	}
3293145836Smlaier
3294171168Smlaier#ifdef __FreeBSD__
3295171168Smlaier	if (inp != NULL)
3296171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3297171168Smlaier	else if (debug_pfugidhack) {
3298171168Smlaier		PF_UNLOCK();
3299171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3300171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3301171168Smlaier		PF_LOCK();
3302171168Smlaier	}
3303165631Smlaier#endif
3304165631Smlaier
3305126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3306126258Smlaier
3307126258Smlaier	if (direction == PF_OUT) {
3308126258Smlaier		bport = nport = th->th_sport;
3309126258Smlaier		/* check outgoing packet for BINAT/NAT */
3310130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3311126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3312130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3313130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3314126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3315130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3316126258Smlaier			rewrite++;
3317130613Smlaier			if (nr->natpass)
3318126258Smlaier				r = NULL;
3319130613Smlaier			pd->nat_rule = nr;
3320126258Smlaier		}
3321126258Smlaier	} else {
3322126258Smlaier		bport = nport = th->th_dport;
3323126258Smlaier		/* check incoming packet for BINAT/RDR */
3324130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3325130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3326130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3327130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3328126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3329130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3330126258Smlaier			rewrite++;
3331130613Smlaier			if (nr->natpass)
3332126258Smlaier				r = NULL;
3333130613Smlaier			pd->nat_rule = nr;
3334126258Smlaier		}
3335126258Smlaier	}
3336126258Smlaier
3337126258Smlaier	while (r != NULL) {
3338126258Smlaier		r->evaluations++;
3339171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3340126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3341126258Smlaier		else if (r->direction && r->direction != direction)
3342126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3343126258Smlaier		else if (r->af && r->af != af)
3344126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3345126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3346126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3347171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3348171168Smlaier		    r->src.neg, kif))
3349126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3350126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3351126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3352126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3353171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3354171168Smlaier		    r->dst.neg, NULL))
3355126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3356126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3357126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3358126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3359171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3360126258Smlaier			r = TAILQ_NEXT(r, entries);
3361126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3362126258Smlaier			r = TAILQ_NEXT(r, entries);
3363126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3364126258Smlaier			r = TAILQ_NEXT(r, entries);
3365171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3366135920Smlaier#ifdef __FreeBSD__
3367171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3368135920Smlaier#else
3369171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3370135920Smlaier#endif
3371126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3372171168Smlaier		    pd->lookup.uid))
3373126258Smlaier			r = TAILQ_NEXT(r, entries);
3374171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3375135920Smlaier#ifdef __FreeBSD__
3376171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3377135920Smlaier#else
3378171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3379135920Smlaier#endif
3380126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3381171168Smlaier		    pd->lookup.gid))
3382126258Smlaier			r = TAILQ_NEXT(r, entries);
3383145836Smlaier		else if (r->prob && r->prob <= arc4random())
3384126258Smlaier			r = TAILQ_NEXT(r, entries);
3385171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3386126258Smlaier			r = TAILQ_NEXT(r, entries);
3387126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3388126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3389126258Smlaier			r = TAILQ_NEXT(r, entries);
3390126258Smlaier		else {
3391126258Smlaier			if (r->tag)
3392126258Smlaier				tag = r->tag;
3393171168Smlaier			if (r->rtableid >= 0)
3394171168Smlaier				rtableid = r->rtableid;
3395126258Smlaier			if (r->anchor == NULL) {
3396171168Smlaier				match = 1;
3397126258Smlaier				*rm = r;
3398126258Smlaier				*am = a;
3399126258Smlaier				*rsm = ruleset;
3400126258Smlaier				if ((*rm)->quick)
3401126258Smlaier					break;
3402126258Smlaier				r = TAILQ_NEXT(r, entries);
3403126258Smlaier			} else
3404145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3405171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3406126258Smlaier		}
3407171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3408171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3409171168Smlaier			break;
3410126258Smlaier	}
3411126258Smlaier	r = *rm;
3412126258Smlaier	a = *am;
3413126258Smlaier	ruleset = *rsm;
3414126258Smlaier
3415126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3416126258Smlaier
3417171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3418126258Smlaier		if (rewrite)
3419171168Smlaier#ifdef __FreeBSD__
3420126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3421171168Smlaier#else
3422171168Smlaier			m_copyback(m, off, sizeof(*th), th);
3423171168Smlaier#endif
3424171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3425171168Smlaier		    a, ruleset, pd);
3426126258Smlaier	}
3427126258Smlaier
3428126258Smlaier	if ((r->action == PF_DROP) &&
3429126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3430126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3431126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3432126258Smlaier		/* undo NAT changes, if they have taken place */
3433130613Smlaier		if (nr != NULL) {
3434130613Smlaier			if (direction == PF_OUT) {
3435130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3436130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3437130613Smlaier				rewrite++;
3438130613Smlaier			} else {
3439130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3440130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3441130613Smlaier				rewrite++;
3442130613Smlaier			}
3443126258Smlaier		}
3444126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3445126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3446126258Smlaier		    !(th->th_flags & TH_RST)) {
3447126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3448126258Smlaier
3449126258Smlaier			if (th->th_flags & TH_SYN)
3450126258Smlaier				ack++;
3451126258Smlaier			if (th->th_flags & TH_FIN)
3452126258Smlaier				ack++;
3453162238Scsjp#ifdef __FreeBSD__
3454162238Scsjp			pf_send_tcp(m, r, af, pd->dst,
3455162238Scsjp#else
3456126258Smlaier			pf_send_tcp(r, af, pd->dst,
3457162238Scsjp#endif
3458126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3459126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3460171168Smlaier			    r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
3461126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3462126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3463126258Smlaier			    r->return_icmp & 255, af, r);
3464126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3465126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3466126258Smlaier			    r->return_icmp6 & 255, af, r);
3467126258Smlaier	}
3468126258Smlaier
3469126258Smlaier	if (r->action == PF_DROP)
3470126258Smlaier		return (PF_DROP);
3471126258Smlaier
3472171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3473126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3474126258Smlaier		return (PF_DROP);
3475126258Smlaier	}
3476126258Smlaier
3477130613Smlaier	if (r->keep_state || nr != NULL ||
3478126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3479126258Smlaier		/* create new state */
3480126258Smlaier		u_int16_t	 len;
3481126258Smlaier		struct pf_state	*s = NULL;
3482130613Smlaier		struct pf_src_node *sn = NULL;
3483126258Smlaier
3484126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3485130613Smlaier
3486130613Smlaier		/* check maximums */
3487145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3488145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3489145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3490130613Smlaier			goto cleanup;
3491145836Smlaier		}
3492171168Smlaier		/* src node for filter rule */
3493130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3494130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3495145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3496145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3497130613Smlaier			goto cleanup;
3498145836Smlaier		}
3499130613Smlaier		/* src node for translation rule */
3500130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3501130613Smlaier		    ((direction == PF_OUT &&
3502130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3503145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3504145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3505130613Smlaier			goto cleanup;
3506145836Smlaier		}
3507130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3508126258Smlaier		if (s == NULL) {
3509145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3510130613Smlaiercleanup:
3511130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3512130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3513130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3514130613Smlaier				pf_status.src_nodes--;
3515130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3516130613Smlaier			}
3517130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3518130613Smlaier			    nsn->expire == 0) {
3519130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3520130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3521130613Smlaier				pf_status.src_nodes--;
3522130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3523130613Smlaier			}
3524126258Smlaier			return (PF_DROP);
3525126258Smlaier		}
3526126258Smlaier		bzero(s, sizeof(*s));
3527126258Smlaier		s->rule.ptr = r;
3528130613Smlaier		s->nat_rule.ptr = nr;
3529126258Smlaier		s->anchor.ptr = a;
3530145836Smlaier		STATE_INC_COUNTERS(s);
3531126258Smlaier		s->allow_opts = r->allow_opts;
3532171168Smlaier		s->log = r->log & PF_LOG_ALL;
3533171168Smlaier		if (nr != NULL)
3534171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3535126258Smlaier		s->proto = IPPROTO_TCP;
3536126258Smlaier		s->direction = direction;
3537126258Smlaier		s->af = af;
3538126258Smlaier		if (direction == PF_OUT) {
3539126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3540126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3541126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3542126258Smlaier			s->ext.port = th->th_dport;
3543130613Smlaier			if (nr != NULL) {
3544130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3545126258Smlaier				s->lan.port = bport;
3546126258Smlaier			} else {
3547126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3548126258Smlaier				s->lan.port = s->gwy.port;
3549126258Smlaier			}
3550126258Smlaier		} else {
3551126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3552126258Smlaier			s->lan.port = th->th_dport;
3553126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3554126258Smlaier			s->ext.port = th->th_sport;
3555130613Smlaier			if (nr != NULL) {
3556130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3557126258Smlaier				s->gwy.port = bport;
3558126258Smlaier			} else {
3559126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3560126258Smlaier				s->gwy.port = s->lan.port;
3561126258Smlaier			}
3562126258Smlaier		}
3563126258Smlaier
3564126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3565126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3566126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3567126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3568126258Smlaier			/* Generate sequence number modulator */
3569171168Smlaier#ifdef __FreeBSD__
3570171168Smlaier			while ((s->src.seqdiff =
3571171168Smlaier			    pf_new_isn(s) - s->src.seqlo) == 0)
3572171168Smlaier				;
3573171168Smlaier#else
3574171168Smlaier			while ((s->src.seqdiff =
3575171168Smlaier			    tcp_rndiss_next() - s->src.seqlo) == 0)
3576126258Smlaier				;
3577171168Smlaier#endif
3578126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3579126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3580126258Smlaier			rewrite = 1;
3581126258Smlaier		} else
3582126258Smlaier			s->src.seqdiff = 0;
3583126258Smlaier		if (th->th_flags & TH_SYN) {
3584126258Smlaier			s->src.seqhi++;
3585126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3586126258Smlaier		}
3587126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3588126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3589126258Smlaier			/* Remove scale factor from initial window */
3590126258Smlaier			int win = s->src.max_win;
3591126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3592126258Smlaier			s->src.max_win = (win - 1) >>
3593126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3594126258Smlaier		}
3595126258Smlaier		if (th->th_flags & TH_FIN)
3596126258Smlaier			s->src.seqhi++;
3597126258Smlaier		s->dst.seqhi = 1;
3598126258Smlaier		s->dst.max_win = 1;
3599126258Smlaier		s->src.state = TCPS_SYN_SENT;
3600126258Smlaier		s->dst.state = TCPS_CLOSED;
3601126261Smlaier		s->creation = time_second;
3602126261Smlaier		s->expire = time_second;
3603126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3604126258Smlaier		pf_set_rt_ifp(s, saddr);
3605130613Smlaier		if (sn != NULL) {
3606130613Smlaier			s->src_node = sn;
3607130613Smlaier			s->src_node->states++;
3608130613Smlaier		}
3609130613Smlaier		if (nsn != NULL) {
3610130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3611130613Smlaier			s->nat_src_node = nsn;
3612130613Smlaier			s->nat_src_node->states++;
3613130613Smlaier		}
3614126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3615126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3616126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3617130613Smlaier			pf_src_tree_remove_state(s);
3618145836Smlaier			STATE_DEC_COUNTERS(s);
3619126258Smlaier			pool_put(&pf_state_pl, s);
3620126258Smlaier			return (PF_DROP);
3621126258Smlaier		}
3622126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3623145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3624145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3625145836Smlaier			/* This really shouldn't happen!!! */
3626145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3627145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3628126258Smlaier			pf_normalize_tcp_cleanup(s);
3629130613Smlaier			pf_src_tree_remove_state(s);
3630145836Smlaier			STATE_DEC_COUNTERS(s);
3631126258Smlaier			pool_put(&pf_state_pl, s);
3632126258Smlaier			return (PF_DROP);
3633126258Smlaier		}
3634130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3635126258Smlaier			pf_normalize_tcp_cleanup(s);
3636145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3637130613Smlaier			pf_src_tree_remove_state(s);
3638145836Smlaier			STATE_DEC_COUNTERS(s);
3639126258Smlaier			pool_put(&pf_state_pl, s);
3640126258Smlaier			return (PF_DROP);
3641126258Smlaier		} else
3642126258Smlaier			*sm = s;
3643145836Smlaier		if (tag > 0) {
3644145836Smlaier			pf_tag_ref(tag);
3645145836Smlaier			s->tag = tag;
3646145836Smlaier		}
3647126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3648126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3649126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3650130613Smlaier			if (nr != NULL) {
3651130613Smlaier				if (direction == PF_OUT) {
3652130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3653130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3654130613Smlaier					    bport, 0, af);
3655130613Smlaier				} else {
3656130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3657130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3658130613Smlaier					    bport, 0, af);
3659130613Smlaier				}
3660130613Smlaier			}
3661145836Smlaier			s->src.seqhi = htonl(arc4random());
3662126258Smlaier			/* Find mss option */
3663126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3664126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3665126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3666126258Smlaier			s->src.mss = mss;
3667162238Scsjp#ifdef __FreeBSD__
3668162238Scsjp			pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
3669162238Scsjp#else
3670126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3671162238Scsjp#endif
3672130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3673171168Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
3674145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3675126258Smlaier			return (PF_SYNPROXY_DROP);
3676126258Smlaier		}
3677126258Smlaier	}
3678126258Smlaier
3679126258Smlaier	/* copy back packet headers if we performed NAT operations */
3680126258Smlaier	if (rewrite)
3681126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3682126258Smlaier
3683126258Smlaier	return (PF_PASS);
3684126258Smlaier}
3685126258Smlaier
3686126258Smlaierint
3687126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3688130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3689135920Smlaier#ifdef __FreeBSD__
3690135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3691145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3692135920Smlaier#else
3693145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3694145836Smlaier    struct ifqueue *ifq)
3695135920Smlaier#endif
3696126258Smlaier{
3697130613Smlaier	struct pf_rule		*nr = NULL;
3698126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3699126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3700126258Smlaier	u_int16_t		 bport, nport = 0;
3701126258Smlaier	sa_family_t		 af = pd->af;
3702126258Smlaier	struct pf_rule		*r, *a = NULL;
3703126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3704130613Smlaier	struct pf_src_node	*nsn = NULL;
3705126258Smlaier	u_short			 reason;
3706126258Smlaier	int			 rewrite = 0;
3707171168Smlaier	int			 tag = -1, rtableid = -1;
3708145836Smlaier	int			 asd = 0;
3709171168Smlaier	int			 match = 0;
3710126258Smlaier
3711145836Smlaier	if (pf_check_congestion(ifq)) {
3712145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3713145836Smlaier		return (PF_DROP);
3714145836Smlaier	}
3715145836Smlaier
3716171168Smlaier#ifdef __FreeBSD__
3717171168Smlaier	if (inp != NULL)
3718171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3719171168Smlaier	else if (debug_pfugidhack) {
3720171168Smlaier		PF_UNLOCK();
3721171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3722171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3723171168Smlaier		PF_LOCK();
3724171168Smlaier	}
3725165631Smlaier#endif
3726165631Smlaier
3727126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3728126258Smlaier
3729126258Smlaier	if (direction == PF_OUT) {
3730126258Smlaier		bport = nport = uh->uh_sport;
3731126258Smlaier		/* check outgoing packet for BINAT/NAT */
3732130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3733126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3734130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3735130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3736126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3737130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3738126258Smlaier			rewrite++;
3739130613Smlaier			if (nr->natpass)
3740126258Smlaier				r = NULL;
3741130613Smlaier			pd->nat_rule = nr;
3742126258Smlaier		}
3743126258Smlaier	} else {
3744126258Smlaier		bport = nport = uh->uh_dport;
3745126258Smlaier		/* check incoming packet for BINAT/RDR */
3746130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3747130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3748130613Smlaier		    &nport)) != NULL) {
3749130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3750126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3751130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3752126258Smlaier			rewrite++;
3753130613Smlaier			if (nr->natpass)
3754126258Smlaier				r = NULL;
3755130613Smlaier			pd->nat_rule = nr;
3756126258Smlaier		}
3757126258Smlaier	}
3758126258Smlaier
3759126258Smlaier	while (r != NULL) {
3760126258Smlaier		r->evaluations++;
3761171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3762126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3763126258Smlaier		else if (r->direction && r->direction != direction)
3764126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3765126258Smlaier		else if (r->af && r->af != af)
3766126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3767126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3768126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3769171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3770171168Smlaier		    r->src.neg, kif))
3771126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3772126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3773126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3774126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3775171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3776171168Smlaier		    r->dst.neg, NULL))
3777126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3778126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3779126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3780126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3781171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3782126258Smlaier			r = TAILQ_NEXT(r, entries);
3783126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3784126258Smlaier			r = TAILQ_NEXT(r, entries);
3785171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3786135920Smlaier#ifdef __FreeBSD__
3787171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3788135920Smlaier#else
3789171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3790135920Smlaier#endif
3791126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3792171168Smlaier		    pd->lookup.uid))
3793126258Smlaier			r = TAILQ_NEXT(r, entries);
3794171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3795135920Smlaier#ifdef __FreeBSD__
3796171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3797135920Smlaier#else
3798171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3799135920Smlaier#endif
3800126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3801171168Smlaier		    pd->lookup.gid))
3802126258Smlaier			r = TAILQ_NEXT(r, entries);
3803145836Smlaier		else if (r->prob && r->prob <= arc4random())
3804126258Smlaier			r = TAILQ_NEXT(r, entries);
3805171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3806126258Smlaier			r = TAILQ_NEXT(r, entries);
3807126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3808126258Smlaier			r = TAILQ_NEXT(r, entries);
3809126258Smlaier		else {
3810126258Smlaier			if (r->tag)
3811126258Smlaier				tag = r->tag;
3812171168Smlaier			if (r->rtableid >= 0)
3813171168Smlaier				rtableid = r->rtableid;
3814126258Smlaier			if (r->anchor == NULL) {
3815171168Smlaier				match = 1;
3816126258Smlaier				*rm = r;
3817126258Smlaier				*am = a;
3818126258Smlaier				*rsm = ruleset;
3819126258Smlaier				if ((*rm)->quick)
3820126258Smlaier					break;
3821126258Smlaier				r = TAILQ_NEXT(r, entries);
3822126258Smlaier			} else
3823145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3824171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3825126258Smlaier		}
3826171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3827171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3828171168Smlaier			break;
3829126258Smlaier	}
3830126258Smlaier	r = *rm;
3831126258Smlaier	a = *am;
3832126258Smlaier	ruleset = *rsm;
3833126258Smlaier
3834126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3835126258Smlaier
3836171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3837126258Smlaier		if (rewrite)
3838171168Smlaier#ifdef __FreeBSD__
3839126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3840171168Smlaier#else
3841171168Smlaier			m_copyback(m, off, sizeof(*uh), uh);
3842171168Smlaier#endif
3843171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3844171168Smlaier		    a, ruleset, pd);
3845126258Smlaier	}
3846126258Smlaier
3847126258Smlaier	if ((r->action == PF_DROP) &&
3848126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3849126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3850126258Smlaier		/* undo NAT changes, if they have taken place */
3851130613Smlaier		if (nr != NULL) {
3852130613Smlaier			if (direction == PF_OUT) {
3853130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3854130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3855130613Smlaier				rewrite++;
3856130613Smlaier			} else {
3857130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3858130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3859130613Smlaier				rewrite++;
3860130613Smlaier			}
3861126258Smlaier		}
3862126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3863126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3864126258Smlaier			    r->return_icmp & 255, af, r);
3865126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3866126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3867126258Smlaier			    r->return_icmp6 & 255, af, r);
3868126258Smlaier	}
3869126258Smlaier
3870126258Smlaier	if (r->action == PF_DROP)
3871126258Smlaier		return (PF_DROP);
3872126258Smlaier
3873171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3874126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3875126258Smlaier		return (PF_DROP);
3876126258Smlaier	}
3877126258Smlaier
3878130613Smlaier	if (r->keep_state || nr != NULL) {
3879126258Smlaier		/* create new state */
3880126258Smlaier		struct pf_state	*s = NULL;
3881130613Smlaier		struct pf_src_node *sn = NULL;
3882126258Smlaier
3883130613Smlaier		/* check maximums */
3884145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3885145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3886145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3887130613Smlaier			goto cleanup;
3888145836Smlaier		}
3889171168Smlaier		/* src node for filter rule */
3890130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3891130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3892145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3893145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3894130613Smlaier			goto cleanup;
3895145836Smlaier		}
3896130613Smlaier		/* src node for translation rule */
3897130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3898130613Smlaier		    ((direction == PF_OUT &&
3899130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3900145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3901145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3902130613Smlaier			goto cleanup;
3903145836Smlaier		}
3904130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3905126258Smlaier		if (s == NULL) {
3906145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3907130613Smlaiercleanup:
3908130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3909130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3910130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3911130613Smlaier				pf_status.src_nodes--;
3912130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3913130613Smlaier			}
3914130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3915130613Smlaier			    nsn->expire == 0) {
3916130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3917130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3918130613Smlaier				pf_status.src_nodes--;
3919130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3920130613Smlaier			}
3921126258Smlaier			return (PF_DROP);
3922126258Smlaier		}
3923126258Smlaier		bzero(s, sizeof(*s));
3924126258Smlaier		s->rule.ptr = r;
3925130613Smlaier		s->nat_rule.ptr = nr;
3926126258Smlaier		s->anchor.ptr = a;
3927145836Smlaier		STATE_INC_COUNTERS(s);
3928126258Smlaier		s->allow_opts = r->allow_opts;
3929171168Smlaier		s->log = r->log & PF_LOG_ALL;
3930171168Smlaier		if (nr != NULL)
3931171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3932126258Smlaier		s->proto = IPPROTO_UDP;
3933126258Smlaier		s->direction = direction;
3934126258Smlaier		s->af = af;
3935126258Smlaier		if (direction == PF_OUT) {
3936126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3937126258Smlaier			s->gwy.port = uh->uh_sport;
3938126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3939126258Smlaier			s->ext.port = uh->uh_dport;
3940130613Smlaier			if (nr != NULL) {
3941130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3942126258Smlaier				s->lan.port = bport;
3943126258Smlaier			} else {
3944126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3945126258Smlaier				s->lan.port = s->gwy.port;
3946126258Smlaier			}
3947126258Smlaier		} else {
3948126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3949126258Smlaier			s->lan.port = uh->uh_dport;
3950126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3951126258Smlaier			s->ext.port = uh->uh_sport;
3952130613Smlaier			if (nr != NULL) {
3953130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3954126258Smlaier				s->gwy.port = bport;
3955126258Smlaier			} else {
3956126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3957126258Smlaier				s->gwy.port = s->lan.port;
3958126258Smlaier			}
3959126258Smlaier		}
3960126258Smlaier		s->src.state = PFUDPS_SINGLE;
3961126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3962126261Smlaier		s->creation = time_second;
3963126261Smlaier		s->expire = time_second;
3964126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3965126258Smlaier		pf_set_rt_ifp(s, saddr);
3966130613Smlaier		if (sn != NULL) {
3967130613Smlaier			s->src_node = sn;
3968130613Smlaier			s->src_node->states++;
3969130613Smlaier		}
3970130613Smlaier		if (nsn != NULL) {
3971130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3972130613Smlaier			s->nat_src_node = nsn;
3973130613Smlaier			s->nat_src_node->states++;
3974130613Smlaier		}
3975130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3976145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3977130613Smlaier			pf_src_tree_remove_state(s);
3978145836Smlaier			STATE_DEC_COUNTERS(s);
3979126258Smlaier			pool_put(&pf_state_pl, s);
3980126258Smlaier			return (PF_DROP);
3981126258Smlaier		} else
3982126258Smlaier			*sm = s;
3983145836Smlaier		if (tag > 0) {
3984145836Smlaier			pf_tag_ref(tag);
3985145836Smlaier			s->tag = tag;
3986145836Smlaier		}
3987126258Smlaier	}
3988126258Smlaier
3989126258Smlaier	/* copy back packet headers if we performed NAT operations */
3990126258Smlaier	if (rewrite)
3991126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3992126258Smlaier
3993126258Smlaier	return (PF_PASS);
3994126258Smlaier}
3995126258Smlaier
3996126258Smlaierint
3997126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3998130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3999145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
4000145836Smlaier    struct ifqueue *ifq)
4001126258Smlaier{
4002130613Smlaier	struct pf_rule		*nr = NULL;
4003126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
4004126258Smlaier	struct pf_rule		*r, *a = NULL;
4005126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4006130613Smlaier	struct pf_src_node	*nsn = NULL;
4007126258Smlaier	u_short			 reason;
4008149893Smlaier	u_int16_t		 icmpid = 0, bport, nport = 0;
4009126258Smlaier	sa_family_t		 af = pd->af;
4010127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
4011127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
4012126258Smlaier	int			 state_icmp = 0;
4013171168Smlaier	int			 tag = -1, rtableid = -1;
4014126258Smlaier#ifdef INET6
4015126258Smlaier	int			 rewrite = 0;
4016126258Smlaier#endif /* INET6 */
4017145836Smlaier	int			 asd = 0;
4018171168Smlaier	int			 match = 0;
4019126258Smlaier
4020145836Smlaier	if (pf_check_congestion(ifq)) {
4021145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
4022145836Smlaier		return (PF_DROP);
4023145836Smlaier	}
4024145836Smlaier
4025126258Smlaier	switch (pd->proto) {
4026126258Smlaier#ifdef INET
4027126258Smlaier	case IPPROTO_ICMP:
4028126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4029126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
4030126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4031126258Smlaier
4032126258Smlaier		if (icmptype == ICMP_UNREACH ||
4033126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4034126258Smlaier		    icmptype == ICMP_REDIRECT ||
4035126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4036126258Smlaier		    icmptype == ICMP_PARAMPROB)
4037126258Smlaier			state_icmp++;
4038126258Smlaier		break;
4039126258Smlaier#endif /* INET */
4040126258Smlaier#ifdef INET6
4041126258Smlaier	case IPPROTO_ICMPV6:
4042126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4043126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
4044126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4045126258Smlaier
4046126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4047126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4048126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4049126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4050126258Smlaier			state_icmp++;
4051126258Smlaier		break;
4052126258Smlaier#endif /* INET6 */
4053126258Smlaier	}
4054126258Smlaier
4055126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4056126258Smlaier
4057126258Smlaier	if (direction == PF_OUT) {
4058149884Smlaier		bport = nport = icmpid;
4059126258Smlaier		/* check outgoing packet for BINAT/NAT */
4060130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4061149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4062149884Smlaier		    NULL) {
4063130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4064126258Smlaier			switch (af) {
4065126258Smlaier#ifdef INET
4066126258Smlaier			case AF_INET:
4067126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4068130613Smlaier				    pd->naddr.v4.s_addr, 0);
4069149884Smlaier				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
4070149884Smlaier				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
4071149884Smlaier				pd->hdr.icmp->icmp_id = nport;
4072149893Smlaier				m_copyback(m, off, ICMP_MINLEN,
4073149893Smlaier				    (caddr_t)pd->hdr.icmp);
4074126258Smlaier				break;
4075126258Smlaier#endif /* INET */
4076126258Smlaier#ifdef INET6
4077126258Smlaier			case AF_INET6:
4078126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
4079130613Smlaier				    &pd->naddr, 0);
4080126258Smlaier				rewrite++;
4081126258Smlaier				break;
4082126258Smlaier#endif /* INET6 */
4083126258Smlaier			}
4084130613Smlaier			if (nr->natpass)
4085126258Smlaier				r = NULL;
4086130613Smlaier			pd->nat_rule = nr;
4087126258Smlaier		}
4088126258Smlaier	} else {
4089149884Smlaier		bport = nport = icmpid;
4090126258Smlaier		/* check incoming packet for BINAT/RDR */
4091130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4092149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4093149884Smlaier		    NULL) {
4094130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4095126258Smlaier			switch (af) {
4096126258Smlaier#ifdef INET
4097126258Smlaier			case AF_INET:
4098126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4099130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4100126258Smlaier				break;
4101126258Smlaier#endif /* INET */
4102126258Smlaier#ifdef INET6
4103126258Smlaier			case AF_INET6:
4104126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
4105130613Smlaier				    &pd->naddr, 0);
4106126258Smlaier				rewrite++;
4107126258Smlaier				break;
4108126258Smlaier#endif /* INET6 */
4109126258Smlaier			}
4110130613Smlaier			if (nr->natpass)
4111126258Smlaier				r = NULL;
4112130613Smlaier			pd->nat_rule = nr;
4113126258Smlaier		}
4114126258Smlaier	}
4115126258Smlaier
4116126258Smlaier	while (r != NULL) {
4117126258Smlaier		r->evaluations++;
4118171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4119126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4120126258Smlaier		else if (r->direction && r->direction != direction)
4121126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4122126258Smlaier		else if (r->af && r->af != af)
4123126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4124126258Smlaier		else if (r->proto && r->proto != pd->proto)
4125126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4126171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
4127171168Smlaier		    r->src.neg, kif))
4128126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4129171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
4130171168Smlaier		    r->dst.neg, NULL))
4131126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4132126258Smlaier		else if (r->type && r->type != icmptype + 1)
4133126258Smlaier			r = TAILQ_NEXT(r, entries);
4134126258Smlaier		else if (r->code && r->code != icmpcode + 1)
4135126258Smlaier			r = TAILQ_NEXT(r, entries);
4136171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4137126258Smlaier			r = TAILQ_NEXT(r, entries);
4138126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4139126258Smlaier			r = TAILQ_NEXT(r, entries);
4140145836Smlaier		else if (r->prob && r->prob <= arc4random())
4141126258Smlaier			r = TAILQ_NEXT(r, entries);
4142171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4143126258Smlaier			r = TAILQ_NEXT(r, entries);
4144126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4145126258Smlaier			r = TAILQ_NEXT(r, entries);
4146126258Smlaier		else {
4147126258Smlaier			if (r->tag)
4148126258Smlaier				tag = r->tag;
4149171168Smlaier			if (r->rtableid >= 0)
4150171168Smlaier				rtableid = r->rtableid;
4151126258Smlaier			if (r->anchor == NULL) {
4152171168Smlaier				match = 1;
4153126258Smlaier				*rm = r;
4154126258Smlaier				*am = a;
4155126258Smlaier				*rsm = ruleset;
4156126258Smlaier				if ((*rm)->quick)
4157126258Smlaier					break;
4158126258Smlaier				r = TAILQ_NEXT(r, entries);
4159126258Smlaier			} else
4160145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4161171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4162126258Smlaier		}
4163171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4164171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4165171168Smlaier			break;
4166126258Smlaier	}
4167126258Smlaier	r = *rm;
4168126258Smlaier	a = *am;
4169126258Smlaier	ruleset = *rsm;
4170126258Smlaier
4171126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4172126258Smlaier
4173171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
4174126258Smlaier#ifdef INET6
4175126258Smlaier		if (rewrite)
4176126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
4177126261Smlaier			    (caddr_t)pd->hdr.icmp6);
4178126258Smlaier#endif /* INET6 */
4179171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4180171168Smlaier		    a, ruleset, pd);
4181126258Smlaier	}
4182126258Smlaier
4183126258Smlaier	if (r->action != PF_PASS)
4184126258Smlaier		return (PF_DROP);
4185126258Smlaier
4186171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4187126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4188126258Smlaier		return (PF_DROP);
4189126258Smlaier	}
4190126258Smlaier
4191130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
4192126258Smlaier		/* create new state */
4193126258Smlaier		struct pf_state	*s = NULL;
4194130613Smlaier		struct pf_src_node *sn = NULL;
4195126258Smlaier
4196130613Smlaier		/* check maximums */
4197145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4198145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4199145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4200130613Smlaier			goto cleanup;
4201145836Smlaier		}
4202171168Smlaier		/* src node for filter rule */
4203130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4204130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4205145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4206145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4207130613Smlaier			goto cleanup;
4208145836Smlaier		}
4209130613Smlaier		/* src node for translation rule */
4210130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4211130613Smlaier		    ((direction == PF_OUT &&
4212130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4213145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4214145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4215130613Smlaier			goto cleanup;
4216145836Smlaier		}
4217130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4218126258Smlaier		if (s == NULL) {
4219145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4220130613Smlaiercleanup:
4221130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4222130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4223130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4224130613Smlaier				pf_status.src_nodes--;
4225130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4226130613Smlaier			}
4227130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4228130613Smlaier			    nsn->expire == 0) {
4229130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4230130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4231130613Smlaier				pf_status.src_nodes--;
4232130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4233130613Smlaier			}
4234126258Smlaier			return (PF_DROP);
4235126258Smlaier		}
4236126258Smlaier		bzero(s, sizeof(*s));
4237126258Smlaier		s->rule.ptr = r;
4238130613Smlaier		s->nat_rule.ptr = nr;
4239126258Smlaier		s->anchor.ptr = a;
4240145836Smlaier		STATE_INC_COUNTERS(s);
4241126258Smlaier		s->allow_opts = r->allow_opts;
4242171168Smlaier		s->log = r->log & PF_LOG_ALL;
4243171168Smlaier		if (nr != NULL)
4244171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4245126258Smlaier		s->proto = pd->proto;
4246126258Smlaier		s->direction = direction;
4247126258Smlaier		s->af = af;
4248126258Smlaier		if (direction == PF_OUT) {
4249126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4250149884Smlaier			s->gwy.port = nport;
4251126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4252149884Smlaier			s->ext.port = 0;
4253149884Smlaier			if (nr != NULL) {
4254130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4255149884Smlaier				s->lan.port = bport;
4256149884Smlaier			} else {
4257126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4258149884Smlaier				s->lan.port = s->gwy.port;
4259149884Smlaier			}
4260126258Smlaier		} else {
4261126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4262149884Smlaier			s->lan.port = nport;
4263126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4264149884Smlaier			s->ext.port = 0;
4265149884Smlaier			if (nr != NULL) {
4266130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4267149884Smlaier				s->gwy.port = bport;
4268149884Smlaier			} else {
4269126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4270149884Smlaier				s->gwy.port = s->lan.port;
4271149884Smlaier			}
4272126258Smlaier		}
4273126261Smlaier		s->creation = time_second;
4274126261Smlaier		s->expire = time_second;
4275126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
4276126258Smlaier		pf_set_rt_ifp(s, saddr);
4277130613Smlaier		if (sn != NULL) {
4278130613Smlaier			s->src_node = sn;
4279130613Smlaier			s->src_node->states++;
4280130613Smlaier		}
4281130613Smlaier		if (nsn != NULL) {
4282130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4283130613Smlaier			s->nat_src_node = nsn;
4284130613Smlaier			s->nat_src_node->states++;
4285130613Smlaier		}
4286130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4287145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4288130613Smlaier			pf_src_tree_remove_state(s);
4289145836Smlaier			STATE_DEC_COUNTERS(s);
4290126258Smlaier			pool_put(&pf_state_pl, s);
4291126258Smlaier			return (PF_DROP);
4292126258Smlaier		} else
4293126258Smlaier			*sm = s;
4294145836Smlaier		if (tag > 0) {
4295145836Smlaier			pf_tag_ref(tag);
4296145836Smlaier			s->tag = tag;
4297145836Smlaier		}
4298126258Smlaier	}
4299126258Smlaier
4300126258Smlaier#ifdef INET6
4301126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
4302126258Smlaier	if (rewrite)
4303126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
4304126261Smlaier		    (caddr_t)pd->hdr.icmp6);
4305126258Smlaier#endif /* INET6 */
4306126258Smlaier
4307126258Smlaier	return (PF_PASS);
4308126258Smlaier}
4309126258Smlaier
4310126258Smlaierint
4311126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
4312130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4313145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
4314126258Smlaier{
4315130613Smlaier	struct pf_rule		*nr = NULL;
4316126258Smlaier	struct pf_rule		*r, *a = NULL;
4317126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4318130613Smlaier	struct pf_src_node	*nsn = NULL;
4319126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
4320126258Smlaier	sa_family_t		 af = pd->af;
4321126258Smlaier	u_short			 reason;
4322171168Smlaier	int			 tag = -1, rtableid = -1;
4323145836Smlaier	int			 asd = 0;
4324171168Smlaier	int			 match = 0;
4325126258Smlaier
4326145836Smlaier	if (pf_check_congestion(ifq)) {
4327145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
4328145836Smlaier		return (PF_DROP);
4329145836Smlaier	}
4330145836Smlaier
4331126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4332126258Smlaier
4333126258Smlaier	if (direction == PF_OUT) {
4334126258Smlaier		/* check outgoing packet for BINAT/NAT */
4335130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4336130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4337130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4338126258Smlaier			switch (af) {
4339126258Smlaier#ifdef INET
4340126258Smlaier			case AF_INET:
4341126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4342130613Smlaier				    pd->naddr.v4.s_addr, 0);
4343126258Smlaier				break;
4344126258Smlaier#endif /* INET */
4345126258Smlaier#ifdef INET6
4346126258Smlaier			case AF_INET6:
4347130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
4348126258Smlaier				break;
4349126258Smlaier#endif /* INET6 */
4350126258Smlaier			}
4351130613Smlaier			if (nr->natpass)
4352126258Smlaier				r = NULL;
4353130613Smlaier			pd->nat_rule = nr;
4354126258Smlaier		}
4355126258Smlaier	} else {
4356126258Smlaier		/* check incoming packet for BINAT/RDR */
4357130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4358130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4359130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4360126258Smlaier			switch (af) {
4361126258Smlaier#ifdef INET
4362126258Smlaier			case AF_INET:
4363126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4364130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4365126258Smlaier				break;
4366126258Smlaier#endif /* INET */
4367126258Smlaier#ifdef INET6
4368126258Smlaier			case AF_INET6:
4369130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
4370126258Smlaier				break;
4371126258Smlaier#endif /* INET6 */
4372126258Smlaier			}
4373130613Smlaier			if (nr->natpass)
4374126258Smlaier				r = NULL;
4375130613Smlaier			pd->nat_rule = nr;
4376126258Smlaier		}
4377126258Smlaier	}
4378126258Smlaier
4379126258Smlaier	while (r != NULL) {
4380126258Smlaier		r->evaluations++;
4381171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4382126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4383126258Smlaier		else if (r->direction && r->direction != direction)
4384126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4385126258Smlaier		else if (r->af && r->af != af)
4386126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4387126258Smlaier		else if (r->proto && r->proto != pd->proto)
4388126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4389171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4390171168Smlaier		    r->src.neg, kif))
4391126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4392171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4393171168Smlaier		    r->dst.neg, NULL))
4394126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4395171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4396126258Smlaier			r = TAILQ_NEXT(r, entries);
4397126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4398126258Smlaier			r = TAILQ_NEXT(r, entries);
4399145836Smlaier		else if (r->prob && r->prob <= arc4random())
4400126258Smlaier			r = TAILQ_NEXT(r, entries);
4401171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4402126258Smlaier			r = TAILQ_NEXT(r, entries);
4403126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4404126258Smlaier			r = TAILQ_NEXT(r, entries);
4405126258Smlaier		else {
4406126258Smlaier			if (r->tag)
4407126258Smlaier				tag = r->tag;
4408171168Smlaier			if (r->rtableid >= 0)
4409171168Smlaier				rtableid = r->rtableid;
4410126258Smlaier			if (r->anchor == NULL) {
4411171168Smlaier				match = 1;
4412126258Smlaier				*rm = r;
4413126258Smlaier				*am = a;
4414126258Smlaier				*rsm = ruleset;
4415126258Smlaier				if ((*rm)->quick)
4416126258Smlaier					break;
4417126258Smlaier				r = TAILQ_NEXT(r, entries);
4418126258Smlaier			} else
4419145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4420171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4421126258Smlaier		}
4422171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4423171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4424171168Smlaier			break;
4425126258Smlaier	}
4426126258Smlaier	r = *rm;
4427126258Smlaier	a = *am;
4428126258Smlaier	ruleset = *rsm;
4429126258Smlaier
4430126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4431130613Smlaier
4432171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log))
4433171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4434171168Smlaier		    a, ruleset, pd);
4435126258Smlaier
4436126258Smlaier	if ((r->action == PF_DROP) &&
4437126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4438126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4439126258Smlaier		struct pf_addr *a = NULL;
4440126258Smlaier
4441130613Smlaier		if (nr != NULL) {
4442130613Smlaier			if (direction == PF_OUT)
4443130613Smlaier				a = saddr;
4444130613Smlaier			else
4445130613Smlaier				a = daddr;
4446130613Smlaier		}
4447126258Smlaier		if (a != NULL) {
4448126258Smlaier			switch (af) {
4449126258Smlaier#ifdef INET
4450126258Smlaier			case AF_INET:
4451126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4452130613Smlaier				    pd->baddr.v4.s_addr, 0);
4453126258Smlaier				break;
4454126258Smlaier#endif /* INET */
4455126258Smlaier#ifdef INET6
4456126258Smlaier			case AF_INET6:
4457130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4458126258Smlaier				break;
4459126258Smlaier#endif /* INET6 */
4460126258Smlaier			}
4461126258Smlaier		}
4462126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4463126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4464126258Smlaier			    r->return_icmp & 255, af, r);
4465126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4466126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4467126258Smlaier			    r->return_icmp6 & 255, af, r);
4468126258Smlaier	}
4469126258Smlaier
4470126258Smlaier	if (r->action != PF_PASS)
4471126258Smlaier		return (PF_DROP);
4472126258Smlaier
4473171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4474126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4475126258Smlaier		return (PF_DROP);
4476126258Smlaier	}
4477126258Smlaier
4478130613Smlaier	if (r->keep_state || nr != NULL) {
4479126258Smlaier		/* create new state */
4480126258Smlaier		struct pf_state	*s = NULL;
4481130613Smlaier		struct pf_src_node *sn = NULL;
4482126258Smlaier
4483130613Smlaier		/* check maximums */
4484145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4485145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4486145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4487130613Smlaier			goto cleanup;
4488145836Smlaier		}
4489171168Smlaier		/* src node for filter rule */
4490130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4491130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4492145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4493145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4494130613Smlaier			goto cleanup;
4495145836Smlaier		}
4496130613Smlaier		/* src node for translation rule */
4497130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4498130613Smlaier		    ((direction == PF_OUT &&
4499130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4500145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4501145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4502130613Smlaier			goto cleanup;
4503145836Smlaier		}
4504130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4505126258Smlaier		if (s == NULL) {
4506145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4507130613Smlaiercleanup:
4508130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4509130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4510130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4511130613Smlaier				pf_status.src_nodes--;
4512130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4513130613Smlaier			}
4514130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4515130613Smlaier			    nsn->expire == 0) {
4516130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4517130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4518130613Smlaier				pf_status.src_nodes--;
4519130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4520130613Smlaier			}
4521126258Smlaier			return (PF_DROP);
4522126258Smlaier		}
4523126258Smlaier		bzero(s, sizeof(*s));
4524126258Smlaier		s->rule.ptr = r;
4525130613Smlaier		s->nat_rule.ptr = nr;
4526126258Smlaier		s->anchor.ptr = a;
4527145836Smlaier		STATE_INC_COUNTERS(s);
4528126258Smlaier		s->allow_opts = r->allow_opts;
4529171168Smlaier		s->log = r->log & PF_LOG_ALL;
4530171168Smlaier		if (nr != NULL)
4531171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4532126258Smlaier		s->proto = pd->proto;
4533126258Smlaier		s->direction = direction;
4534126258Smlaier		s->af = af;
4535126258Smlaier		if (direction == PF_OUT) {
4536126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4537126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4538130613Smlaier			if (nr != NULL)
4539130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4540126258Smlaier			else
4541126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4542126258Smlaier		} else {
4543126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4544126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4545130613Smlaier			if (nr != NULL)
4546130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4547126258Smlaier			else
4548126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4549126258Smlaier		}
4550126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4551126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4552126261Smlaier		s->creation = time_second;
4553126261Smlaier		s->expire = time_second;
4554126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4555126258Smlaier		pf_set_rt_ifp(s, saddr);
4556130613Smlaier		if (sn != NULL) {
4557130613Smlaier			s->src_node = sn;
4558130613Smlaier			s->src_node->states++;
4559130613Smlaier		}
4560130613Smlaier		if (nsn != NULL) {
4561130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4562130613Smlaier			s->nat_src_node = nsn;
4563130613Smlaier			s->nat_src_node->states++;
4564130613Smlaier		}
4565130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4566145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4567130613Smlaier			pf_src_tree_remove_state(s);
4568145836Smlaier			STATE_DEC_COUNTERS(s);
4569126258Smlaier			pool_put(&pf_state_pl, s);
4570126258Smlaier			return (PF_DROP);
4571126258Smlaier		} else
4572126258Smlaier			*sm = s;
4573145836Smlaier		if (tag > 0) {
4574145836Smlaier			pf_tag_ref(tag);
4575145836Smlaier			s->tag = tag;
4576145836Smlaier		}
4577126258Smlaier	}
4578126258Smlaier
4579126258Smlaier	return (PF_PASS);
4580126258Smlaier}
4581126258Smlaier
4582126258Smlaierint
4583130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4584126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4585126258Smlaier    struct pf_ruleset **rsm)
4586126258Smlaier{
4587126258Smlaier	struct pf_rule		*r, *a = NULL;
4588126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4589126258Smlaier	sa_family_t		 af = pd->af;
4590126258Smlaier	u_short			 reason;
4591126258Smlaier	int			 tag = -1;
4592145836Smlaier	int			 asd = 0;
4593171168Smlaier	int			 match = 0;
4594126258Smlaier
4595126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4596126258Smlaier	while (r != NULL) {
4597126258Smlaier		r->evaluations++;
4598171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4599126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4600126258Smlaier		else if (r->direction && r->direction != direction)
4601126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4602126258Smlaier		else if (r->af && r->af != af)
4603126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4604126258Smlaier		else if (r->proto && r->proto != pd->proto)
4605126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4606171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4607171168Smlaier		    r->src.neg, kif))
4608126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4609171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4610171168Smlaier		    r->dst.neg, NULL))
4611126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4612171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4613126258Smlaier			r = TAILQ_NEXT(r, entries);
4614173815Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4615126258Smlaier			r = TAILQ_NEXT(r, entries);
4616173815Smlaier		else if (pd->proto == IPPROTO_UDP &&
4617173815Smlaier		    (r->src.port_op || r->dst.port_op))
4618173815Smlaier			r = TAILQ_NEXT(r, entries);
4619173815Smlaier		else if (pd->proto == IPPROTO_TCP &&
4620173815Smlaier		    (r->src.port_op || r->dst.port_op || r->flagset))
4621173815Smlaier			r = TAILQ_NEXT(r, entries);
4622173815Smlaier		else if ((pd->proto == IPPROTO_ICMP ||
4623173815Smlaier		    pd->proto == IPPROTO_ICMPV6) &&
4624173815Smlaier		    (r->type || r->code))
4625173815Smlaier			r = TAILQ_NEXT(r, entries);
4626145836Smlaier		else if (r->prob && r->prob <= arc4random())
4627126258Smlaier			r = TAILQ_NEXT(r, entries);
4628171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4629126258Smlaier			r = TAILQ_NEXT(r, entries);
4630126258Smlaier		else {
4631126258Smlaier			if (r->anchor == NULL) {
4632171168Smlaier				match = 1;
4633126258Smlaier				*rm = r;
4634126258Smlaier				*am = a;
4635126258Smlaier				*rsm = ruleset;
4636126258Smlaier				if ((*rm)->quick)
4637126258Smlaier					break;
4638126258Smlaier				r = TAILQ_NEXT(r, entries);
4639126258Smlaier			} else
4640145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4641171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4642126258Smlaier		}
4643171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4644171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4645171168Smlaier			break;
4646126258Smlaier	}
4647126258Smlaier	r = *rm;
4648126258Smlaier	a = *am;
4649126258Smlaier	ruleset = *rsm;
4650126258Smlaier
4651126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4652130613Smlaier
4653126258Smlaier	if (r->log)
4654171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
4655171168Smlaier		    pd);
4656126258Smlaier
4657126258Smlaier	if (r->action != PF_PASS)
4658126258Smlaier		return (PF_DROP);
4659126258Smlaier
4660171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
4661126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4662126258Smlaier		return (PF_DROP);
4663126258Smlaier	}
4664126258Smlaier
4665126258Smlaier	return (PF_PASS);
4666126258Smlaier}
4667126258Smlaier
4668126258Smlaierint
4669130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4670130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4671126258Smlaier    u_short *reason)
4672126258Smlaier{
4673171168Smlaier	struct pf_state_cmp	 key;
4674126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4675126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4676145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4677126258Smlaier	u_int8_t		 sws, dws;
4678130613Smlaier	int			 ackskew;
4679126258Smlaier	int			 copyback = 0;
4680126258Smlaier	struct pf_state_peer	*src, *dst;
4681126258Smlaier
4682126258Smlaier	key.af = pd->af;
4683126258Smlaier	key.proto = IPPROTO_TCP;
4684130613Smlaier	if (direction == PF_IN)	{
4685130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4686130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4687130613Smlaier		key.ext.port = th->th_sport;
4688130613Smlaier		key.gwy.port = th->th_dport;
4689130613Smlaier	} else {
4690130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4691130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4692130613Smlaier		key.lan.port = th->th_sport;
4693130613Smlaier		key.ext.port = th->th_dport;
4694130613Smlaier	}
4695126258Smlaier
4696126258Smlaier	STATE_LOOKUP();
4697126258Smlaier
4698126258Smlaier	if (direction == (*state)->direction) {
4699126258Smlaier		src = &(*state)->src;
4700126258Smlaier		dst = &(*state)->dst;
4701126258Smlaier	} else {
4702126258Smlaier		src = &(*state)->dst;
4703126258Smlaier		dst = &(*state)->src;
4704126258Smlaier	}
4705126258Smlaier
4706126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4707145836Smlaier		if (direction != (*state)->direction) {
4708145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4709126258Smlaier			return (PF_SYNPROXY_DROP);
4710145836Smlaier		}
4711126258Smlaier		if (th->th_flags & TH_SYN) {
4712145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4713145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4714126258Smlaier				return (PF_DROP);
4715145836Smlaier			}
4716162238Scsjp#ifdef __FreeBSD__
4717162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4718162238Scsjp#else
4719126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4720162238Scsjp#endif
4721126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4722126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4723145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4724171168Smlaier			    0, NULL, NULL);
4725145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4726126258Smlaier			return (PF_SYNPROXY_DROP);
4727126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4728126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4729145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4730145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4731126258Smlaier			return (PF_DROP);
4732145836Smlaier		} else if ((*state)->src_node != NULL &&
4733145836Smlaier		    pf_src_connlimit(state)) {
4734145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4735145836Smlaier			return (PF_DROP);
4736145836Smlaier		} else
4737126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4738126258Smlaier	}
4739126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4740126258Smlaier		struct pf_state_host *src, *dst;
4741126258Smlaier
4742126258Smlaier		if (direction == PF_OUT) {
4743126258Smlaier			src = &(*state)->gwy;
4744126258Smlaier			dst = &(*state)->ext;
4745126258Smlaier		} else {
4746126258Smlaier			src = &(*state)->ext;
4747126258Smlaier			dst = &(*state)->lan;
4748126258Smlaier		}
4749126258Smlaier		if (direction == (*state)->direction) {
4750126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4751126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4752145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4753145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4754126258Smlaier				return (PF_DROP);
4755145836Smlaier			}
4756126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4757126258Smlaier			if ((*state)->dst.seqhi == 1)
4758145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4759162238Scsjp#ifdef __FreeBSD__
4760162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4761162238Scsjp			    &src->addr,
4762162238Scsjp#else
4763126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4764162238Scsjp#endif
4765126258Smlaier			    &dst->addr, src->port, dst->port,
4766130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4767171168Smlaier			    (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
4768145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4769126258Smlaier			return (PF_SYNPROXY_DROP);
4770126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4771126258Smlaier		    (TH_SYN|TH_ACK)) ||
4772145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4773145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4774126258Smlaier			return (PF_DROP);
4775145836Smlaier		} else {
4776126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4777126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4778162238Scsjp#ifdef __FreeBSD__
4779162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4780162238Scsjp#else
4781126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4782162238Scsjp#endif
4783126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4784126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4785145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4786171168Smlaier			    (*state)->tag, NULL, NULL);
4787162238Scsjp#ifdef __FreeBSD__
4788162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4789162238Scsjp			    &src->addr,
4790162238Scsjp#else
4791126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4792162238Scsjp#endif
4793126258Smlaier			    &dst->addr, src->port, dst->port,
4794126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4795145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4796171168Smlaier			    0, NULL, NULL);
4797126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4798126258Smlaier			    (*state)->src.seqlo;
4799126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4800126258Smlaier			    (*state)->dst.seqlo;
4801126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4802145875Smlaier			    (*state)->dst.max_win;
4803145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4804145836Smlaier			    (*state)->src.max_win;
4805126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4806126258Smlaier			(*state)->src.state = (*state)->dst.state =
4807126258Smlaier			    TCPS_ESTABLISHED;
4808145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4809126258Smlaier			return (PF_SYNPROXY_DROP);
4810126258Smlaier		}
4811126258Smlaier	}
4812126258Smlaier
4813181295Smlaier	if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
4814181295Smlaier	    dst->state >= TCPS_FIN_WAIT_2 &&
4815181295Smlaier	    src->state >= TCPS_FIN_WAIT_2) {
4816181295Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4817181295Smlaier			printf("pf: state reuse ");
4818181295Smlaier			pf_print_state(*state);
4819181295Smlaier			pf_print_flags(th->th_flags);
4820181295Smlaier			printf("\n");
4821181295Smlaier		}
4822181295Smlaier		/* XXX make sure it's the same direction ?? */
4823181295Smlaier		(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
4824181295Smlaier		pf_unlink_state(*state);
4825181295Smlaier		*state = NULL;
4826181295Smlaier		return (PF_DROP);
4827181295Smlaier	}
4828181295Smlaier
4829126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4830126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4831126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4832126258Smlaier	} else
4833126258Smlaier		sws = dws = 0;
4834126258Smlaier
4835126258Smlaier	/*
4836126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4837126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4838126258Smlaier	 *	tcp_filtering.ps
4839126258Smlaier	 */
4840126258Smlaier
4841145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4842126258Smlaier	if (src->seqlo == 0) {
4843126258Smlaier		/* First packet from this end. Set its state */
4844126258Smlaier
4845126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4846126258Smlaier		    src->scrub == NULL) {
4847126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4848126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4849126258Smlaier				return (PF_DROP);
4850126258Smlaier			}
4851126258Smlaier		}
4852126258Smlaier
4853126258Smlaier		/* Deferred generation of sequence number modulator */
4854126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4855171168Smlaier#ifdef __FreeBSD__
4856171168Smlaier			while ((src->seqdiff = pf_new_isn(*state) - seq) == 0)
4857126258Smlaier				;
4858171168Smlaier#else
4859171168Smlaier			while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
4860171168Smlaier				;
4861171168Smlaier#endif
4862126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4863126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4864126258Smlaier			    src->seqdiff), 0);
4865126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4866126258Smlaier			copyback = 1;
4867126258Smlaier		} else {
4868126258Smlaier			ack = ntohl(th->th_ack);
4869126258Smlaier		}
4870126258Smlaier
4871126258Smlaier		end = seq + pd->p_len;
4872126258Smlaier		if (th->th_flags & TH_SYN) {
4873126258Smlaier			end++;
4874126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4875126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4876126258Smlaier				    pd->af);
4877126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4878126258Smlaier					/* Remove scale factor from initial
4879126258Smlaier					 * window */
4880126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4881126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4882126258Smlaier					    >> sws;
4883126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4884126258Smlaier				} else {
4885126258Smlaier					/* fixup other window */
4886126258Smlaier					dst->max_win <<= dst->wscale &
4887126258Smlaier					    PF_WSCALE_MASK;
4888126258Smlaier					/* in case of a retrans SYN|ACK */
4889126258Smlaier					dst->wscale = 0;
4890126258Smlaier				}
4891126258Smlaier			}
4892126258Smlaier		}
4893126258Smlaier		if (th->th_flags & TH_FIN)
4894126258Smlaier			end++;
4895126258Smlaier
4896126258Smlaier		src->seqlo = seq;
4897126258Smlaier		if (src->state < TCPS_SYN_SENT)
4898126258Smlaier			src->state = TCPS_SYN_SENT;
4899126258Smlaier
4900126258Smlaier		/*
4901126258Smlaier		 * May need to slide the window (seqhi may have been set by
4902126258Smlaier		 * the crappy stack check or if we picked up the connection
4903126258Smlaier		 * after establishment)
4904126258Smlaier		 */
4905126258Smlaier		if (src->seqhi == 1 ||
4906126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4907126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4908126258Smlaier		if (win > src->max_win)
4909126258Smlaier			src->max_win = win;
4910126258Smlaier
4911126258Smlaier	} else {
4912126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4913126258Smlaier		if (src->seqdiff) {
4914126258Smlaier			/* Modulate sequence numbers */
4915126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4916126258Smlaier			    src->seqdiff), 0);
4917126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4918126258Smlaier			copyback = 1;
4919126258Smlaier		}
4920126258Smlaier		end = seq + pd->p_len;
4921126258Smlaier		if (th->th_flags & TH_SYN)
4922126258Smlaier			end++;
4923126258Smlaier		if (th->th_flags & TH_FIN)
4924126258Smlaier			end++;
4925126258Smlaier	}
4926126258Smlaier
4927126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4928126258Smlaier		/* Let it pass through the ack skew check */
4929126258Smlaier		ack = dst->seqlo;
4930126258Smlaier	} else if ((ack == 0 &&
4931126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4932126258Smlaier	    /* broken tcp stacks do not set ack */
4933126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4934126258Smlaier		/*
4935126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4936126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4937126258Smlaier		 */
4938126258Smlaier		ack = dst->seqlo;
4939126258Smlaier	}
4940126258Smlaier
4941126258Smlaier	if (seq == end) {
4942126258Smlaier		/* Ease sequencing restrictions on no data packets */
4943126258Smlaier		seq = src->seqlo;
4944126258Smlaier		end = seq;
4945126258Smlaier	}
4946126258Smlaier
4947126258Smlaier	ackskew = dst->seqlo - ack;
4948126258Smlaier
4949171168Smlaier
4950171168Smlaier	/*
4951171168Smlaier	 * Need to demodulate the sequence numbers in any TCP SACK options
4952171168Smlaier	 * (Selective ACK). We could optionally validate the SACK values
4953171168Smlaier	 * against the current ACK window, either forwards or backwards, but
4954171168Smlaier	 * I'm not confident that SACK has been implemented properly
4955171168Smlaier	 * everywhere. It wouldn't surprise me if several stacks accidently
4956171168Smlaier	 * SACK too far backwards of previously ACKed data. There really aren't
4957171168Smlaier	 * any security implications of bad SACKing unless the target stack
4958171168Smlaier	 * doesn't validate the option length correctly. Someone trying to
4959171168Smlaier	 * spoof into a TCP connection won't bother blindly sending SACK
4960171168Smlaier	 * options anyway.
4961171168Smlaier	 */
4962171168Smlaier	if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
4963171168Smlaier		if (pf_modulate_sack(m, off, pd, th, dst))
4964171168Smlaier			copyback = 1;
4965171168Smlaier	}
4966171168Smlaier
4967171168Smlaier
4968126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4969126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4970126258Smlaier	    /* Last octet inside other's window space */
4971126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4972126258Smlaier	    /* Retrans: not more than one window back */
4973126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4974126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4975145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4976126258Smlaier	    /* Acking not more than one window forward */
4977145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4978171168Smlaier	    (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
4979171168Smlaier	    /* Require an exact/+1 sequence match on resets when possible */
4980126258Smlaier
4981145836Smlaier		if (dst->scrub || src->scrub) {
4982145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4983145836Smlaier			    *state, src, dst, &copyback))
4984145836Smlaier				return (PF_DROP);
4985145836Smlaier		}
4986145836Smlaier
4987126258Smlaier		/* update max window */
4988126258Smlaier		if (src->max_win < win)
4989126258Smlaier			src->max_win = win;
4990126258Smlaier		/* synchronize sequencing */
4991126258Smlaier		if (SEQ_GT(end, src->seqlo))
4992126258Smlaier			src->seqlo = end;
4993126258Smlaier		/* slide the window of what the other end can send */
4994126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4995126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4996126258Smlaier
4997126258Smlaier
4998126258Smlaier		/* update states */
4999126258Smlaier		if (th->th_flags & TH_SYN)
5000126258Smlaier			if (src->state < TCPS_SYN_SENT)
5001126258Smlaier				src->state = TCPS_SYN_SENT;
5002126258Smlaier		if (th->th_flags & TH_FIN)
5003126258Smlaier			if (src->state < TCPS_CLOSING)
5004126258Smlaier				src->state = TCPS_CLOSING;
5005126258Smlaier		if (th->th_flags & TH_ACK) {
5006145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
5007126258Smlaier				dst->state = TCPS_ESTABLISHED;
5008145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
5009145836Smlaier				    (*state)->src_node != NULL &&
5010145836Smlaier				    pf_src_connlimit(state)) {
5011145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
5012145836Smlaier					return (PF_DROP);
5013145836Smlaier				}
5014145836Smlaier			} else if (dst->state == TCPS_CLOSING)
5015126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
5016126258Smlaier		}
5017126258Smlaier		if (th->th_flags & TH_RST)
5018126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
5019126258Smlaier
5020126258Smlaier		/* update expire time */
5021126261Smlaier		(*state)->expire = time_second;
5022126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
5023126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
5024126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
5025171168Smlaier		else if (src->state >= TCPS_CLOSING &&
5026171168Smlaier		    dst->state >= TCPS_CLOSING)
5027126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
5028126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
5029126258Smlaier		    dst->state < TCPS_ESTABLISHED)
5030126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
5031126258Smlaier		else if (src->state >= TCPS_CLOSING ||
5032126258Smlaier		    dst->state >= TCPS_CLOSING)
5033126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
5034126258Smlaier		else
5035126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
5036126258Smlaier
5037126258Smlaier		/* Fall through to PASS packet */
5038126258Smlaier
5039126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
5040126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
5041126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
5042126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
5043126258Smlaier	    /* Within a window forward of the originating packet */
5044126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
5045126258Smlaier	    /* Within a window backward of the originating packet */
5046126258Smlaier
5047126258Smlaier		/*
5048126258Smlaier		 * This currently handles three situations:
5049126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
5050126258Smlaier		 *     replies.
5051126258Smlaier		 *  2) When PF catches an already established stream (the
5052126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
5053126258Smlaier		 *     changed...)
5054126258Smlaier		 *  3) Packets get funky immediately after the connection
5055126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
5056126258Smlaier		 *     that web servers like to spew after a close)
5057126258Smlaier		 *
5058126258Smlaier		 * This must be a little more careful than the above code
5059126258Smlaier		 * since packet floods will also be caught here. We don't
5060126258Smlaier		 * update the TTL here to mitigate the damage of a packet
5061126258Smlaier		 * flood and so the same code can handle awkward establishment
5062126258Smlaier		 * and a loosened connection close.
5063126258Smlaier		 * In the establishment case, a correct peer response will
5064126258Smlaier		 * validate the connection, go through the normal state code
5065126258Smlaier		 * and keep updating the state TTL.
5066126258Smlaier		 */
5067126258Smlaier
5068126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
5069126258Smlaier			printf("pf: loose state match: ");
5070126258Smlaier			pf_print_state(*state);
5071126258Smlaier			pf_print_flags(th->th_flags);
5072171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5073171168Smlaier			    "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
5074171168Smlaier#ifdef __FreeBSD__
5075171168Smlaier			    ackskew, (unsigned long long)(*state)->packets[0],
5076171168Smlaier			    (unsigned long long)(*state)->packets[1]);
5077171168Smlaier#else
5078171168Smlaier			    ackskew, (*state)->packets[0],
5079171168Smlaier			    (*state)->packets[1]);
5080171168Smlaier#endif
5081126258Smlaier		}
5082126258Smlaier
5083145836Smlaier		if (dst->scrub || src->scrub) {
5084145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
5085145836Smlaier			    *state, src, dst, &copyback))
5086145836Smlaier				return (PF_DROP);
5087145836Smlaier		}
5088145836Smlaier
5089126258Smlaier		/* update max window */
5090126258Smlaier		if (src->max_win < win)
5091126258Smlaier			src->max_win = win;
5092126258Smlaier		/* synchronize sequencing */
5093126258Smlaier		if (SEQ_GT(end, src->seqlo))
5094126258Smlaier			src->seqlo = end;
5095126258Smlaier		/* slide the window of what the other end can send */
5096126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
5097126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
5098126258Smlaier
5099126258Smlaier		/*
5100126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
5101126258Smlaier		 * SYN and not an already established connection.
5102126258Smlaier		 */
5103126258Smlaier
5104126258Smlaier		if (th->th_flags & TH_FIN)
5105126258Smlaier			if (src->state < TCPS_CLOSING)
5106126258Smlaier				src->state = TCPS_CLOSING;
5107126258Smlaier		if (th->th_flags & TH_RST)
5108126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
5109126258Smlaier
5110126258Smlaier		/* Fall through to PASS packet */
5111126258Smlaier
5112126258Smlaier	} else {
5113126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
5114126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
5115126258Smlaier			/* Send RST for state mismatches during handshake */
5116145836Smlaier			if (!(th->th_flags & TH_RST))
5117162238Scsjp#ifdef __FreeBSD__
5118162238Scsjp				pf_send_tcp(m, (*state)->rule.ptr, pd->af,
5119162238Scsjp#else
5120126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
5121162238Scsjp#endif
5122126258Smlaier				    pd->dst, pd->src, th->th_dport,
5123145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
5124145836Smlaier				    TH_RST, 0, 0,
5125171168Smlaier				    (*state)->rule.ptr->return_ttl, 1, 0,
5126145836Smlaier				    pd->eh, kif->pfik_ifp);
5127126258Smlaier			src->seqlo = 0;
5128126258Smlaier			src->seqhi = 1;
5129126258Smlaier			src->max_win = 1;
5130126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
5131126258Smlaier			printf("pf: BAD state: ");
5132126258Smlaier			pf_print_state(*state);
5133126258Smlaier			pf_print_flags(th->th_flags);
5134171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5135171168Smlaier			    "pkts=%llu:%llu dir=%s,%s\n",
5136171168Smlaier			    seq, orig_seq, ack, pd->p_len, ackskew,
5137171168Smlaier#ifdef __FreeBSD__
5138171168Smlaier			    (unsigned long long)(*state)->packets[0],
5139171168Smlaier			    (unsigned long long)(*state)->packets[1],
5140171168Smlaier#else
5141126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
5142171168Smlaier#endif
5143126258Smlaier			    direction == PF_IN ? "in" : "out",
5144126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
5145126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
5146126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
5147126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
5148126258Smlaier			    ' ': '2',
5149126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
5150126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
5151126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
5152126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
5153126258Smlaier		}
5154145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
5155126258Smlaier		return (PF_DROP);
5156126258Smlaier	}
5157126258Smlaier
5158126258Smlaier	/* Any packets which have gotten here are to be passed */
5159126258Smlaier
5160126258Smlaier	/* translate source/destination address, if necessary */
5161126258Smlaier	if (STATE_TRANSLATE(*state)) {
5162126258Smlaier		if (direction == PF_OUT)
5163126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
5164126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
5165126258Smlaier			    (*state)->gwy.port, 0, pd->af);
5166126258Smlaier		else
5167126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
5168126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
5169126258Smlaier			    (*state)->lan.port, 0, pd->af);
5170126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5171126258Smlaier	} else if (copyback) {
5172126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
5173126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5174126258Smlaier	}
5175126258Smlaier
5176126258Smlaier	return (PF_PASS);
5177126258Smlaier}
5178126258Smlaier
5179126258Smlaierint
5180130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
5181130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
5182126258Smlaier{
5183126258Smlaier	struct pf_state_peer	*src, *dst;
5184171168Smlaier	struct pf_state_cmp	 key;
5185126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
5186126258Smlaier
5187126258Smlaier	key.af = pd->af;
5188126258Smlaier	key.proto = IPPROTO_UDP;
5189130613Smlaier	if (direction == PF_IN)	{
5190130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5191130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5192130613Smlaier		key.ext.port = uh->uh_sport;
5193130613Smlaier		key.gwy.port = uh->uh_dport;
5194130613Smlaier	} else {
5195130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5196130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5197130613Smlaier		key.lan.port = uh->uh_sport;
5198130613Smlaier		key.ext.port = uh->uh_dport;
5199130613Smlaier	}
5200126258Smlaier
5201126258Smlaier	STATE_LOOKUP();
5202126258Smlaier
5203126258Smlaier	if (direction == (*state)->direction) {
5204126258Smlaier		src = &(*state)->src;
5205126258Smlaier		dst = &(*state)->dst;
5206126258Smlaier	} else {
5207126258Smlaier		src = &(*state)->dst;
5208126258Smlaier		dst = &(*state)->src;
5209126258Smlaier	}
5210126258Smlaier
5211126258Smlaier	/* update states */
5212126258Smlaier	if (src->state < PFUDPS_SINGLE)
5213126258Smlaier		src->state = PFUDPS_SINGLE;
5214126258Smlaier	if (dst->state == PFUDPS_SINGLE)
5215126258Smlaier		dst->state = PFUDPS_MULTIPLE;
5216126258Smlaier
5217126258Smlaier	/* update expire time */
5218126261Smlaier	(*state)->expire = time_second;
5219126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
5220126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
5221126258Smlaier	else
5222126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
5223126258Smlaier
5224126258Smlaier	/* translate source/destination address, if necessary */
5225126258Smlaier	if (STATE_TRANSLATE(*state)) {
5226126258Smlaier		if (direction == PF_OUT)
5227126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
5228126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
5229126258Smlaier			    (*state)->gwy.port, 1, pd->af);
5230126258Smlaier		else
5231126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
5232126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
5233126258Smlaier			    (*state)->lan.port, 1, pd->af);
5234126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
5235126258Smlaier	}
5236126258Smlaier
5237126258Smlaier	return (PF_PASS);
5238126258Smlaier}
5239126258Smlaier
5240126258Smlaierint
5241130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
5242145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
5243126258Smlaier{
5244126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
5245127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
5246127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
5247127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
5248130613Smlaier	int		 state_icmp = 0;
5249171168Smlaier	struct pf_state_cmp key;
5250126258Smlaier
5251126258Smlaier	switch (pd->proto) {
5252126258Smlaier#ifdef INET
5253126258Smlaier	case IPPROTO_ICMP:
5254126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
5255126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
5256126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
5257126258Smlaier
5258126258Smlaier		if (icmptype == ICMP_UNREACH ||
5259126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
5260126258Smlaier		    icmptype == ICMP_REDIRECT ||
5261126258Smlaier		    icmptype == ICMP_TIMXCEED ||
5262126258Smlaier		    icmptype == ICMP_PARAMPROB)
5263126258Smlaier			state_icmp++;
5264126258Smlaier		break;
5265126258Smlaier#endif /* INET */
5266126258Smlaier#ifdef INET6
5267126258Smlaier	case IPPROTO_ICMPV6:
5268126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
5269126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
5270126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
5271126258Smlaier
5272126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
5273126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
5274126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
5275126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
5276126258Smlaier			state_icmp++;
5277126258Smlaier		break;
5278126258Smlaier#endif /* INET6 */
5279126258Smlaier	}
5280126258Smlaier
5281126258Smlaier	if (!state_icmp) {
5282126258Smlaier
5283126258Smlaier		/*
5284126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
5285126258Smlaier		 * Search for an ICMP state.
5286126258Smlaier		 */
5287126258Smlaier		key.af = pd->af;
5288126258Smlaier		key.proto = pd->proto;
5289130613Smlaier		if (direction == PF_IN)	{
5290130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
5291130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5292149884Smlaier			key.ext.port = 0;
5293130613Smlaier			key.gwy.port = icmpid;
5294130613Smlaier		} else {
5295130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
5296130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
5297130613Smlaier			key.lan.port = icmpid;
5298149884Smlaier			key.ext.port = 0;
5299130613Smlaier		}
5300126258Smlaier
5301126258Smlaier		STATE_LOOKUP();
5302126258Smlaier
5303126261Smlaier		(*state)->expire = time_second;
5304126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
5305126258Smlaier
5306126258Smlaier		/* translate source/destination address, if necessary */
5307149884Smlaier		if (STATE_TRANSLATE(*state)) {
5308126258Smlaier			if (direction == PF_OUT) {
5309126258Smlaier				switch (pd->af) {
5310126258Smlaier#ifdef INET
5311126258Smlaier				case AF_INET:
5312126258Smlaier					pf_change_a(&saddr->v4.s_addr,
5313126258Smlaier					    pd->ip_sum,
5314126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
5315149884Smlaier					pd->hdr.icmp->icmp_cksum =
5316149884Smlaier					    pf_cksum_fixup(
5317149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5318149884Smlaier					    (*state)->gwy.port, 0);
5319149884Smlaier					pd->hdr.icmp->icmp_id =
5320149884Smlaier					    (*state)->gwy.port;
5321149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5322149893Smlaier					    (caddr_t)pd->hdr.icmp);
5323126258Smlaier					break;
5324126258Smlaier#endif /* INET */
5325126258Smlaier#ifdef INET6
5326126258Smlaier				case AF_INET6:
5327126258Smlaier					pf_change_a6(saddr,
5328126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5329126258Smlaier					    &(*state)->gwy.addr, 0);
5330126258Smlaier					m_copyback(m, off,
5331126258Smlaier					    sizeof(struct icmp6_hdr),
5332126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5333126258Smlaier					break;
5334126258Smlaier#endif /* INET6 */
5335126258Smlaier				}
5336126258Smlaier			} else {
5337126258Smlaier				switch (pd->af) {
5338126258Smlaier#ifdef INET
5339126258Smlaier				case AF_INET:
5340126258Smlaier					pf_change_a(&daddr->v4.s_addr,
5341126258Smlaier					    pd->ip_sum,
5342126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
5343149884Smlaier					pd->hdr.icmp->icmp_cksum =
5344149884Smlaier					    pf_cksum_fixup(
5345149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5346149884Smlaier					    (*state)->lan.port, 0);
5347149884Smlaier					pd->hdr.icmp->icmp_id =
5348149884Smlaier					    (*state)->lan.port;
5349149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5350149893Smlaier					    (caddr_t)pd->hdr.icmp);
5351126258Smlaier					break;
5352126258Smlaier#endif /* INET */
5353126258Smlaier#ifdef INET6
5354126258Smlaier				case AF_INET6:
5355126258Smlaier					pf_change_a6(daddr,
5356126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5357126258Smlaier					    &(*state)->lan.addr, 0);
5358126258Smlaier					m_copyback(m, off,
5359126258Smlaier					    sizeof(struct icmp6_hdr),
5360126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5361126258Smlaier					break;
5362126258Smlaier#endif /* INET6 */
5363126258Smlaier				}
5364126258Smlaier			}
5365126258Smlaier		}
5366126258Smlaier
5367126258Smlaier		return (PF_PASS);
5368126258Smlaier
5369126258Smlaier	} else {
5370126258Smlaier		/*
5371126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
5372126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
5373126258Smlaier		 */
5374126258Smlaier
5375126258Smlaier		struct pf_pdesc	pd2;
5376126258Smlaier#ifdef INET
5377126258Smlaier		struct ip	h2;
5378126258Smlaier#endif /* INET */
5379126258Smlaier#ifdef INET6
5380126258Smlaier		struct ip6_hdr	h2_6;
5381126258Smlaier		int		terminal = 0;
5382126258Smlaier#endif /* INET6 */
5383127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
5384127629Smlaier		int		off2 = 0;	/* make the compiler happy */
5385126258Smlaier
5386126258Smlaier		pd2.af = pd->af;
5387126258Smlaier		switch (pd->af) {
5388126258Smlaier#ifdef INET
5389126258Smlaier		case AF_INET:
5390126258Smlaier			/* offset of h2 in mbuf chain */
5391126258Smlaier			ipoff2 = off + ICMP_MINLEN;
5392126258Smlaier
5393126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
5394145836Smlaier			    NULL, reason, pd2.af)) {
5395126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5396126258Smlaier				    ("pf: ICMP error message too short "
5397126258Smlaier				    "(ip)\n"));
5398126258Smlaier				return (PF_DROP);
5399126258Smlaier			}
5400126258Smlaier			/*
5401126258Smlaier			 * ICMP error messages don't refer to non-first
5402126258Smlaier			 * fragments
5403126258Smlaier			 */
5404145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
5405145836Smlaier				REASON_SET(reason, PFRES_FRAG);
5406126258Smlaier				return (PF_DROP);
5407145836Smlaier			}
5408126258Smlaier
5409126258Smlaier			/* offset of protocol header that follows h2 */
5410126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
5411126258Smlaier
5412126258Smlaier			pd2.proto = h2.ip_p;
5413126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
5414126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
5415126258Smlaier			pd2.ip_sum = &h2.ip_sum;
5416126258Smlaier			break;
5417126258Smlaier#endif /* INET */
5418126258Smlaier#ifdef INET6
5419126258Smlaier		case AF_INET6:
5420126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
5421126258Smlaier
5422126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
5423145836Smlaier			    NULL, reason, pd2.af)) {
5424126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5425126258Smlaier				    ("pf: ICMP error message too short "
5426126258Smlaier				    "(ip6)\n"));
5427126258Smlaier				return (PF_DROP);
5428126258Smlaier			}
5429126258Smlaier			pd2.proto = h2_6.ip6_nxt;
5430126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
5431126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
5432126258Smlaier			pd2.ip_sum = NULL;
5433126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
5434126258Smlaier			do {
5435126258Smlaier				switch (pd2.proto) {
5436126258Smlaier				case IPPROTO_FRAGMENT:
5437126258Smlaier					/*
5438126258Smlaier					 * ICMPv6 error messages for
5439126258Smlaier					 * non-first fragments
5440126258Smlaier					 */
5441145836Smlaier					REASON_SET(reason, PFRES_FRAG);
5442126258Smlaier					return (PF_DROP);
5443126258Smlaier				case IPPROTO_AH:
5444126258Smlaier				case IPPROTO_HOPOPTS:
5445126258Smlaier				case IPPROTO_ROUTING:
5446126258Smlaier				case IPPROTO_DSTOPTS: {
5447126258Smlaier					/* get next header and header length */
5448126258Smlaier					struct ip6_ext opt6;
5449126258Smlaier
5450126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5451145836Smlaier					    sizeof(opt6), NULL, reason,
5452145836Smlaier					    pd2.af)) {
5453126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5454126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5455126258Smlaier						return (PF_DROP);
5456126258Smlaier					}
5457126258Smlaier					if (pd2.proto == IPPROTO_AH)
5458126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5459126258Smlaier					else
5460126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5461126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5462126258Smlaier					/* goto the next header */
5463126258Smlaier					break;
5464126258Smlaier				}
5465126258Smlaier				default:
5466126258Smlaier					terminal++;
5467126258Smlaier					break;
5468126258Smlaier				}
5469126258Smlaier			} while (!terminal);
5470126258Smlaier			break;
5471126258Smlaier#endif /* INET6 */
5472171168Smlaier#ifdef __FreeBSD__
5473171168Smlaier		default:
5474171168Smlaier			panic("AF not supported: %d", pd->af);
5475171168Smlaier#endif
5476126258Smlaier		}
5477126258Smlaier
5478126258Smlaier		switch (pd2.proto) {
5479126258Smlaier		case IPPROTO_TCP: {
5480126258Smlaier			struct tcphdr		 th;
5481126258Smlaier			u_int32_t		 seq;
5482126258Smlaier			struct pf_state_peer	*src, *dst;
5483126258Smlaier			u_int8_t		 dws;
5484128129Smlaier			int			 copyback = 0;
5485126258Smlaier
5486126258Smlaier			/*
5487126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5488126258Smlaier			 * expected. Don't access any TCP header fields after
5489126258Smlaier			 * th_seq, an ackskew test is not possible.
5490126258Smlaier			 */
5491145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5492145836Smlaier			    pd2.af)) {
5493126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5494126258Smlaier				    ("pf: ICMP error message too short "
5495126258Smlaier				    "(tcp)\n"));
5496126258Smlaier				return (PF_DROP);
5497126258Smlaier			}
5498126258Smlaier
5499126258Smlaier			key.af = pd2.af;
5500126258Smlaier			key.proto = IPPROTO_TCP;
5501130613Smlaier			if (direction == PF_IN)	{
5502130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5503130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5504130613Smlaier				key.ext.port = th.th_dport;
5505130613Smlaier				key.gwy.port = th.th_sport;
5506130613Smlaier			} else {
5507130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5508130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5509130613Smlaier				key.lan.port = th.th_dport;
5510130613Smlaier				key.ext.port = th.th_sport;
5511130613Smlaier			}
5512126258Smlaier
5513126258Smlaier			STATE_LOOKUP();
5514126258Smlaier
5515126258Smlaier			if (direction == (*state)->direction) {
5516126258Smlaier				src = &(*state)->dst;
5517126258Smlaier				dst = &(*state)->src;
5518126258Smlaier			} else {
5519126258Smlaier				src = &(*state)->src;
5520126258Smlaier				dst = &(*state)->dst;
5521126258Smlaier			}
5522126258Smlaier
5523171929Sdhartmei			if (src->wscale && dst->wscale)
5524126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5525126258Smlaier			else
5526126258Smlaier				dws = 0;
5527126258Smlaier
5528126258Smlaier			/* Demodulate sequence number */
5529126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5530128129Smlaier			if (src->seqdiff) {
5531128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5532126258Smlaier				    htonl(seq), 0);
5533128129Smlaier				copyback = 1;
5534128129Smlaier			}
5535126258Smlaier
5536126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5537126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5538126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5539126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5540126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5541126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5542126258Smlaier					printf(" -> ");
5543126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5544126258Smlaier					printf(" state: ");
5545126258Smlaier					pf_print_state(*state);
5546126258Smlaier					printf(" seq=%u\n", seq);
5547126258Smlaier				}
5548145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5549126258Smlaier				return (PF_DROP);
5550126258Smlaier			}
5551126258Smlaier
5552126258Smlaier			if (STATE_TRANSLATE(*state)) {
5553126258Smlaier				if (direction == PF_IN) {
5554126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5555128129Smlaier					    daddr, &(*state)->lan.addr,
5556126258Smlaier					    (*state)->lan.port, NULL,
5557126258Smlaier					    pd2.ip_sum, icmpsum,
5558126258Smlaier					    pd->ip_sum, 0, pd2.af);
5559126258Smlaier				} else {
5560126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5561126258Smlaier					    saddr, &(*state)->gwy.addr,
5562126258Smlaier					    (*state)->gwy.port, NULL,
5563126258Smlaier					    pd2.ip_sum, icmpsum,
5564126258Smlaier					    pd->ip_sum, 0, pd2.af);
5565126258Smlaier				}
5566128129Smlaier				copyback = 1;
5567128129Smlaier			}
5568128129Smlaier
5569128129Smlaier			if (copyback) {
5570126258Smlaier				switch (pd2.af) {
5571126258Smlaier#ifdef INET
5572126258Smlaier				case AF_INET:
5573126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5574126261Smlaier					    (caddr_t)pd->hdr.icmp);
5575126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5576126261Smlaier					    (caddr_t)&h2);
5577126258Smlaier					break;
5578126258Smlaier#endif /* INET */
5579126258Smlaier#ifdef INET6
5580126258Smlaier				case AF_INET6:
5581126258Smlaier					m_copyback(m, off,
5582126258Smlaier					    sizeof(struct icmp6_hdr),
5583126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5584126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5585126261Smlaier					    (caddr_t)&h2_6);
5586126258Smlaier					break;
5587126258Smlaier#endif /* INET6 */
5588126258Smlaier				}
5589126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5590126258Smlaier			}
5591126258Smlaier
5592126258Smlaier			return (PF_PASS);
5593126258Smlaier			break;
5594126258Smlaier		}
5595126258Smlaier		case IPPROTO_UDP: {
5596126258Smlaier			struct udphdr		uh;
5597126258Smlaier
5598126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5599145836Smlaier			    NULL, reason, pd2.af)) {
5600126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5601126258Smlaier				    ("pf: ICMP error message too short "
5602126258Smlaier				    "(udp)\n"));
5603126258Smlaier				return (PF_DROP);
5604126258Smlaier			}
5605126258Smlaier
5606126258Smlaier			key.af = pd2.af;
5607126258Smlaier			key.proto = IPPROTO_UDP;
5608130613Smlaier			if (direction == PF_IN)	{
5609130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5610130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5611130613Smlaier				key.ext.port = uh.uh_dport;
5612130613Smlaier				key.gwy.port = uh.uh_sport;
5613130613Smlaier			} else {
5614130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5615130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5616130613Smlaier				key.lan.port = uh.uh_dport;
5617130613Smlaier				key.ext.port = uh.uh_sport;
5618130613Smlaier			}
5619126258Smlaier
5620126258Smlaier			STATE_LOOKUP();
5621126258Smlaier
5622126258Smlaier			if (STATE_TRANSLATE(*state)) {
5623126258Smlaier				if (direction == PF_IN) {
5624126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5625126258Smlaier					    daddr, &(*state)->lan.addr,
5626126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5627126258Smlaier					    pd2.ip_sum, icmpsum,
5628126258Smlaier					    pd->ip_sum, 1, pd2.af);
5629126258Smlaier				} else {
5630126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5631126258Smlaier					    saddr, &(*state)->gwy.addr,
5632126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5633126258Smlaier					    pd2.ip_sum, icmpsum,
5634126258Smlaier					    pd->ip_sum, 1, pd2.af);
5635126258Smlaier				}
5636126258Smlaier				switch (pd2.af) {
5637126258Smlaier#ifdef INET
5638126258Smlaier				case AF_INET:
5639126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5640126261Smlaier					    (caddr_t)pd->hdr.icmp);
5641126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5642126261Smlaier					    (caddr_t)&h2);
5643126258Smlaier					break;
5644126258Smlaier#endif /* INET */
5645126258Smlaier#ifdef INET6
5646126258Smlaier				case AF_INET6:
5647126258Smlaier					m_copyback(m, off,
5648126258Smlaier					    sizeof(struct icmp6_hdr),
5649126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5650126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5651126261Smlaier					    (caddr_t)&h2_6);
5652126258Smlaier					break;
5653126258Smlaier#endif /* INET6 */
5654126258Smlaier				}
5655126261Smlaier				m_copyback(m, off2, sizeof(uh),
5656126261Smlaier				    (caddr_t)&uh);
5657126258Smlaier			}
5658126258Smlaier
5659126258Smlaier			return (PF_PASS);
5660126258Smlaier			break;
5661126258Smlaier		}
5662126258Smlaier#ifdef INET
5663126258Smlaier		case IPPROTO_ICMP: {
5664126258Smlaier			struct icmp		iih;
5665126258Smlaier
5666126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5667145836Smlaier			    NULL, reason, pd2.af)) {
5668126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5669126258Smlaier				    ("pf: ICMP error message too short i"
5670126258Smlaier				    "(icmp)\n"));
5671126258Smlaier				return (PF_DROP);
5672126258Smlaier			}
5673126258Smlaier
5674126258Smlaier			key.af = pd2.af;
5675126258Smlaier			key.proto = IPPROTO_ICMP;
5676130613Smlaier			if (direction == PF_IN)	{
5677130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5678130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5679149884Smlaier				key.ext.port = 0;
5680130613Smlaier				key.gwy.port = iih.icmp_id;
5681130613Smlaier			} else {
5682130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5683130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5684130613Smlaier				key.lan.port = iih.icmp_id;
5685149884Smlaier				key.ext.port = 0;
5686130613Smlaier			}
5687126258Smlaier
5688126258Smlaier			STATE_LOOKUP();
5689126258Smlaier
5690126258Smlaier			if (STATE_TRANSLATE(*state)) {
5691126258Smlaier				if (direction == PF_IN) {
5692126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5693126258Smlaier					    daddr, &(*state)->lan.addr,
5694126258Smlaier					    (*state)->lan.port, NULL,
5695126258Smlaier					    pd2.ip_sum, icmpsum,
5696126258Smlaier					    pd->ip_sum, 0, AF_INET);
5697126258Smlaier				} else {
5698126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5699126258Smlaier					    saddr, &(*state)->gwy.addr,
5700126258Smlaier					    (*state)->gwy.port, NULL,
5701126258Smlaier					    pd2.ip_sum, icmpsum,
5702126258Smlaier					    pd->ip_sum, 0, AF_INET);
5703126258Smlaier				}
5704126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5705126261Smlaier				    (caddr_t)pd->hdr.icmp);
5706126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5707126261Smlaier				    (caddr_t)&h2);
5708126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5709126261Smlaier				    (caddr_t)&iih);
5710126258Smlaier			}
5711126258Smlaier
5712126258Smlaier			return (PF_PASS);
5713126258Smlaier			break;
5714126258Smlaier		}
5715126258Smlaier#endif /* INET */
5716126258Smlaier#ifdef INET6
5717126258Smlaier		case IPPROTO_ICMPV6: {
5718126258Smlaier			struct icmp6_hdr	iih;
5719126258Smlaier
5720126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5721145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5722126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5723126258Smlaier				    ("pf: ICMP error message too short "
5724126258Smlaier				    "(icmp6)\n"));
5725126258Smlaier				return (PF_DROP);
5726126258Smlaier			}
5727126258Smlaier
5728126258Smlaier			key.af = pd2.af;
5729126258Smlaier			key.proto = IPPROTO_ICMPV6;
5730130613Smlaier			if (direction == PF_IN)	{
5731130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5732130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5733149884Smlaier				key.ext.port = 0;
5734130613Smlaier				key.gwy.port = iih.icmp6_id;
5735130613Smlaier			} else {
5736130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5737130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5738130613Smlaier				key.lan.port = iih.icmp6_id;
5739149884Smlaier				key.ext.port = 0;
5740130613Smlaier			}
5741126258Smlaier
5742126258Smlaier			STATE_LOOKUP();
5743126258Smlaier
5744126258Smlaier			if (STATE_TRANSLATE(*state)) {
5745126258Smlaier				if (direction == PF_IN) {
5746126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5747126258Smlaier					    daddr, &(*state)->lan.addr,
5748126258Smlaier					    (*state)->lan.port, NULL,
5749126258Smlaier					    pd2.ip_sum, icmpsum,
5750126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5751126258Smlaier				} else {
5752126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5753126258Smlaier					    saddr, &(*state)->gwy.addr,
5754126258Smlaier					    (*state)->gwy.port, NULL,
5755126258Smlaier					    pd2.ip_sum, icmpsum,
5756126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5757126258Smlaier				}
5758126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5759126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5760126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5761126261Smlaier				    (caddr_t)&h2_6);
5762126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5763126261Smlaier				    (caddr_t)&iih);
5764126258Smlaier			}
5765126258Smlaier
5766126258Smlaier			return (PF_PASS);
5767126258Smlaier			break;
5768126258Smlaier		}
5769126258Smlaier#endif /* INET6 */
5770126258Smlaier		default: {
5771126258Smlaier			key.af = pd2.af;
5772126258Smlaier			key.proto = pd2.proto;
5773130613Smlaier			if (direction == PF_IN)	{
5774130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5775130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5776130613Smlaier				key.ext.port = 0;
5777130613Smlaier				key.gwy.port = 0;
5778130613Smlaier			} else {
5779130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5780130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5781130613Smlaier				key.lan.port = 0;
5782130613Smlaier				key.ext.port = 0;
5783130613Smlaier			}
5784126258Smlaier
5785126258Smlaier			STATE_LOOKUP();
5786126258Smlaier
5787126258Smlaier			if (STATE_TRANSLATE(*state)) {
5788126258Smlaier				if (direction == PF_IN) {
5789126258Smlaier					pf_change_icmp(pd2.src, NULL,
5790126258Smlaier					    daddr, &(*state)->lan.addr,
5791126258Smlaier					    0, NULL,
5792126258Smlaier					    pd2.ip_sum, icmpsum,
5793126258Smlaier					    pd->ip_sum, 0, pd2.af);
5794126258Smlaier				} else {
5795126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5796126258Smlaier					    saddr, &(*state)->gwy.addr,
5797126258Smlaier					    0, NULL,
5798126258Smlaier					    pd2.ip_sum, icmpsum,
5799126258Smlaier					    pd->ip_sum, 0, pd2.af);
5800126258Smlaier				}
5801126258Smlaier				switch (pd2.af) {
5802126258Smlaier#ifdef INET
5803126258Smlaier				case AF_INET:
5804126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5805126261Smlaier					    (caddr_t)pd->hdr.icmp);
5806126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5807126261Smlaier					    (caddr_t)&h2);
5808126258Smlaier					break;
5809126258Smlaier#endif /* INET */
5810126258Smlaier#ifdef INET6
5811126258Smlaier				case AF_INET6:
5812126258Smlaier					m_copyback(m, off,
5813126258Smlaier					    sizeof(struct icmp6_hdr),
5814126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5815126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5816126261Smlaier					    (caddr_t)&h2_6);
5817126258Smlaier					break;
5818126258Smlaier#endif /* INET6 */
5819126258Smlaier				}
5820126258Smlaier			}
5821126258Smlaier
5822126258Smlaier			return (PF_PASS);
5823126258Smlaier			break;
5824126258Smlaier		}
5825126258Smlaier		}
5826126258Smlaier	}
5827126258Smlaier}
5828126258Smlaier
5829126258Smlaierint
5830130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5831126258Smlaier    struct pf_pdesc *pd)
5832126258Smlaier{
5833126258Smlaier	struct pf_state_peer	*src, *dst;
5834171168Smlaier	struct pf_state_cmp	 key;
5835126258Smlaier
5836126258Smlaier	key.af = pd->af;
5837126258Smlaier	key.proto = pd->proto;
5838130613Smlaier	if (direction == PF_IN)	{
5839130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5840130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5841130613Smlaier		key.ext.port = 0;
5842130613Smlaier		key.gwy.port = 0;
5843130613Smlaier	} else {
5844130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5845130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5846130613Smlaier		key.lan.port = 0;
5847130613Smlaier		key.ext.port = 0;
5848130613Smlaier	}
5849126258Smlaier
5850126258Smlaier	STATE_LOOKUP();
5851126258Smlaier
5852126258Smlaier	if (direction == (*state)->direction) {
5853126258Smlaier		src = &(*state)->src;
5854126258Smlaier		dst = &(*state)->dst;
5855126258Smlaier	} else {
5856126258Smlaier		src = &(*state)->dst;
5857126258Smlaier		dst = &(*state)->src;
5858126258Smlaier	}
5859126258Smlaier
5860126258Smlaier	/* update states */
5861126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5862126258Smlaier		src->state = PFOTHERS_SINGLE;
5863126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5864126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5865126258Smlaier
5866126258Smlaier	/* update expire time */
5867126261Smlaier	(*state)->expire = time_second;
5868126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5869126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5870126258Smlaier	else
5871126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5872126258Smlaier
5873126258Smlaier	/* translate source/destination address, if necessary */
5874126258Smlaier	if (STATE_TRANSLATE(*state)) {
5875126258Smlaier		if (direction == PF_OUT)
5876126258Smlaier			switch (pd->af) {
5877126258Smlaier#ifdef INET
5878126258Smlaier			case AF_INET:
5879126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5880126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5881126258Smlaier				    0);
5882126258Smlaier				break;
5883126258Smlaier#endif /* INET */
5884126258Smlaier#ifdef INET6
5885126258Smlaier			case AF_INET6:
5886126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5887126258Smlaier				break;
5888126258Smlaier#endif /* INET6 */
5889126258Smlaier			}
5890126258Smlaier		else
5891126258Smlaier			switch (pd->af) {
5892126258Smlaier#ifdef INET
5893126258Smlaier			case AF_INET:
5894126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5895126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5896126258Smlaier				    0);
5897126258Smlaier				break;
5898126258Smlaier#endif /* INET */
5899126258Smlaier#ifdef INET6
5900126258Smlaier			case AF_INET6:
5901126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5902126258Smlaier				break;
5903126258Smlaier#endif /* INET6 */
5904126258Smlaier			}
5905126258Smlaier	}
5906126258Smlaier
5907126258Smlaier	return (PF_PASS);
5908126258Smlaier}
5909126258Smlaier
5910126258Smlaier/*
5911126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5912126258Smlaier * h must be at "ipoff" on the mbuf chain.
5913126258Smlaier */
5914126258Smlaiervoid *
5915126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5916126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5917126258Smlaier{
5918126258Smlaier	switch (af) {
5919126258Smlaier#ifdef INET
5920126258Smlaier	case AF_INET: {
5921126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5922126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5923126258Smlaier
5924126258Smlaier		if (fragoff) {
5925126258Smlaier			if (fragoff >= len)
5926126258Smlaier				ACTION_SET(actionp, PF_PASS);
5927126258Smlaier			else {
5928126258Smlaier				ACTION_SET(actionp, PF_DROP);
5929126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5930126258Smlaier			}
5931126258Smlaier			return (NULL);
5932126258Smlaier		}
5933130613Smlaier		if (m->m_pkthdr.len < off + len ||
5934130613Smlaier		    ntohs(h->ip_len) < off + len) {
5935126258Smlaier			ACTION_SET(actionp, PF_DROP);
5936126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5937126258Smlaier			return (NULL);
5938126258Smlaier		}
5939126258Smlaier		break;
5940126258Smlaier	}
5941126258Smlaier#endif /* INET */
5942126258Smlaier#ifdef INET6
5943126258Smlaier	case AF_INET6: {
5944126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5945126258Smlaier
5946126258Smlaier		if (m->m_pkthdr.len < off + len ||
5947126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5948126258Smlaier		    (unsigned)(off + len)) {
5949126258Smlaier			ACTION_SET(actionp, PF_DROP);
5950126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5951126258Smlaier			return (NULL);
5952126258Smlaier		}
5953126258Smlaier		break;
5954126258Smlaier	}
5955126258Smlaier#endif /* INET6 */
5956126258Smlaier	}
5957126258Smlaier	m_copydata(m, off, len, p);
5958126258Smlaier	return (p);
5959126258Smlaier}
5960126258Smlaier
5961126258Smlaierint
5962171168Smlaierpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
5963126258Smlaier{
5964126258Smlaier	struct sockaddr_in	*dst;
5965171168Smlaier	int			 ret = 1;
5966171168Smlaier	int			 check_mpath;
5967171168Smlaier#ifndef __FreeBSD__
5968171168Smlaier	extern int		 ipmultipath;
5969171168Smlaier#endif
5970145836Smlaier#ifdef INET6
5971171168Smlaier#ifndef __FreeBSD__
5972171168Smlaier	extern int		 ip6_multipath;
5973171168Smlaier#endif
5974145836Smlaier	struct sockaddr_in6	*dst6;
5975145836Smlaier	struct route_in6	 ro;
5976145836Smlaier#else
5977126258Smlaier	struct route		 ro;
5978145836Smlaier#endif
5979171168Smlaier	struct radix_node	*rn;
5980171168Smlaier	struct rtentry		*rt;
5981171168Smlaier	struct ifnet		*ifp;
5982126258Smlaier
5983171168Smlaier	check_mpath = 0;
5984126258Smlaier	bzero(&ro, sizeof(ro));
5985145836Smlaier	switch (af) {
5986145836Smlaier	case AF_INET:
5987145836Smlaier		dst = satosin(&ro.ro_dst);
5988145836Smlaier		dst->sin_family = AF_INET;
5989145836Smlaier		dst->sin_len = sizeof(*dst);
5990145836Smlaier		dst->sin_addr = addr->v4;
5991171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
5992171168Smlaier		if (ipmultipath)
5993171168Smlaier			check_mpath = 1;
5994171168Smlaier#endif
5995145836Smlaier		break;
5996145836Smlaier#ifdef INET6
5997145836Smlaier	case AF_INET6:
5998145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5999145836Smlaier		dst6->sin6_family = AF_INET6;
6000145836Smlaier		dst6->sin6_len = sizeof(*dst6);
6001145836Smlaier		dst6->sin6_addr = addr->v6;
6002171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
6003171168Smlaier		if (ip6_multipath)
6004171168Smlaier			check_mpath = 1;
6005171168Smlaier#endif
6006145836Smlaier		break;
6007145836Smlaier#endif /* INET6 */
6008145836Smlaier	default:
6009145836Smlaier		return (0);
6010145836Smlaier	}
6011145836Smlaier
6012171168Smlaier	/* Skip checks for ipsec interfaces */
6013171168Smlaier	if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
6014171168Smlaier		goto out;
6015171168Smlaier
6016127145Smlaier#ifdef __FreeBSD__
6017178888Sjulian/* XXX MRT not always INET */ /* stick with table 0 though */
6018178888Sjulian	if (af == AF_INET)
6019186119Sqingli		in_rtalloc_ign((struct route *)&ro, 0, 0);
6020178888Sjulian	else
6021186119Sqingli		rtalloc_ign((struct route *)&ro, 0);
6022126261Smlaier#else /* ! __FreeBSD__ */
6023145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
6024126261Smlaier#endif
6025126258Smlaier
6026126258Smlaier	if (ro.ro_rt != NULL) {
6027171168Smlaier		/* No interface given, this is a no-route check */
6028171168Smlaier		if (kif == NULL)
6029171168Smlaier			goto out;
6030171168Smlaier
6031171168Smlaier		if (kif->pfik_ifp == NULL) {
6032171168Smlaier			ret = 0;
6033171168Smlaier			goto out;
6034171168Smlaier		}
6035171168Smlaier
6036171168Smlaier		/* Perform uRPF check if passed input interface */
6037171168Smlaier		ret = 0;
6038171168Smlaier		rn = (struct radix_node *)ro.ro_rt;
6039171168Smlaier		do {
6040171168Smlaier			rt = (struct rtentry *)rn;
6041171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */
6042171168Smlaier			if (rt->rt_ifp->if_type == IFT_CARP)
6043171168Smlaier				ifp = rt->rt_ifp->if_carpdev;
6044171168Smlaier			else
6045171168Smlaier#endif
6046171168Smlaier				ifp = rt->rt_ifp;
6047171168Smlaier
6048171168Smlaier			if (kif->pfik_ifp == ifp)
6049171168Smlaier				ret = 1;
6050171168Smlaier#ifdef __FreeBSD__ /* MULTIPATH_ROUTING */
6051171168Smlaier			rn = NULL;
6052171168Smlaier#else
6053171168Smlaier			rn = rn_mpath_next(rn);
6054171168Smlaier#endif
6055171168Smlaier		} while (check_mpath == 1 && rn != NULL && ret == 0);
6056171168Smlaier	} else
6057171168Smlaier		ret = 0;
6058171168Smlaierout:
6059171168Smlaier	if (ro.ro_rt != NULL)
6060126258Smlaier		RTFREE(ro.ro_rt);
6061171168Smlaier	return (ret);
6062145836Smlaier}
6063145836Smlaier
6064145836Smlaierint
6065145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
6066145836Smlaier{
6067145836Smlaier	struct sockaddr_in	*dst;
6068145836Smlaier#ifdef INET6
6069145836Smlaier	struct sockaddr_in6	*dst6;
6070145836Smlaier	struct route_in6	 ro;
6071145836Smlaier#else
6072145836Smlaier	struct route		 ro;
6073145836Smlaier#endif
6074145836Smlaier	int			 ret = 0;
6075145836Smlaier
6076145836Smlaier	bzero(&ro, sizeof(ro));
6077145836Smlaier	switch (af) {
6078145836Smlaier	case AF_INET:
6079145836Smlaier		dst = satosin(&ro.ro_dst);
6080145836Smlaier		dst->sin_family = AF_INET;
6081145836Smlaier		dst->sin_len = sizeof(*dst);
6082145836Smlaier		dst->sin_addr = addr->v4;
6083145836Smlaier		break;
6084145836Smlaier#ifdef INET6
6085145836Smlaier	case AF_INET6:
6086145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
6087145836Smlaier		dst6->sin6_family = AF_INET6;
6088145836Smlaier		dst6->sin6_len = sizeof(*dst6);
6089145836Smlaier		dst6->sin6_addr = addr->v6;
6090145836Smlaier		break;
6091145836Smlaier#endif /* INET6 */
6092145836Smlaier	default:
6093145836Smlaier		return (0);
6094145836Smlaier	}
6095145836Smlaier
6096145836Smlaier#ifdef __FreeBSD__
6097145836Smlaier# ifdef RTF_PRCLONING
6098145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
6099145836Smlaier# else /* !RTF_PRCLONING */
6100178888Sjulian	if (af == AF_INET)
6101186119Sqingli		in_rtalloc_ign((struct route *)&ro, 0, 0);
6102178888Sjulian	else
6103186119Sqingli		rtalloc_ign((struct route *)&ro, 0);
6104145836Smlaier# endif
6105145836Smlaier#else /* ! __FreeBSD__ */
6106145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
6107145836Smlaier#endif
6108145836Smlaier
6109145836Smlaier	if (ro.ro_rt != NULL) {
6110145836Smlaier#ifdef __FreeBSD__
6111145836Smlaier		/* XXX_IMPORT: later */
6112145836Smlaier#else
6113145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
6114145836Smlaier			ret = 1;
6115145836Smlaier#endif
6116145836Smlaier		RTFREE(ro.ro_rt);
6117145836Smlaier	}
6118145836Smlaier
6119126258Smlaier	return (ret);
6120126258Smlaier}
6121126258Smlaier
6122126258Smlaier#ifdef INET
6123126261Smlaier
6124126258Smlaiervoid
6125126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6126171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6127126258Smlaier{
6128126258Smlaier	struct mbuf		*m0, *m1;
6129126258Smlaier	struct route		 iproute;
6130171168Smlaier	struct route		*ro = NULL;
6131126258Smlaier	struct sockaddr_in	*dst;
6132126258Smlaier	struct ip		*ip;
6133126258Smlaier	struct ifnet		*ifp = NULL;
6134126258Smlaier	struct pf_addr		 naddr;
6135130613Smlaier	struct pf_src_node	*sn = NULL;
6136126258Smlaier	int			 error = 0;
6137127145Smlaier#ifdef __FreeBSD__
6138126261Smlaier	int sw_csum;
6139126261Smlaier#endif
6140171168Smlaier#ifdef IPSEC
6141171168Smlaier	struct m_tag		*mtag;
6142171168Smlaier#endif /* IPSEC */
6143126258Smlaier
6144126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6145126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6146126258Smlaier		panic("pf_route: invalid parameters");
6147126258Smlaier
6148171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6149171168Smlaier		m0 = *m;
6150171168Smlaier		*m = NULL;
6151171168Smlaier		goto bad;
6152132303Smlaier	}
6153132303Smlaier
6154126258Smlaier	if (r->rt == PF_DUPTO) {
6155127145Smlaier#ifdef __FreeBSD__
6156132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6157126261Smlaier#else
6158132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6159126261Smlaier#endif
6160126258Smlaier			return;
6161126258Smlaier	} else {
6162126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6163126258Smlaier			return;
6164126258Smlaier		m0 = *m;
6165126258Smlaier	}
6166126258Smlaier
6167145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
6168145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6169145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6170145836Smlaier		goto bad;
6171145836Smlaier	}
6172145836Smlaier
6173126258Smlaier	ip = mtod(m0, struct ip *);
6174126258Smlaier
6175126258Smlaier	ro = &iproute;
6176126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6177126258Smlaier	dst = satosin(&ro->ro_dst);
6178126258Smlaier	dst->sin_family = AF_INET;
6179126258Smlaier	dst->sin_len = sizeof(*dst);
6180126258Smlaier	dst->sin_addr = ip->ip_dst;
6181126258Smlaier
6182126258Smlaier	if (r->rt == PF_FASTROUTE) {
6183178888Sjulian		in_rtalloc(ro, 0);
6184126258Smlaier		if (ro->ro_rt == 0) {
6185196039Srwatson			KMOD_IPSTAT_INC(ips_noroute);
6186126258Smlaier			goto bad;
6187126258Smlaier		}
6188126258Smlaier
6189126258Smlaier		ifp = ro->ro_rt->rt_ifp;
6190126258Smlaier		ro->ro_rt->rt_use++;
6191126258Smlaier
6192126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
6193126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
6194126258Smlaier	} else {
6195145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
6196145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6197145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
6198145836Smlaier			goto bad;
6199145836Smlaier		}
6200126258Smlaier		if (s == NULL) {
6201130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
6202130613Smlaier			    &naddr, NULL, &sn);
6203126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
6204126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
6205130613Smlaier			ifp = r->rpool.cur->kif ?
6206130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
6207126258Smlaier		} else {
6208126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
6209126258Smlaier				dst->sin_addr.s_addr =
6210126258Smlaier				    s->rt_addr.v4.s_addr;
6211130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6212126258Smlaier		}
6213126258Smlaier	}
6214126258Smlaier	if (ifp == NULL)
6215126258Smlaier		goto bad;
6216126258Smlaier
6217130639Smlaier	if (oifp != ifp) {
6218127145Smlaier#ifdef __FreeBSD__
6219126261Smlaier		PF_UNLOCK();
6220145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6221126261Smlaier			PF_LOCK();
6222126261Smlaier			goto bad;
6223126261Smlaier		} else if (m0 == NULL) {
6224126261Smlaier			PF_LOCK();
6225126261Smlaier			goto done;
6226126261Smlaier		}
6227126261Smlaier		PF_LOCK();
6228126261Smlaier#else
6229145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6230126258Smlaier			goto bad;
6231126258Smlaier		else if (m0 == NULL)
6232126258Smlaier			goto done;
6233126261Smlaier#endif
6234145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
6235145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6236145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6237145836Smlaier			goto bad;
6238145836Smlaier		}
6239126258Smlaier		ip = mtod(m0, struct ip *);
6240126258Smlaier	}
6241126258Smlaier
6242127145Smlaier#ifdef __FreeBSD__
6243126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
6244126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
6245126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
6246126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
6247126261Smlaier		/*
6248126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
6249126261Smlaier		 */
6250126261Smlaier		NTOHS(ip->ip_len);
6251126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
6252126261Smlaier		in_delayed_cksum(m0);
6253126261Smlaier		HTONS(ip->ip_len);
6254126261Smlaier		HTONS(ip->ip_off);
6255126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
6256126261Smlaier	}
6257126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
6258126261Smlaier
6259126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
6260126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
6261126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
6262126261Smlaier		/*
6263126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
6264126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
6265126261Smlaier		 */
6266126261Smlaier		ip->ip_sum = 0;
6267126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
6268126261Smlaier			/* From KAME */
6269126261Smlaier			if (ip->ip_v == IPVERSION &&
6270126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
6271126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
6272126261Smlaier			} else {
6273126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6274126261Smlaier			}
6275126261Smlaier		}
6276126261Smlaier		PF_UNLOCK();
6277191148Skmacy		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro);
6278126261Smlaier		PF_LOCK();
6279126261Smlaier		goto done;
6280126261Smlaier	}
6281126261Smlaier
6282126261Smlaier#else
6283126258Smlaier	/* Copied from ip_output. */
6284130613Smlaier#ifdef IPSEC
6285130613Smlaier	/*
6286130613Smlaier	 * If deferred crypto processing is needed, check that the
6287130613Smlaier	 * interface supports it.
6288130613Smlaier	 */
6289130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
6290130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
6291130613Smlaier		/* Notify IPsec to do its own crypto. */
6292130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
6293130613Smlaier		goto bad;
6294130613Smlaier	}
6295130613Smlaier#endif /* IPSEC */
6296130613Smlaier
6297130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
6298171168Smlaier	if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
6299130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
6300130613Smlaier		    ifp->if_bridge != NULL) {
6301130613Smlaier			in_delayed_cksum(m0);
6302171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
6303130613Smlaier		}
6304171168Smlaier	} else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
6305130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
6306130613Smlaier		    ifp->if_bridge != NULL) {
6307130613Smlaier			in_delayed_cksum(m0);
6308171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
6309130613Smlaier		}
6310130613Smlaier	}
6311130613Smlaier
6312126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
6313126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
6314126258Smlaier		    ifp->if_bridge == NULL) {
6315171168Smlaier			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
6316196039Srwatson			KMOD_IPSTAT_INC(ips_outhwcsum);
6317126258Smlaier		} else {
6318126258Smlaier			ip->ip_sum = 0;
6319126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6320126258Smlaier		}
6321126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
6322171168Smlaier		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
6323196039Srwatson			KMOD_TCPSTAT_INC(tcps_outhwcsum);
6324171168Smlaier		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
6325196039Srwatson			KMOD_UDPSTAT_INC(udps_outhwcsum);
6326126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
6327126258Smlaier		goto done;
6328126258Smlaier	}
6329126261Smlaier#endif
6330126258Smlaier	/*
6331126258Smlaier	 * Too large for interface; fragment if possible.
6332126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
6333126258Smlaier	 */
6334126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
6335196039Srwatson		KMOD_IPSTAT_INC(ips_cantfrag);
6336126258Smlaier		if (r->rt != PF_DUPTO) {
6337127145Smlaier#ifdef __FreeBSD__
6338126261Smlaier			/* icmp_error() expects host byte ordering */
6339126261Smlaier			NTOHS(ip->ip_len);
6340126261Smlaier			NTOHS(ip->ip_off);
6341126261Smlaier			PF_UNLOCK();
6342126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6343145886Smlaier			    ifp->if_mtu);
6344145874Smlaier			PF_LOCK();
6345145874Smlaier#else
6346145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6347171168Smlaier			    ifp->if_mtu);
6348126261Smlaier#endif
6349126258Smlaier			goto done;
6350126258Smlaier		} else
6351126258Smlaier			goto bad;
6352126258Smlaier	}
6353126258Smlaier
6354126258Smlaier	m1 = m0;
6355127145Smlaier#ifdef __FreeBSD__
6356126261Smlaier	/*
6357126261Smlaier	 * XXX: is cheaper + less error prone than own function
6358126261Smlaier	 */
6359126261Smlaier	NTOHS(ip->ip_len);
6360126261Smlaier	NTOHS(ip->ip_off);
6361126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
6362126261Smlaier#else
6363126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
6364126261Smlaier#endif
6365127531Smlaier	if (error) {
6366127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
6367127531Smlaier		m0 = NULL;
6368126261Smlaier#endif
6369126258Smlaier		goto bad;
6370127531Smlaier	}
6371126258Smlaier
6372126258Smlaier	for (m0 = m1; m0; m0 = m1) {
6373126258Smlaier		m1 = m0->m_nextpkt;
6374126258Smlaier		m0->m_nextpkt = 0;
6375127145Smlaier#ifdef __FreeBSD__
6376126261Smlaier		if (error == 0) {
6377126261Smlaier			PF_UNLOCK();
6378126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6379126261Smlaier			    NULL);
6380126261Smlaier			PF_LOCK();
6381126261Smlaier		} else
6382126261Smlaier#else
6383126258Smlaier		if (error == 0)
6384126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6385126258Smlaier			    NULL);
6386126258Smlaier		else
6387126261Smlaier#endif
6388126258Smlaier			m_freem(m0);
6389126258Smlaier	}
6390126258Smlaier
6391126258Smlaier	if (error == 0)
6392196039Srwatson		KMOD_IPSTAT_INC(ips_fragmented);
6393126258Smlaier
6394126258Smlaierdone:
6395126258Smlaier	if (r->rt != PF_DUPTO)
6396126258Smlaier		*m = NULL;
6397126258Smlaier	if (ro == &iproute && ro->ro_rt)
6398126258Smlaier		RTFREE(ro->ro_rt);
6399126258Smlaier	return;
6400126258Smlaier
6401126258Smlaierbad:
6402126258Smlaier	m_freem(m0);
6403126258Smlaier	goto done;
6404126258Smlaier}
6405126258Smlaier#endif /* INET */
6406126258Smlaier
6407126258Smlaier#ifdef INET6
6408126258Smlaiervoid
6409126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6410171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6411126258Smlaier{
6412126258Smlaier	struct mbuf		*m0;
6413126258Smlaier	struct route_in6	 ip6route;
6414126258Smlaier	struct route_in6	*ro;
6415126258Smlaier	struct sockaddr_in6	*dst;
6416126258Smlaier	struct ip6_hdr		*ip6;
6417126258Smlaier	struct ifnet		*ifp = NULL;
6418126258Smlaier	struct pf_addr		 naddr;
6419130613Smlaier	struct pf_src_node	*sn = NULL;
6420126258Smlaier	int			 error = 0;
6421126258Smlaier
6422126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6423126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6424126258Smlaier		panic("pf_route6: invalid parameters");
6425126258Smlaier
6426171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6427171168Smlaier		m0 = *m;
6428171168Smlaier		*m = NULL;
6429171168Smlaier		goto bad;
6430132303Smlaier	}
6431132303Smlaier
6432126258Smlaier	if (r->rt == PF_DUPTO) {
6433127145Smlaier#ifdef __FreeBSD__
6434132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6435126261Smlaier#else
6436132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6437126261Smlaier#endif
6438126258Smlaier			return;
6439126258Smlaier	} else {
6440126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6441126258Smlaier			return;
6442126258Smlaier		m0 = *m;
6443126258Smlaier	}
6444126258Smlaier
6445145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
6446145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6447145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6448145836Smlaier		goto bad;
6449145836Smlaier	}
6450126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
6451126258Smlaier
6452126258Smlaier	ro = &ip6route;
6453126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6454126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
6455126258Smlaier	dst->sin6_family = AF_INET6;
6456126258Smlaier	dst->sin6_len = sizeof(*dst);
6457126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
6458126258Smlaier
6459171168Smlaier	/* Cheat. XXX why only in the v6 case??? */
6460126258Smlaier	if (r->rt == PF_FASTROUTE) {
6461127145Smlaier#ifdef __FreeBSD__
6462132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
6463126261Smlaier		PF_UNLOCK();
6464126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6465126261Smlaier		PF_LOCK();
6466126261Smlaier#else
6467132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
6468132280Smlaier		if (mtag == NULL)
6469132280Smlaier			goto bad;
6470132280Smlaier		m_tag_prepend(m0, mtag);
6471171168Smlaier		pd->pf_mtag->flags |= PF_TAG_GENERATED;
6472126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
6473126261Smlaier#endif
6474126258Smlaier		return;
6475126258Smlaier	}
6476126258Smlaier
6477145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6478145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6479145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6480145836Smlaier		goto bad;
6481145836Smlaier	}
6482126258Smlaier	if (s == NULL) {
6483130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6484130613Smlaier		    &naddr, NULL, &sn);
6485126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6486126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6487126258Smlaier			    &naddr, AF_INET6);
6488130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6489126258Smlaier	} else {
6490126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6491126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6492126258Smlaier			    &s->rt_addr, AF_INET6);
6493130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6494126258Smlaier	}
6495126258Smlaier	if (ifp == NULL)
6496126258Smlaier		goto bad;
6497126258Smlaier
6498126258Smlaier	if (oifp != ifp) {
6499127145Smlaier#ifdef __FreeBSD__
6500132303Smlaier		PF_UNLOCK();
6501145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6502126261Smlaier			PF_LOCK();
6503132303Smlaier			goto bad;
6504132303Smlaier		} else if (m0 == NULL) {
6505132303Smlaier			PF_LOCK();
6506132303Smlaier			goto done;
6507132303Smlaier		}
6508132303Smlaier		PF_LOCK();
6509126261Smlaier#else
6510145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6511132303Smlaier			goto bad;
6512132303Smlaier		else if (m0 == NULL)
6513132303Smlaier			goto done;
6514126261Smlaier#endif
6515145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6516145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6517145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6518145836Smlaier			goto bad;
6519145836Smlaier		}
6520132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6521126258Smlaier	}
6522126258Smlaier
6523126258Smlaier	/*
6524126258Smlaier	 * If the packet is too large for the outgoing interface,
6525126258Smlaier	 * send back an icmp6 error.
6526126258Smlaier	 */
6527171168Smlaier	if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
6528126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6529126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6530127145Smlaier#ifdef __FreeBSD__
6531126261Smlaier		PF_UNLOCK();
6532126261Smlaier#endif
6533126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
6534127145Smlaier#ifdef __FreeBSD__
6535126261Smlaier		PF_LOCK();
6536126261Smlaier#endif
6537126258Smlaier	} else {
6538126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6539127145Smlaier#ifdef __FreeBSD__
6540126261Smlaier		if (r->rt != PF_DUPTO) {
6541126261Smlaier			PF_UNLOCK();
6542126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6543126261Smlaier			PF_LOCK();
6544126261Smlaier		 } else
6545126261Smlaier#else
6546126258Smlaier		if (r->rt != PF_DUPTO)
6547126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6548126258Smlaier		else
6549126261Smlaier#endif
6550126258Smlaier			goto bad;
6551126258Smlaier	}
6552126258Smlaier
6553126258Smlaierdone:
6554126258Smlaier	if (r->rt != PF_DUPTO)
6555126258Smlaier		*m = NULL;
6556126258Smlaier	return;
6557126258Smlaier
6558126258Smlaierbad:
6559126258Smlaier	m_freem(m0);
6560126258Smlaier	goto done;
6561126258Smlaier}
6562126258Smlaier#endif /* INET6 */
6563126258Smlaier
6564126258Smlaier
6565127145Smlaier#ifdef __FreeBSD__
6566126258Smlaier/*
6567132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6568137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6569132566Smlaier *   ti(4), txp(4), xl(4)
6570132566Smlaier *
6571132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6572132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6573132566Smlaier *   csum_data
6574132566Smlaier * CSUM_DATA_VALID :
6575132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6576132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6577132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6578132566Smlaier *
6579132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6580132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6581132566Smlaier * TCP/UDP layer.
6582132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6583126261Smlaier */
6584126261Smlaierint
6585126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6586126261Smlaier{
6587126261Smlaier	u_int16_t sum = 0;
6588126261Smlaier	int hw_assist = 0;
6589126261Smlaier	struct ip *ip;
6590126261Smlaier
6591126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6592126261Smlaier		return (1);
6593126261Smlaier	if (m->m_pkthdr.len < off + len)
6594126261Smlaier		return (1);
6595126261Smlaier
6596126261Smlaier	switch (p) {
6597126261Smlaier	case IPPROTO_TCP:
6598126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6599126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6600126261Smlaier				sum = m->m_pkthdr.csum_data;
6601126261Smlaier			} else {
6602126261Smlaier				ip = mtod(m, struct ip *);
6603126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6604135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6605135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6606126261Smlaier			}
6607126261Smlaier			sum ^= 0xffff;
6608126261Smlaier			++hw_assist;
6609126261Smlaier		}
6610126261Smlaier		break;
6611126261Smlaier	case IPPROTO_UDP:
6612126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6613126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6614126261Smlaier				sum = m->m_pkthdr.csum_data;
6615126261Smlaier			} else {
6616126261Smlaier				ip = mtod(m, struct ip *);
6617126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6618126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6619126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6620126261Smlaier			}
6621126261Smlaier			sum ^= 0xffff;
6622126261Smlaier			++hw_assist;
6623126261Smlaier                }
6624126261Smlaier		break;
6625126261Smlaier	case IPPROTO_ICMP:
6626126261Smlaier#ifdef INET6
6627126261Smlaier	case IPPROTO_ICMPV6:
6628126261Smlaier#endif /* INET6 */
6629126261Smlaier		break;
6630126261Smlaier	default:
6631126261Smlaier		return (1);
6632126261Smlaier	}
6633126261Smlaier
6634126261Smlaier	if (!hw_assist) {
6635126261Smlaier		switch (af) {
6636126261Smlaier		case AF_INET:
6637126261Smlaier			if (p == IPPROTO_ICMP) {
6638126261Smlaier				if (m->m_len < off)
6639126261Smlaier					return (1);
6640126261Smlaier				m->m_data += off;
6641126261Smlaier				m->m_len -= off;
6642126261Smlaier				sum = in_cksum(m, len);
6643126261Smlaier				m->m_data -= off;
6644126261Smlaier				m->m_len += off;
6645126261Smlaier			} else {
6646126261Smlaier				if (m->m_len < sizeof(struct ip))
6647126261Smlaier					return (1);
6648126261Smlaier				sum = in4_cksum(m, p, off, len);
6649126261Smlaier			}
6650126261Smlaier			break;
6651126261Smlaier#ifdef INET6
6652126261Smlaier		case AF_INET6:
6653126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6654126261Smlaier				return (1);
6655126261Smlaier			sum = in6_cksum(m, p, off, len);
6656126261Smlaier			break;
6657126261Smlaier#endif /* INET6 */
6658126261Smlaier		default:
6659126261Smlaier			return (1);
6660126261Smlaier		}
6661126261Smlaier	}
6662126261Smlaier	if (sum) {
6663126261Smlaier		switch (p) {
6664126261Smlaier		case IPPROTO_TCP:
6665183550Szec		    {
6666196039Srwatson			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
6667126261Smlaier			break;
6668183550Szec		    }
6669126261Smlaier		case IPPROTO_UDP:
6670183550Szec		    {
6671196039Srwatson			KMOD_UDPSTAT_INC(udps_badsum);
6672126261Smlaier			break;
6673183550Szec		    }
6674126261Smlaier		case IPPROTO_ICMP:
6675183550Szec		    {
6676196039Srwatson			KMOD_ICMPSTAT_INC(icps_checksum);
6677126261Smlaier			break;
6678183550Szec		    }
6679126261Smlaier#ifdef INET6
6680126261Smlaier		case IPPROTO_ICMPV6:
6681183550Szec		    {
6682196039Srwatson			KMOD_ICMP6STAT_INC(icp6s_checksum);
6683126261Smlaier			break;
6684183550Szec		    }
6685126261Smlaier#endif /* INET6 */
6686126261Smlaier		}
6687126261Smlaier		return (1);
6688132566Smlaier	} else {
6689132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6690132566Smlaier			m->m_pkthdr.csum_flags |=
6691132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6692132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6693132566Smlaier		}
6694126261Smlaier	}
6695126261Smlaier	return (0);
6696126261Smlaier}
6697171168Smlaier#else /* !__FreeBSD__ */
6698126261Smlaier/*
6699126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6700126258Smlaier *   off is the offset where the protocol header starts
6701126258Smlaier *   len is the total length of protocol header plus payload
6702126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6703126258Smlaier */
6704126258Smlaierint
6705130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6706130613Smlaier    sa_family_t af)
6707126258Smlaier{
6708126258Smlaier	u_int16_t flag_ok, flag_bad;
6709126258Smlaier	u_int16_t sum;
6710126258Smlaier
6711126258Smlaier	switch (p) {
6712126258Smlaier	case IPPROTO_TCP:
6713126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6714126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6715126258Smlaier		break;
6716126258Smlaier	case IPPROTO_UDP:
6717126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6718126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6719126258Smlaier		break;
6720126258Smlaier	case IPPROTO_ICMP:
6721126258Smlaier#ifdef INET6
6722126258Smlaier	case IPPROTO_ICMPV6:
6723126258Smlaier#endif /* INET6 */
6724126258Smlaier		flag_ok = flag_bad = 0;
6725126258Smlaier		break;
6726126258Smlaier	default:
6727126258Smlaier		return (1);
6728126258Smlaier	}
6729171168Smlaier	if (m->m_pkthdr.csum_flags & flag_ok)
6730126258Smlaier		return (0);
6731171168Smlaier	if (m->m_pkthdr.csum_flags & flag_bad)
6732126258Smlaier		return (1);
6733126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6734126258Smlaier		return (1);
6735126258Smlaier	if (m->m_pkthdr.len < off + len)
6736126258Smlaier		return (1);
6737145836Smlaier	switch (af) {
6738145836Smlaier#ifdef INET
6739126258Smlaier	case AF_INET:
6740126258Smlaier		if (p == IPPROTO_ICMP) {
6741126258Smlaier			if (m->m_len < off)
6742126258Smlaier				return (1);
6743126258Smlaier			m->m_data += off;
6744126258Smlaier			m->m_len -= off;
6745126258Smlaier			sum = in_cksum(m, len);
6746126258Smlaier			m->m_data -= off;
6747126258Smlaier			m->m_len += off;
6748126258Smlaier		} else {
6749126258Smlaier			if (m->m_len < sizeof(struct ip))
6750126258Smlaier				return (1);
6751126258Smlaier			sum = in4_cksum(m, p, off, len);
6752126258Smlaier		}
6753126258Smlaier		break;
6754145836Smlaier#endif /* INET */
6755126258Smlaier#ifdef INET6
6756126258Smlaier	case AF_INET6:
6757126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6758126258Smlaier			return (1);
6759126258Smlaier		sum = in6_cksum(m, p, off, len);
6760126258Smlaier		break;
6761126258Smlaier#endif /* INET6 */
6762126258Smlaier	default:
6763126258Smlaier		return (1);
6764126258Smlaier	}
6765126258Smlaier	if (sum) {
6766171168Smlaier		m->m_pkthdr.csum_flags |= flag_bad;
6767126258Smlaier		switch (p) {
6768126258Smlaier		case IPPROTO_TCP:
6769196039Srwatson			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
6770126258Smlaier			break;
6771126258Smlaier		case IPPROTO_UDP:
6772196039Srwatson			KMOD_UDPSTAT_INC(udps_badsum);
6773126258Smlaier			break;
6774126258Smlaier		case IPPROTO_ICMP:
6775196039Srwatson			KMOD_ICMPSTAT_INC(icps_checksum);
6776126258Smlaier			break;
6777126258Smlaier#ifdef INET6
6778126258Smlaier		case IPPROTO_ICMPV6:
6779196039Srwatson			KMOD_ICMP6STAT_INC(icp6s_checksum);
6780126258Smlaier			break;
6781126258Smlaier#endif /* INET6 */
6782126258Smlaier		}
6783126258Smlaier		return (1);
6784126258Smlaier	}
6785171168Smlaier	m->m_pkthdr.csum_flags |= flag_ok;
6786126258Smlaier	return (0);
6787126258Smlaier}
6788171168Smlaier#endif /* __FreeBSD__ */
6789126258Smlaier
6790126258Smlaier#ifdef INET
6791126258Smlaierint
6792135920Smlaier#ifdef __FreeBSD__
6793145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6794145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6795135920Smlaier#else
6796145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6797145836Smlaier    struct ether_header *eh)
6798135920Smlaier#endif
6799126258Smlaier{
6800130613Smlaier	struct pfi_kif		*kif;
6801130613Smlaier	u_short			 action, reason = 0, log = 0;
6802130613Smlaier	struct mbuf		*m = *m0;
6803130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6804130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6805130613Smlaier	struct pf_state		*s = NULL;
6806130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6807130613Smlaier	struct pf_pdesc		 pd;
6808130613Smlaier	int			 off, dirndx, pqid = 0;
6809126258Smlaier
6810127145Smlaier#ifdef __FreeBSD__
6811126261Smlaier	PF_LOCK();
6812126261Smlaier#endif
6813171168Smlaier	if (!pf_status.running)
6814127145Smlaier#ifdef __FreeBSD__
6815171168Smlaier	{
6816126261Smlaier		PF_UNLOCK();
6817126261Smlaier#endif
6818171168Smlaier		return (PF_PASS);
6819171168Smlaier#ifdef __FreeBSD__
6820126261Smlaier	}
6821171168Smlaier#endif
6822126258Smlaier
6823171168Smlaier	memset(&pd, 0, sizeof(pd));
6824171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
6825145836Smlaier#ifdef __FreeBSD__
6826171168Smlaier		PF_UNLOCK();
6827171168Smlaier#endif
6828171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6829171168Smlaier		    ("pf_test: pf_get_mtag returned NULL\n"));
6830171168Smlaier		return (PF_DROP);
6831171168Smlaier	}
6832171168Smlaier#ifdef __FreeBSD__
6833171168Smlaier	if (m->m_flags & M_SKIP_FIREWALL) {
6834171168Smlaier		PF_UNLOCK();
6835171168Smlaier		return (PF_PASS);
6836171168Smlaier	}
6837171168Smlaier#else
6838171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
6839171168Smlaier		return (PF_PASS);
6840171168Smlaier#endif
6841171168Smlaier
6842171168Smlaier#ifdef __FreeBSD__
6843145836Smlaier	/* XXX_IMPORT: later */
6844145836Smlaier#else
6845145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6846145836Smlaier		ifp = ifp->if_carpdev;
6847145836Smlaier#endif
6848145836Smlaier
6849171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
6850130613Smlaier	if (kif == NULL) {
6851130613Smlaier#ifdef __FreeBSD__
6852130613Smlaier		PF_UNLOCK();
6853130613Smlaier#endif
6854145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6855145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6856130613Smlaier		return (PF_DROP);
6857130613Smlaier	}
6858145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6859145836Smlaier#ifdef __FreeBSD__
6860145836Smlaier		PF_UNLOCK();
6861145836Smlaier#endif
6862145836Smlaier		return (PF_PASS);
6863145836Smlaier	}
6864130613Smlaier
6865130613Smlaier#ifdef __FreeBSD__
6866126261Smlaier	M_ASSERTPKTHDR(m);
6867126261Smlaier#else
6868126258Smlaier#ifdef DIAGNOSTIC
6869126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6870126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6871145836Smlaier#endif /* DIAGNOSTIC */
6872145836Smlaier#endif /* __FreeBSD__ */
6873126258Smlaier
6874126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6875126258Smlaier		action = PF_DROP;
6876126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6877126258Smlaier		log = 1;
6878126258Smlaier		goto done;
6879126258Smlaier	}
6880126258Smlaier
6881126258Smlaier	/* We do IP header normalization and packet reassembly here */
6882145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6883126258Smlaier		action = PF_DROP;
6884126258Smlaier		goto done;
6885126258Smlaier	}
6886126258Smlaier	m = *m0;
6887126258Smlaier	h = mtod(m, struct ip *);
6888126258Smlaier
6889126258Smlaier	off = h->ip_hl << 2;
6890126258Smlaier	if (off < (int)sizeof(*h)) {
6891126258Smlaier		action = PF_DROP;
6892126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6893126258Smlaier		log = 1;
6894126258Smlaier		goto done;
6895126258Smlaier	}
6896126258Smlaier
6897126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6898126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6899130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6900126258Smlaier	pd.ip_sum = &h->ip_sum;
6901126258Smlaier	pd.proto = h->ip_p;
6902126258Smlaier	pd.af = AF_INET;
6903126258Smlaier	pd.tos = h->ip_tos;
6904126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6905145836Smlaier	pd.eh = eh;
6906126258Smlaier
6907126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6908126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6909130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6910126258Smlaier		    &pd, &a, &ruleset);
6911126258Smlaier		goto done;
6912126258Smlaier	}
6913126258Smlaier
6914126258Smlaier	switch (h->ip_p) {
6915126258Smlaier
6916126258Smlaier	case IPPROTO_TCP: {
6917126258Smlaier		struct tcphdr	th;
6918126258Smlaier
6919126258Smlaier		pd.hdr.tcp = &th;
6920126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6921126258Smlaier		    &action, &reason, AF_INET)) {
6922126258Smlaier			log = action != PF_PASS;
6923126258Smlaier			goto done;
6924126258Smlaier		}
6925126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6926126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6927171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6928126258Smlaier			action = PF_DROP;
6929126258Smlaier			goto done;
6930126258Smlaier		}
6931126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6932126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6933126258Smlaier			pqid = 1;
6934130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6935126258Smlaier		if (action == PF_DROP)
6936130613Smlaier			goto done;
6937130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6938126258Smlaier		    &reason);
6939126258Smlaier		if (action == PF_PASS) {
6940130613Smlaier#if NPFSYNC
6941130613Smlaier			pfsync_update_state(s);
6942145836Smlaier#endif /* NPFSYNC */
6943126258Smlaier			r = s->rule.ptr;
6944130613Smlaier			a = s->anchor.ptr;
6945126258Smlaier			log = s->log;
6946126258Smlaier		} else if (s == NULL)
6947135920Smlaier#ifdef __FreeBSD__
6948130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6949145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6950135920Smlaier#else
6951135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6952145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6953135920Smlaier#endif
6954126258Smlaier		break;
6955126258Smlaier	}
6956126258Smlaier
6957126258Smlaier	case IPPROTO_UDP: {
6958126258Smlaier		struct udphdr	uh;
6959126258Smlaier
6960126258Smlaier		pd.hdr.udp = &uh;
6961126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6962126258Smlaier		    &action, &reason, AF_INET)) {
6963126258Smlaier			log = action != PF_PASS;
6964126258Smlaier			goto done;
6965126258Smlaier		}
6966126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6967126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6968126258Smlaier			action = PF_DROP;
6969171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6970126258Smlaier			goto done;
6971126258Smlaier		}
6972130613Smlaier		if (uh.uh_dport == 0 ||
6973130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6974130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6975130613Smlaier			action = PF_DROP;
6976171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
6977130613Smlaier			goto done;
6978130613Smlaier		}
6979130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &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)
6988135920Smlaier#ifdef __FreeBSD__
6989130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6990145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6991135920Smlaier#else
6992135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6993145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6994135920Smlaier#endif
6995126258Smlaier		break;
6996126258Smlaier	}
6997126258Smlaier
6998126258Smlaier	case IPPROTO_ICMP: {
6999126258Smlaier		struct icmp	ih;
7000126258Smlaier
7001126258Smlaier		pd.hdr.icmp = &ih;
7002126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
7003126258Smlaier		    &action, &reason, AF_INET)) {
7004126258Smlaier			log = action != PF_PASS;
7005126258Smlaier			goto done;
7006126258Smlaier		}
7007126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
7008126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
7009126258Smlaier			action = PF_DROP;
7010171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7011126258Smlaier			goto done;
7012126258Smlaier		}
7013145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
7014145836Smlaier		    &reason);
7015126258Smlaier		if (action == PF_PASS) {
7016130613Smlaier#if NPFSYNC
7017130613Smlaier			pfsync_update_state(s);
7018145836Smlaier#endif /* NPFSYNC */
7019126258Smlaier			r = s->rule.ptr;
7020126258Smlaier			a = s->anchor.ptr;
7021126258Smlaier			log = s->log;
7022126258Smlaier		} else if (s == NULL)
7023145836Smlaier#ifdef __FreeBSD__
7024130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7025145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
7026145836Smlaier#else
7027145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7028145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
7029145836Smlaier#endif
7030126258Smlaier		break;
7031126258Smlaier	}
7032126258Smlaier
7033126258Smlaier	default:
7034130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
7035126258Smlaier		if (action == PF_PASS) {
7036130613Smlaier#if NPFSYNC
7037130613Smlaier			pfsync_update_state(s);
7038145836Smlaier#endif /* NPFSYNC */
7039126258Smlaier			r = s->rule.ptr;
7040126258Smlaier			a = s->anchor.ptr;
7041126258Smlaier			log = s->log;
7042126258Smlaier		} else if (s == NULL)
7043145836Smlaier#ifdef __FreeBSD__
7044130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7045145836Smlaier			    &pd, &a, &ruleset, NULL);
7046145836Smlaier#else
7047145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7048145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
7049145836Smlaier#endif
7050126258Smlaier		break;
7051126258Smlaier	}
7052126258Smlaier
7053126258Smlaierdone:
7054126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
7055126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
7056126258Smlaier		action = PF_DROP;
7057145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
7058126258Smlaier		log = 1;
7059126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
7060126258Smlaier		    ("pf: dropping packet with ip options\n"));
7061126258Smlaier	}
7062126258Smlaier
7063171168Smlaier	if ((s && s->tag) || r->rtableid)
7064171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7065145836Smlaier
7066126258Smlaier#ifdef ALTQ
7067126258Smlaier	if (action == PF_PASS && r->qid) {
7068171168Smlaier		if (pqid || (pd.tos & IPTOS_LOWDELAY))
7069171168Smlaier			pd.pf_mtag->qid = r->pqid;
7070171168Smlaier		else
7071171168Smlaier			pd.pf_mtag->qid = r->qid;
7072171168Smlaier		/* add hints for ecn */
7073171168Smlaier		pd.pf_mtag->af = AF_INET;
7074171168Smlaier		pd.pf_mtag->hdr = h;
7075126258Smlaier	}
7076145836Smlaier#endif /* ALTQ */
7077126258Smlaier
7078130613Smlaier	/*
7079130613Smlaier	 * connections redirected to loopback should not match sockets
7080130613Smlaier	 * bound specifically to loopback due to security implications,
7081130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
7082130613Smlaier	 */
7083130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7084130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7085130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7086130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7087171168Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
7088171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7089171168Smlaier
7090171168Smlaier	if (log) {
7091171168Smlaier		struct pf_rule *lr;
7092171168Smlaier
7093171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7094171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7095171168Smlaier			lr = s->nat_rule.ptr;
7096171168Smlaier		else
7097171168Smlaier			lr = r;
7098171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
7099171168Smlaier		    &pd);
7100130613Smlaier	}
7101130613Smlaier
7102130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7103130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
7104130613Smlaier
7105130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7106171168Smlaier		dirndx = (dir == PF_OUT);
7107171168Smlaier		r->packets[dirndx]++;
7108171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7109130613Smlaier		if (a != NULL) {
7110171168Smlaier			a->packets[dirndx]++;
7111171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7112130613Smlaier		}
7113130613Smlaier		if (s != NULL) {
7114130613Smlaier			if (s->nat_rule.ptr != NULL) {
7115171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7116171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7117130613Smlaier			}
7118130613Smlaier			if (s->src_node != NULL) {
7119171168Smlaier				s->src_node->packets[dirndx]++;
7120171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7121130613Smlaier			}
7122130613Smlaier			if (s->nat_src_node != NULL) {
7123171168Smlaier				s->nat_src_node->packets[dirndx]++;
7124171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7125130613Smlaier			}
7126171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7127171168Smlaier			s->packets[dirndx]++;
7128171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7129130613Smlaier		}
7130130613Smlaier		tr = r;
7131130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7132130613Smlaier		if (nr != NULL) {
7133130613Smlaier			struct pf_addr *x;
7134130613Smlaier			/*
7135130613Smlaier			 * XXX: we need to make sure that the addresses
7136130613Smlaier			 * passed to pfr_update_stats() are the same than
7137130613Smlaier			 * the addresses used during matching (pfr_match)
7138130613Smlaier			 */
7139130613Smlaier			if (r == &pf_default_rule) {
7140130613Smlaier				tr = nr;
7141130613Smlaier				x = (s == NULL || s->direction == dir) ?
7142130613Smlaier				    &pd.baddr : &pd.naddr;
7143130613Smlaier			} else
7144130613Smlaier				x = (s == NULL || s->direction == dir) ?
7145130613Smlaier				    &pd.naddr : &pd.baddr;
7146130613Smlaier			if (x == &pd.baddr || s == NULL) {
7147130613Smlaier				/* we need to change the address */
7148130613Smlaier				if (dir == PF_OUT)
7149130613Smlaier					pd.src = x;
7150130613Smlaier				else
7151130613Smlaier					pd.dst = x;
7152130613Smlaier			}
7153130613Smlaier		}
7154130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7155130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7156130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7157130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7158145836Smlaier			    tr->src.neg);
7159130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7160130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7161130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7162130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7163145836Smlaier			    tr->dst.neg);
7164130613Smlaier	}
7165130613Smlaier
7166130613Smlaier
7167126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7168126258Smlaier		m_freem(*m0);
7169126258Smlaier		*m0 = NULL;
7170126258Smlaier		action = PF_PASS;
7171126258Smlaier	} else if (r->rt)
7172126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
7173171168Smlaier		pf_route(m0, r, dir, ifp, s, &pd);
7174126258Smlaier
7175127145Smlaier#ifdef __FreeBSD__
7176126261Smlaier	PF_UNLOCK();
7177126261Smlaier#endif
7178126261Smlaier
7179126258Smlaier	return (action);
7180126258Smlaier}
7181126258Smlaier#endif /* INET */
7182126258Smlaier
7183126258Smlaier#ifdef INET6
7184126258Smlaierint
7185135920Smlaier#ifdef __FreeBSD__
7186145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7187145836Smlaier    struct ether_header *eh, struct inpcb *inp)
7188135920Smlaier#else
7189145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7190145836Smlaier    struct ether_header *eh)
7191135920Smlaier#endif
7192126258Smlaier{
7193130613Smlaier	struct pfi_kif		*kif;
7194130613Smlaier	u_short			 action, reason = 0, log = 0;
7195171168Smlaier	struct mbuf		*m = *m0, *n = NULL;
7196171168Smlaier	struct ip6_hdr		*h;
7197130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
7198130613Smlaier	struct pf_state		*s = NULL;
7199130613Smlaier	struct pf_ruleset	*ruleset = NULL;
7200130613Smlaier	struct pf_pdesc		 pd;
7201169843Sdhartmei	int			 off, terminal = 0, dirndx, rh_cnt = 0;
7202126258Smlaier
7203127145Smlaier#ifdef __FreeBSD__
7204126261Smlaier	PF_LOCK();
7205126261Smlaier#endif
7206126261Smlaier
7207171168Smlaier	if (!pf_status.running)
7208127145Smlaier#ifdef __FreeBSD__
7209171168Smlaier	{
7210126261Smlaier		PF_UNLOCK();
7211126261Smlaier#endif
7212126258Smlaier		return (PF_PASS);
7213171168Smlaier#ifdef __FreeBSD__
7214126261Smlaier	}
7215171168Smlaier#endif
7216126258Smlaier
7217171168Smlaier	memset(&pd, 0, sizeof(pd));
7218171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
7219145836Smlaier#ifdef __FreeBSD__
7220171168Smlaier		PF_UNLOCK();
7221171168Smlaier#endif
7222171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7223171168Smlaier		    ("pf_test6: pf_get_mtag returned NULL\n"));
7224171168Smlaier		return (PF_DROP);
7225171168Smlaier	}
7226171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
7227171168Smlaier		return (PF_PASS);
7228171168Smlaier
7229171168Smlaier#ifdef __FreeBSD__
7230145836Smlaier	/* XXX_IMPORT: later */
7231145836Smlaier#else
7232145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
7233145836Smlaier		ifp = ifp->if_carpdev;
7234145836Smlaier#endif
7235145836Smlaier
7236171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
7237130613Smlaier	if (kif == NULL) {
7238130613Smlaier#ifdef __FreeBSD__
7239130613Smlaier		PF_UNLOCK();
7240130613Smlaier#endif
7241145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7242145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
7243130613Smlaier		return (PF_DROP);
7244130613Smlaier	}
7245145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
7246145836Smlaier#ifdef __FreeBSD__
7247145836Smlaier		PF_UNLOCK();
7248145836Smlaier#endif
7249145836Smlaier		return (PF_PASS);
7250145836Smlaier	}
7251130613Smlaier
7252130613Smlaier#ifdef __FreeBSD__
7253126261Smlaier	M_ASSERTPKTHDR(m);
7254126261Smlaier#else
7255126258Smlaier#ifdef DIAGNOSTIC
7256126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
7257145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
7258145836Smlaier#endif /* DIAGNOSTIC */
7259126258Smlaier#endif
7260126258Smlaier
7261171168Smlaier#ifdef __FreeBSD__
7262171168Smlaier	h = NULL;	/* make the compiler happy */
7263171168Smlaier#endif
7264171168Smlaier
7265126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
7266126258Smlaier		action = PF_DROP;
7267126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
7268126258Smlaier		log = 1;
7269126258Smlaier		goto done;
7270126258Smlaier	}
7271126258Smlaier
7272126258Smlaier	/* We do IP header normalization and packet reassembly here */
7273145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
7274126258Smlaier		action = PF_DROP;
7275126258Smlaier		goto done;
7276126258Smlaier	}
7277126258Smlaier	m = *m0;
7278126258Smlaier	h = mtod(m, struct ip6_hdr *);
7279126258Smlaier
7280169843Sdhartmei#if 1
7281169843Sdhartmei	/*
7282169843Sdhartmei	 * we do not support jumbogram yet.  if we keep going, zero ip6_plen
7283169843Sdhartmei	 * will do something bad, so drop the packet for now.
7284169843Sdhartmei	 */
7285169843Sdhartmei	if (htons(h->ip6_plen) == 0) {
7286169843Sdhartmei		action = PF_DROP;
7287169843Sdhartmei		REASON_SET(&reason, PFRES_NORM);	/*XXX*/
7288169843Sdhartmei		goto done;
7289169843Sdhartmei	}
7290169843Sdhartmei#endif
7291169843Sdhartmei
7292126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
7293126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
7294130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
7295126258Smlaier	pd.ip_sum = NULL;
7296126258Smlaier	pd.af = AF_INET6;
7297126258Smlaier	pd.tos = 0;
7298126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
7299145836Smlaier	pd.eh = eh;
7300126258Smlaier
7301126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
7302126258Smlaier	pd.proto = h->ip6_nxt;
7303126258Smlaier	do {
7304126258Smlaier		switch (pd.proto) {
7305126258Smlaier		case IPPROTO_FRAGMENT:
7306130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
7307126258Smlaier			    &pd, &a, &ruleset);
7308126258Smlaier			if (action == PF_DROP)
7309126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
7310126258Smlaier			goto done;
7311169843Sdhartmei		case IPPROTO_ROUTING: {
7312169843Sdhartmei			struct ip6_rthdr rthdr;
7313169843Sdhartmei
7314169843Sdhartmei			if (rh_cnt++) {
7315169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7316169843Sdhartmei				    ("pf: IPv6 more than one rthdr\n"));
7317169843Sdhartmei				action = PF_DROP;
7318169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7319169843Sdhartmei				log = 1;
7320169843Sdhartmei				goto done;
7321169843Sdhartmei			}
7322169843Sdhartmei			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
7323169843Sdhartmei			    &reason, pd.af)) {
7324169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7325169843Sdhartmei				    ("pf: IPv6 short rthdr\n"));
7326169843Sdhartmei				action = PF_DROP;
7327169843Sdhartmei				REASON_SET(&reason, PFRES_SHORT);
7328169843Sdhartmei				log = 1;
7329169843Sdhartmei				goto done;
7330169843Sdhartmei			}
7331169843Sdhartmei			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
7332169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7333169843Sdhartmei				    ("pf: IPv6 rthdr0\n"));
7334169843Sdhartmei				action = PF_DROP;
7335169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7336169843Sdhartmei				log = 1;
7337169843Sdhartmei				goto done;
7338169843Sdhartmei			}
7339169843Sdhartmei			/* fallthrough */
7340169843Sdhartmei		}
7341126258Smlaier		case IPPROTO_AH:
7342126258Smlaier		case IPPROTO_HOPOPTS:
7343126258Smlaier		case IPPROTO_DSTOPTS: {
7344126258Smlaier			/* get next header and header length */
7345126258Smlaier			struct ip6_ext	opt6;
7346126258Smlaier
7347126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
7348145836Smlaier			    NULL, &reason, pd.af)) {
7349126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
7350126258Smlaier				    ("pf: IPv6 short opt\n"));
7351126258Smlaier				action = PF_DROP;
7352126258Smlaier				log = 1;
7353126258Smlaier				goto done;
7354126258Smlaier			}
7355126258Smlaier			if (pd.proto == IPPROTO_AH)
7356126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
7357126258Smlaier			else
7358126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
7359126258Smlaier			pd.proto = opt6.ip6e_nxt;
7360126258Smlaier			/* goto the next header */
7361126258Smlaier			break;
7362126258Smlaier		}
7363126258Smlaier		default:
7364126258Smlaier			terminal++;
7365126258Smlaier			break;
7366126258Smlaier		}
7367126258Smlaier	} while (!terminal);
7368126258Smlaier
7369171168Smlaier	/* if there's no routing header, use unmodified mbuf for checksumming */
7370171168Smlaier	if (!n)
7371171168Smlaier		n = m;
7372171168Smlaier
7373126258Smlaier	switch (pd.proto) {
7374126258Smlaier
7375126258Smlaier	case IPPROTO_TCP: {
7376126258Smlaier		struct tcphdr	th;
7377126258Smlaier
7378126258Smlaier		pd.hdr.tcp = &th;
7379126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
7380126258Smlaier		    &action, &reason, AF_INET6)) {
7381126258Smlaier			log = action != PF_PASS;
7382126258Smlaier			goto done;
7383126258Smlaier		}
7384171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7385138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7386138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
7387126258Smlaier			action = PF_DROP;
7388145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7389126258Smlaier			goto done;
7390126258Smlaier		}
7391126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
7392130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
7393126258Smlaier		if (action == PF_DROP)
7394130613Smlaier			goto done;
7395130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
7396126258Smlaier		    &reason);
7397126258Smlaier		if (action == PF_PASS) {
7398130613Smlaier#if NPFSYNC
7399130613Smlaier			pfsync_update_state(s);
7400145836Smlaier#endif /* NPFSYNC */
7401126258Smlaier			r = s->rule.ptr;
7402130613Smlaier			a = s->anchor.ptr;
7403126258Smlaier			log = s->log;
7404126258Smlaier		} else if (s == NULL)
7405135920Smlaier#ifdef __FreeBSD__
7406130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7407145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7408135920Smlaier#else
7409135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7410145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7411135920Smlaier#endif
7412126258Smlaier		break;
7413126258Smlaier	}
7414126258Smlaier
7415126258Smlaier	case IPPROTO_UDP: {
7416126258Smlaier		struct udphdr	uh;
7417126258Smlaier
7418126258Smlaier		pd.hdr.udp = &uh;
7419126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
7420126258Smlaier		    &action, &reason, AF_INET6)) {
7421126258Smlaier			log = action != PF_PASS;
7422126258Smlaier			goto done;
7423126258Smlaier		}
7424171168Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
7425138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7426138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
7427126258Smlaier			action = PF_DROP;
7428145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7429126258Smlaier			goto done;
7430126258Smlaier		}
7431130613Smlaier		if (uh.uh_dport == 0 ||
7432130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
7433130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
7434130613Smlaier			action = PF_DROP;
7435171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
7436130613Smlaier			goto done;
7437130613Smlaier		}
7438130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
7439126258Smlaier		if (action == PF_PASS) {
7440130613Smlaier#if NPFSYNC
7441130613Smlaier			pfsync_update_state(s);
7442145836Smlaier#endif /* NPFSYNC */
7443126258Smlaier			r = s->rule.ptr;
7444130613Smlaier			a = s->anchor.ptr;
7445126258Smlaier			log = s->log;
7446126258Smlaier		} else if (s == NULL)
7447135920Smlaier#ifdef __FreeBSD__
7448130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7449145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7450135920Smlaier#else
7451135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7452145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7453135920Smlaier#endif
7454126258Smlaier		break;
7455126258Smlaier	}
7456126258Smlaier
7457126258Smlaier	case IPPROTO_ICMPV6: {
7458126258Smlaier		struct icmp6_hdr	ih;
7459126258Smlaier
7460126258Smlaier		pd.hdr.icmp6 = &ih;
7461126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
7462126258Smlaier		    &action, &reason, AF_INET6)) {
7463126258Smlaier			log = action != PF_PASS;
7464126258Smlaier			goto done;
7465126258Smlaier		}
7466171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7467145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7468138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
7469126258Smlaier			action = PF_DROP;
7470145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7471126258Smlaier			goto done;
7472126258Smlaier		}
7473130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
7474145836Smlaier		    m, off, h, &pd, &reason);
7475126258Smlaier		if (action == PF_PASS) {
7476130613Smlaier#if NPFSYNC
7477130613Smlaier			pfsync_update_state(s);
7478145836Smlaier#endif /* NPFSYNC */
7479126258Smlaier			r = s->rule.ptr;
7480130613Smlaier			a = s->anchor.ptr;
7481126258Smlaier			log = s->log;
7482126258Smlaier		} else if (s == NULL)
7483145836Smlaier#ifdef __FreeBSD__
7484130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7485145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
7486145836Smlaier#else
7487145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7488145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7489145836Smlaier#endif
7490126258Smlaier		break;
7491126258Smlaier	}
7492126258Smlaier
7493126258Smlaier	default:
7494130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
7495130613Smlaier		if (action == PF_PASS) {
7496145836Smlaier#if NPFSYNC
7497145836Smlaier			pfsync_update_state(s);
7498145836Smlaier#endif /* NPFSYNC */
7499130613Smlaier			r = s->rule.ptr;
7500130613Smlaier			a = s->anchor.ptr;
7501130613Smlaier			log = s->log;
7502130613Smlaier		} else if (s == NULL)
7503145836Smlaier#ifdef __FreeBSD__
7504130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7505145836Smlaier			    &pd, &a, &ruleset, NULL);
7506145836Smlaier#else
7507145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7508145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
7509145836Smlaier#endif
7510126258Smlaier		break;
7511126258Smlaier	}
7512126258Smlaier
7513126258Smlaierdone:
7514169843Sdhartmei	/* handle dangerous IPv6 extension headers. */
7515169843Sdhartmei	if (action == PF_PASS && rh_cnt &&
7516169843Sdhartmei	    !((s && s->allow_opts) || r->allow_opts)) {
7517169843Sdhartmei		action = PF_DROP;
7518169843Sdhartmei		REASON_SET(&reason, PFRES_IPOPTIONS);
7519169843Sdhartmei		log = 1;
7520169843Sdhartmei		DPFPRINTF(PF_DEBUG_MISC,
7521169843Sdhartmei		    ("pf: dropping packet with dangerous v6 headers\n"));
7522169843Sdhartmei	}
7523126258Smlaier
7524171168Smlaier	if ((s && s->tag) || r->rtableid)
7525171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7526145836Smlaier
7527126258Smlaier#ifdef ALTQ
7528126258Smlaier	if (action == PF_PASS && r->qid) {
7529171168Smlaier		if (pd.tos & IPTOS_LOWDELAY)
7530171168Smlaier			pd.pf_mtag->qid = r->pqid;
7531171168Smlaier		else
7532171168Smlaier			pd.pf_mtag->qid = r->qid;
7533171168Smlaier		/* add hints for ecn */
7534171168Smlaier		pd.pf_mtag->af = AF_INET6;
7535171168Smlaier		pd.pf_mtag->hdr = h;
7536126258Smlaier	}
7537145836Smlaier#endif /* ALTQ */
7538126258Smlaier
7539130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7540130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7541130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7542130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7543171168Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
7544171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7545171168Smlaier
7546171168Smlaier	if (log) {
7547171168Smlaier		struct pf_rule *lr;
7548171168Smlaier
7549171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7550171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7551171168Smlaier			lr = s->nat_rule.ptr;
7552171168Smlaier		else
7553171168Smlaier			lr = r;
7554171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
7555171168Smlaier		    &pd);
7556130613Smlaier	}
7557130613Smlaier
7558130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7559130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7560130613Smlaier
7561130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7562171168Smlaier		dirndx = (dir == PF_OUT);
7563171168Smlaier		r->packets[dirndx]++;
7564171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7565130613Smlaier		if (a != NULL) {
7566171168Smlaier			a->packets[dirndx]++;
7567171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7568130613Smlaier		}
7569130613Smlaier		if (s != NULL) {
7570130613Smlaier			if (s->nat_rule.ptr != NULL) {
7571171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7572171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7573130613Smlaier			}
7574130613Smlaier			if (s->src_node != NULL) {
7575171168Smlaier				s->src_node->packets[dirndx]++;
7576171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7577130613Smlaier			}
7578130613Smlaier			if (s->nat_src_node != NULL) {
7579171168Smlaier				s->nat_src_node->packets[dirndx]++;
7580171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7581130613Smlaier			}
7582171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7583171168Smlaier			s->packets[dirndx]++;
7584171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7585130613Smlaier		}
7586130613Smlaier		tr = r;
7587130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7588130613Smlaier		if (nr != NULL) {
7589130613Smlaier			struct pf_addr *x;
7590130613Smlaier			/*
7591130613Smlaier			 * XXX: we need to make sure that the addresses
7592130613Smlaier			 * passed to pfr_update_stats() are the same than
7593130613Smlaier			 * the addresses used during matching (pfr_match)
7594130613Smlaier			 */
7595130613Smlaier			if (r == &pf_default_rule) {
7596130613Smlaier				tr = nr;
7597130613Smlaier				x = (s == NULL || s->direction == dir) ?
7598130613Smlaier				    &pd.baddr : &pd.naddr;
7599130613Smlaier			} else {
7600130613Smlaier				x = (s == NULL || s->direction == dir) ?
7601130613Smlaier				    &pd.naddr : &pd.baddr;
7602130613Smlaier			}
7603130613Smlaier			if (x == &pd.baddr || s == NULL) {
7604130613Smlaier				if (dir == PF_OUT)
7605130613Smlaier					pd.src = x;
7606130613Smlaier				else
7607130613Smlaier					pd.dst = x;
7608130613Smlaier			}
7609130613Smlaier		}
7610130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7611130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7612130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7613130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7614145836Smlaier			    tr->src.neg);
7615130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7616130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7617130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7618130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7619145836Smlaier			    tr->dst.neg);
7620130613Smlaier	}
7621130613Smlaier
7622130613Smlaier
7623126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7624126258Smlaier		m_freem(*m0);
7625126258Smlaier		*m0 = NULL;
7626126258Smlaier		action = PF_PASS;
7627126258Smlaier	} else if (r->rt)
7628126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7629171168Smlaier		pf_route6(m0, r, dir, ifp, s, &pd);
7630126258Smlaier
7631127145Smlaier#ifdef __FreeBSD__
7632126261Smlaier	PF_UNLOCK();
7633126261Smlaier#endif
7634126258Smlaier	return (action);
7635126258Smlaier}
7636126258Smlaier#endif /* INET6 */
7637145836Smlaier
7638145836Smlaierint
7639145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7640145836Smlaier{
7641145836Smlaier#ifdef __FreeBSD__
7642145836Smlaier	/* XXX_IMPORT: later */
7643145836Smlaier	return (0);
7644145836Smlaier#else
7645145836Smlaier	if (ifq->ifq_congestion)
7646145836Smlaier		return (1);
7647145836Smlaier	else
7648145836Smlaier		return (0);
7649145836Smlaier#endif
7650145836Smlaier}
7651