pf.c revision 181803
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 181803 2008-08-17 23:27:27Z bz $");
45126261Smlaier#endif
46126261Smlaier
47127145Smlaier#ifdef __FreeBSD__
48162238Scsjp#include "opt_mac.h"
49126261Smlaier#include "opt_bpf.h"
50126261Smlaier#include "opt_pf.h"
51153110Sru
52153110Sru#ifdef DEV_BPF
53127145Smlaier#define	NBPFILTER	DEV_BPF
54153110Sru#else
55153110Sru#define	NBPFILTER	0
56153110Sru#endif
57153110Sru
58153110Sru#ifdef DEV_PFLOG
59127145Smlaier#define	NPFLOG		DEV_PFLOG
60153110Sru#else
61153110Sru#define	NPFLOG		0
62153110Sru#endif
63153110Sru
64153110Sru#ifdef DEV_PFSYNC
65127145Smlaier#define	NPFSYNC		DEV_PFSYNC
66126261Smlaier#else
67153110Sru#define	NPFSYNC		0
68153110Sru#endif
69153110Sru
70153110Sru#else
71126258Smlaier#include "bpfilter.h"
72126258Smlaier#include "pflog.h"
73126258Smlaier#include "pfsync.h"
74126261Smlaier#endif
75126258Smlaier
76126258Smlaier#include <sys/param.h>
77126258Smlaier#include <sys/systm.h>
78126258Smlaier#include <sys/mbuf.h>
79126258Smlaier#include <sys/filio.h>
80126258Smlaier#include <sys/socket.h>
81126258Smlaier#include <sys/socketvar.h>
82126258Smlaier#include <sys/kernel.h>
83126258Smlaier#include <sys/time.h>
84127145Smlaier#ifdef __FreeBSD__
85126261Smlaier#include <sys/sysctl.h>
86130613Smlaier#include <sys/endian.h>
87126261Smlaier#else
88126258Smlaier#include <sys/pool.h>
89126261Smlaier#endif
90171168Smlaier#include <sys/proc.h>
91171168Smlaier#ifdef __FreeBSD__
92171168Smlaier#include <sys/kthread.h>
93171168Smlaier#include <sys/lock.h>
94171168Smlaier#include <sys/sx.h>
95181803Sbz#include <sys/vimage.h>
96171168Smlaier#else
97171168Smlaier#include <sys/rwlock.h>
98171168Smlaier#endif
99126258Smlaier
100126258Smlaier#include <net/if.h>
101126258Smlaier#include <net/if_types.h>
102126258Smlaier#include <net/bpf.h>
103126258Smlaier#include <net/route.h>
104171168Smlaier#ifndef __FreeBSD__
105171168Smlaier#include <net/radix_mpath.h>
106171168Smlaier#endif
107126258Smlaier
108126258Smlaier#include <netinet/in.h>
109126258Smlaier#include <netinet/in_var.h>
110126258Smlaier#include <netinet/in_systm.h>
111126258Smlaier#include <netinet/ip.h>
112126258Smlaier#include <netinet/ip_var.h>
113126258Smlaier#include <netinet/tcp.h>
114126258Smlaier#include <netinet/tcp_seq.h>
115126258Smlaier#include <netinet/udp.h>
116126258Smlaier#include <netinet/ip_icmp.h>
117126258Smlaier#include <netinet/in_pcb.h>
118126258Smlaier#include <netinet/tcp_timer.h>
119126258Smlaier#include <netinet/tcp_var.h>
120126258Smlaier#include <netinet/udp_var.h>
121126258Smlaier#include <netinet/icmp_var.h>
122145836Smlaier#include <netinet/if_ether.h>
123126258Smlaier
124127145Smlaier#ifndef __FreeBSD__
125126258Smlaier#include <dev/rndvar.h>
126126261Smlaier#endif
127126258Smlaier#include <net/pfvar.h>
128126258Smlaier#include <net/if_pflog.h>
129130613Smlaier
130130613Smlaier#if NPFSYNC > 0
131126258Smlaier#include <net/if_pfsync.h>
132130613Smlaier#endif /* NPFSYNC > 0 */
133126258Smlaier
134126258Smlaier#ifdef INET6
135126258Smlaier#include <netinet/ip6.h>
136126258Smlaier#include <netinet/in_pcb.h>
137126258Smlaier#include <netinet/icmp6.h>
138126258Smlaier#include <netinet6/nd6.h>
139127145Smlaier#ifdef __FreeBSD__
140126261Smlaier#include <netinet6/ip6_var.h>
141126261Smlaier#include <netinet6/in6_pcb.h>
142126261Smlaier#endif
143126258Smlaier#endif /* INET6 */
144126258Smlaier
145127145Smlaier#ifdef __FreeBSD__
146126261Smlaier#include <machine/in_cksum.h>
147126261Smlaier#include <sys/limits.h>
148126261Smlaier#include <sys/ucred.h>
149163606Srwatson#include <security/mac/mac_framework.h>
150126258Smlaier
151126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
152171168Smlaierextern int debug_pfugidhack;
153126261Smlaier#endif
154126261Smlaier
155126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
156126258Smlaier
157126258Smlaier/*
158126258Smlaier * Global variables
159126258Smlaier */
160126258Smlaier
161126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
162126258Smlaierstruct pf_palist	 pf_pabuf;
163126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
164126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
165126258Smlaierstruct pf_status	 pf_status;
166126258Smlaier
167126258Smlaieru_int32_t		 ticket_altqs_active;
168126258Smlaieru_int32_t		 ticket_altqs_inactive;
169130613Smlaierint			 altqs_inactive_open;
170126258Smlaieru_int32_t		 ticket_pabuf;
171126258Smlaier
172145836Smlaierstruct pf_anchor_stackframe {
173145836Smlaier	struct pf_ruleset			*rs;
174145836Smlaier	struct pf_rule				*r;
175145836Smlaier	struct pf_anchor_node			*parent;
176145836Smlaier	struct pf_anchor			*child;
177145836Smlaier} pf_anchor_stack[64];
178126261Smlaier
179127145Smlaier#ifdef __FreeBSD__
180130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
181126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
182126261Smlaier#else
183130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
184126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
185126261Smlaier#endif
186126258Smlaier
187126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
188126258Smlaier
189145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
190145836Smlaier			    u_int32_t);
191145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
192145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
193145836Smlaier
194126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
195126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
196126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
197171168Smlaierint			 pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
198171168Smlaier			    struct tcphdr *, struct pf_state_peer *);
199126258Smlaier#ifdef INET6
200126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
201126258Smlaier			    struct pf_addr *, u_int8_t);
202126258Smlaier#endif /* INET6 */
203126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
204126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
205126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
206126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
207162238Scsjp#ifdef __FreeBSD__
208162238Scsjpvoid			 pf_send_tcp(struct mbuf *,
209162238Scsjp			    const struct pf_rule *, sa_family_t,
210162238Scsjp#else
211126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
212162238Scsjp#endif
213126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
214126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
215145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
216171168Smlaier			    u_int16_t, struct ether_header *, struct ifnet *);
217126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
218126258Smlaier			    sa_family_t, struct pf_rule *);
219126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
220130613Smlaier			    int, int, struct pfi_kif *,
221126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
222126258Smlaier			    u_int16_t, int);
223126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
224130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
225126258Smlaier			    struct pf_addr *, u_int16_t,
226126258Smlaier			    struct pf_addr *, u_int16_t,
227126258Smlaier			    struct pf_addr *, u_int16_t *);
228126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
229130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
230126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
231135920Smlaier#ifdef __FreeBSD__
232145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
233145836Smlaier			    struct inpcb *);
234135920Smlaier#else
235145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
236135920Smlaier#endif
237126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
238130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
239126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
240135920Smlaier#ifdef __FreeBSD__
241145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
242145836Smlaier			    struct inpcb *);
243135920Smlaier#else
244145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
245135920Smlaier#endif
246126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
247130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
248126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
249145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
250126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
251130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
252126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
253145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
254126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
255130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
256126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
257126258Smlaier			    struct pf_ruleset **);
258126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
259130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
260126258Smlaier			    void *, struct pf_pdesc *, u_short *);
261126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
262130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
263126258Smlaier			    void *, struct pf_pdesc *);
264126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
265130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
266145836Smlaier			    void *, struct pf_pdesc *, u_short *);
267126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
268130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
269126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
270171168Smlaier			     struct pf_mtag *, int *);
271171168Smlaierint			 pf_step_out_of_anchor(int *, struct pf_ruleset **,
272171168Smlaier			     int, struct pf_rule **, struct pf_rule **,
273171168Smlaier			     int *);
274126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
275126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
276130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
277126258Smlaier			    struct pf_addr *, struct pf_addr *,
278130613Smlaier			    struct pf_addr *, struct pf_src_node **);
279130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
280126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
281130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
282130613Smlaier			    struct pf_src_node **);
283126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
284171168Smlaier			    struct ifnet *, struct pf_state *,
285171168Smlaier			    struct pf_pdesc *);
286126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
287171168Smlaier			    struct ifnet *, struct pf_state *,
288171168Smlaier			    struct pf_pdesc *);
289135920Smlaier#ifdef __FreeBSD__
290171168Smlaier/* XXX: import */
291135920Smlaier#else
292171168Smlaierint			 pf_socket_lookup(int, struct pf_pdesc *);
293135920Smlaier#endif
294126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
295126258Smlaier			    sa_family_t);
296126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
297126258Smlaier			    sa_family_t);
298126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
299126258Smlaier				u_int16_t);
300126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
301126258Smlaier			    struct pf_addr *);
302126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
303126258Smlaier			    u_int8_t, sa_family_t);
304126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
305126258Smlaier			    struct pf_addr_wrap *);
306130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
307171168Smlaier			    struct pf_state_cmp *, u_int8_t);
308145836Smlaierint			 pf_src_connlimit(struct pf_state **);
309145836Smlaierint			 pf_check_congestion(struct ifqueue *);
310126258Smlaier
311127145Smlaier#ifdef __FreeBSD__
312126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
313126258Smlaier
314171168Smlaierextern int pf_end_threads;
315171168Smlaier
316126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
317171168Smlaier#else
318171168Smlaierextern struct pool pfr_ktable_pl;
319171168Smlaierextern struct pool pfr_kentry_pl;
320145836Smlaier
321130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
322130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
323130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
324171168Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT },
325171168Smlaier	{ &pfr_ktable_pl, PFR_KTABLE_HIWAT },
326171168Smlaier	{ &pfr_kentry_pl, PFR_KENTRY_HIWAT }
327130613Smlaier};
328126261Smlaier#endif
329126258Smlaier
330126258Smlaier#define STATE_LOOKUP()							\
331126258Smlaier	do {								\
332126258Smlaier		if (direction == PF_IN)					\
333145836Smlaier			*state = pf_find_state_recurse(			\
334130613Smlaier			    kif, &key, PF_EXT_GWY);			\
335126258Smlaier		else							\
336145836Smlaier			*state = pf_find_state_recurse(			\
337130613Smlaier			    kif, &key, PF_LAN_EXT);			\
338145836Smlaier		if (*state == NULL || (*state)->timeout == PFTM_PURGE)	\
339126258Smlaier			return (PF_DROP);				\
340126258Smlaier		if (direction == PF_OUT &&				\
341126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
342126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
343126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
344126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
345130613Smlaier		    (*state)->rt_kif != NULL &&				\
346130613Smlaier		    (*state)->rt_kif != kif)				\
347126258Smlaier			return (PF_PASS);				\
348126258Smlaier	} while (0)
349126258Smlaier
350126258Smlaier#define	STATE_TRANSLATE(s) \
351126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
352126258Smlaier	((s)->af == AF_INET6 && \
353126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
354126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
355126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
356126258Smlaier	(s)->lan.port != (s)->gwy.port
357126258Smlaier
358171168Smlaier#define BOUND_IFACE(r, k) \
359171168Smlaier	((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
360126258Smlaier
361145836Smlaier#define STATE_INC_COUNTERS(s)				\
362145836Smlaier	do {						\
363145836Smlaier		s->rule.ptr->states++;			\
364145836Smlaier		if (s->anchor.ptr != NULL)		\
365145836Smlaier			s->anchor.ptr->states++;	\
366145836Smlaier		if (s->nat_rule.ptr != NULL)		\
367145836Smlaier			s->nat_rule.ptr->states++;	\
368145836Smlaier	} while (0)
369145836Smlaier
370145836Smlaier#define STATE_DEC_COUNTERS(s)				\
371145836Smlaier	do {						\
372145836Smlaier		if (s->nat_rule.ptr != NULL)		\
373145836Smlaier			s->nat_rule.ptr->states--;	\
374145836Smlaier		if (s->anchor.ptr != NULL)		\
375145836Smlaier			s->anchor.ptr->states--;	\
376145836Smlaier		s->rule.ptr->states--;			\
377145836Smlaier	} while (0)
378145836Smlaier
379130613Smlaierstruct pf_src_tree tree_src_tracking;
380130613Smlaier
381130613Smlaierstruct pf_state_tree_id tree_id;
382171168Smlaierstruct pf_state_queue state_list;
383130613Smlaier
384171168Smlaier#ifdef __FreeBSD__
385171168Smlaierstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
386171168Smlaierstatic int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *);
387171168Smlaierstatic int pf_state_compare_ext_gwy(struct pf_state *, struct pf_state *);
388171168Smlaierstatic int pf_state_compare_id(struct pf_state *, struct pf_state *);
389171168Smlaier#endif
390171168Smlaier
391130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
392130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
393130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
394130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
395130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
396130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
397130613Smlaier    u.s.entry_id, pf_state_compare_id);
398130613Smlaier
399127145Smlaier#ifdef __FreeBSD__
400126409Smlaierstatic int
401126409Smlaier#else
402126258Smlaierstatic __inline int
403126409Smlaier#endif
404130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
405126258Smlaier{
406126258Smlaier	int	diff;
407126258Smlaier
408130613Smlaier	if (a->rule.ptr > b->rule.ptr)
409130613Smlaier		return (1);
410130613Smlaier	if (a->rule.ptr < b->rule.ptr)
411130613Smlaier		return (-1);
412130613Smlaier	if ((diff = a->af - b->af) != 0)
413130613Smlaier		return (diff);
414130613Smlaier	switch (a->af) {
415130613Smlaier#ifdef INET
416130613Smlaier	case AF_INET:
417130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
418130613Smlaier			return (1);
419130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
420130613Smlaier			return (-1);
421130613Smlaier		break;
422130613Smlaier#endif /* INET */
423130613Smlaier#ifdef INET6
424130613Smlaier	case AF_INET6:
425130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
426130613Smlaier			return (1);
427130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
428130613Smlaier			return (-1);
429130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
430130613Smlaier			return (1);
431130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
432130613Smlaier			return (-1);
433130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
434130613Smlaier			return (1);
435130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
436130613Smlaier			return (-1);
437130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
438130613Smlaier			return (1);
439130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
440130613Smlaier			return (-1);
441130613Smlaier		break;
442130613Smlaier#endif /* INET6 */
443130613Smlaier	}
444130613Smlaier	return (0);
445130613Smlaier}
446130613Smlaier
447130613Smlaier#ifdef __FreeBSD__
448130613Smlaierstatic int
449130613Smlaier#else
450130613Smlaierstatic __inline int
451130613Smlaier#endif
452130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
453130613Smlaier{
454130613Smlaier	int	diff;
455130613Smlaier
456126258Smlaier	if ((diff = a->proto - b->proto) != 0)
457126258Smlaier		return (diff);
458126258Smlaier	if ((diff = a->af - b->af) != 0)
459126258Smlaier		return (diff);
460126258Smlaier	switch (a->af) {
461126258Smlaier#ifdef INET
462126258Smlaier	case AF_INET:
463130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
464126258Smlaier			return (1);
465130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
466126258Smlaier			return (-1);
467130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
468126258Smlaier			return (1);
469130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
470126258Smlaier			return (-1);
471126258Smlaier		break;
472126258Smlaier#endif /* INET */
473126258Smlaier#ifdef INET6
474126258Smlaier	case AF_INET6:
475130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
476126258Smlaier			return (1);
477130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
478126258Smlaier			return (-1);
479130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
480126258Smlaier			return (1);
481130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
482126258Smlaier			return (-1);
483130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
484126258Smlaier			return (1);
485130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
486126258Smlaier			return (-1);
487130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
488126258Smlaier			return (1);
489130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
490126258Smlaier			return (-1);
491130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
492126258Smlaier			return (1);
493130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
494126258Smlaier			return (-1);
495130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
496126258Smlaier			return (1);
497130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
498126258Smlaier			return (-1);
499130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
500126258Smlaier			return (1);
501130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
502126258Smlaier			return (-1);
503130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
504126258Smlaier			return (1);
505130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
506126258Smlaier			return (-1);
507126258Smlaier		break;
508126258Smlaier#endif /* INET6 */
509126258Smlaier	}
510126258Smlaier
511130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
512126258Smlaier		return (diff);
513130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
514126258Smlaier		return (diff);
515126258Smlaier
516126258Smlaier	return (0);
517126258Smlaier}
518126258Smlaier
519130613Smlaier#ifdef __FreeBSD__
520130613Smlaierstatic int
521130613Smlaier#else
522130613Smlaierstatic __inline int
523130613Smlaier#endif
524130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
525130613Smlaier{
526130613Smlaier	int	diff;
527130613Smlaier
528130613Smlaier	if ((diff = a->proto - b->proto) != 0)
529130613Smlaier		return (diff);
530130613Smlaier	if ((diff = a->af - b->af) != 0)
531130613Smlaier		return (diff);
532130613Smlaier	switch (a->af) {
533130613Smlaier#ifdef INET
534130613Smlaier	case AF_INET:
535130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
536130613Smlaier			return (1);
537130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
538130613Smlaier			return (-1);
539130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
540130613Smlaier			return (1);
541130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
542130613Smlaier			return (-1);
543130613Smlaier		break;
544130613Smlaier#endif /* INET */
545126258Smlaier#ifdef INET6
546130613Smlaier	case AF_INET6:
547130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
548130613Smlaier			return (1);
549130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
550130613Smlaier			return (-1);
551130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
552130613Smlaier			return (1);
553130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
554130613Smlaier			return (-1);
555130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
556130613Smlaier			return (1);
557130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
558130613Smlaier			return (-1);
559130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
560130613Smlaier			return (1);
561130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
562130613Smlaier			return (-1);
563130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
564130613Smlaier			return (1);
565130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
566130613Smlaier			return (-1);
567130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
568130613Smlaier			return (1);
569130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
570130613Smlaier			return (-1);
571130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
572130613Smlaier			return (1);
573130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
574130613Smlaier			return (-1);
575130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
576130613Smlaier			return (1);
577130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
578130613Smlaier			return (-1);
579130613Smlaier		break;
580130613Smlaier#endif /* INET6 */
581130613Smlaier	}
582130613Smlaier
583130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
584130613Smlaier		return (diff);
585130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
586130613Smlaier		return (diff);
587130613Smlaier
588130613Smlaier	return (0);
589130613Smlaier}
590130613Smlaier
591130613Smlaier#ifdef __FreeBSD__
592130613Smlaierstatic int
593130613Smlaier#else
594130613Smlaierstatic __inline int
595130613Smlaier#endif
596130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
597130613Smlaier{
598130613Smlaier	if (a->id > b->id)
599130613Smlaier		return (1);
600130613Smlaier	if (a->id < b->id)
601130613Smlaier		return (-1);
602130613Smlaier	if (a->creatorid > b->creatorid)
603130613Smlaier		return (1);
604130613Smlaier	if (a->creatorid < b->creatorid)
605130613Smlaier		return (-1);
606130613Smlaier
607130613Smlaier	return (0);
608130613Smlaier}
609130613Smlaier
610130613Smlaier#ifdef INET6
611126258Smlaiervoid
612126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
613126258Smlaier{
614126258Smlaier	switch (af) {
615126258Smlaier#ifdef INET
616126258Smlaier	case AF_INET:
617126258Smlaier		dst->addr32[0] = src->addr32[0];
618126258Smlaier		break;
619126258Smlaier#endif /* INET */
620126258Smlaier	case AF_INET6:
621126258Smlaier		dst->addr32[0] = src->addr32[0];
622126258Smlaier		dst->addr32[1] = src->addr32[1];
623126258Smlaier		dst->addr32[2] = src->addr32[2];
624126258Smlaier		dst->addr32[3] = src->addr32[3];
625126258Smlaier		break;
626126258Smlaier	}
627126258Smlaier}
628145836Smlaier#endif /* INET6 */
629126258Smlaier
630126258Smlaierstruct pf_state *
631171168Smlaierpf_find_state_byid(struct pf_state_cmp *key)
632126258Smlaier{
633130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
634171168Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
635130613Smlaier}
636126258Smlaier
637130613Smlaierstruct pf_state *
638171168Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree)
639130613Smlaier{
640130613Smlaier	struct pf_state *s;
641130613Smlaier
642126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
643130613Smlaier
644130613Smlaier	switch (tree) {
645130613Smlaier	case PF_LAN_EXT:
646171168Smlaier		if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext,
647171168Smlaier		    (struct pf_state *)key)) != NULL)
648171168Smlaier			return (s);
649171168Smlaier		if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext,
650171168Smlaier		    (struct pf_state *)key)) != NULL)
651171168Smlaier			return (s);
652126258Smlaier		return (NULL);
653130613Smlaier	case PF_EXT_GWY:
654171168Smlaier		if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy,
655171168Smlaier		    (struct pf_state *)key)) != NULL)
656171168Smlaier			return (s);
657171168Smlaier		if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy,
658171168Smlaier		    (struct pf_state *)key)) != NULL)
659171168Smlaier			return (s);
660130613Smlaier		return (NULL);
661130613Smlaier	default:
662130613Smlaier		panic("pf_find_state_recurse");
663130613Smlaier	}
664126258Smlaier}
665126258Smlaier
666130613Smlaierstruct pf_state *
667171168Smlaierpf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more)
668130613Smlaier{
669130613Smlaier	struct pf_state *s, *ss = NULL;
670130613Smlaier	struct pfi_kif	*kif;
671130613Smlaier
672130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
673130613Smlaier
674130613Smlaier	switch (tree) {
675130613Smlaier	case PF_LAN_EXT:
676130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
677130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
678171168Smlaier			    &kif->pfik_lan_ext, (struct pf_state *)key);
679130613Smlaier			if (s == NULL)
680130613Smlaier				continue;
681130613Smlaier			if (more == NULL)
682130613Smlaier				return (s);
683130613Smlaier			ss = s;
684130613Smlaier			(*more)++;
685130613Smlaier		}
686130613Smlaier		return (ss);
687130613Smlaier	case PF_EXT_GWY:
688130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
689130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
690171168Smlaier			    &kif->pfik_ext_gwy, (struct pf_state *)key);
691130613Smlaier			if (s == NULL)
692130613Smlaier				continue;
693130613Smlaier			if (more == NULL)
694130613Smlaier				return (s);
695130613Smlaier			ss = s;
696130613Smlaier			(*more)++;
697130613Smlaier		}
698130613Smlaier		return (ss);
699130613Smlaier	default:
700130613Smlaier		panic("pf_find_state_all");
701130613Smlaier	}
702130613Smlaier}
703130613Smlaier
704145836Smlaiervoid
705145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
706145836Smlaier    u_int32_t limit, u_int32_t seconds)
707145836Smlaier{
708145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
709145836Smlaier	threshold->seconds = seconds;
710145836Smlaier	threshold->count = 0;
711145836Smlaier	threshold->last = time_second;
712145836Smlaier}
713145836Smlaier
714145836Smlaiervoid
715145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
716145836Smlaier{
717145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
718145836Smlaier
719145836Smlaier	if (diff >= threshold->seconds)
720145836Smlaier		threshold->count = 0;
721145836Smlaier	else
722145836Smlaier		threshold->count -= threshold->count * diff /
723145836Smlaier		    threshold->seconds;
724145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
725145836Smlaier	threshold->last = t;
726145836Smlaier}
727145836Smlaier
728126258Smlaierint
729145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
730145836Smlaier{
731145836Smlaier	return (threshold->count > threshold->limit);
732145836Smlaier}
733145836Smlaier
734145836Smlaierint
735145836Smlaierpf_src_connlimit(struct pf_state **state)
736145836Smlaier{
737145836Smlaier	struct pf_state	*s;
738145836Smlaier	int bad = 0;
739145836Smlaier
740145836Smlaier	(*state)->src_node->conn++;
741171168Smlaier	(*state)->src.tcp_est = 1;
742145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
743145836Smlaier
744145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
745145836Smlaier	    (*state)->rule.ptr->max_src_conn <
746145836Smlaier	    (*state)->src_node->conn) {
747145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
748145836Smlaier		bad++;
749145836Smlaier	}
750145836Smlaier
751145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
752145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
753145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
754145836Smlaier		bad++;
755145836Smlaier	}
756145836Smlaier
757145836Smlaier	if (!bad)
758145836Smlaier		return (0);
759145836Smlaier
760145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
761145836Smlaier		struct pfr_addr p;
762145836Smlaier		u_int32_t	killed = 0;
763145836Smlaier
764145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
765145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
766145836Smlaier			printf("pf_src_connlimit: blocking address ");
767145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
768145836Smlaier			    (*state)->af);
769145836Smlaier		}
770145836Smlaier
771145836Smlaier		bzero(&p, sizeof(p));
772145836Smlaier		p.pfra_af = (*state)->af;
773145836Smlaier		switch ((*state)->af) {
774145836Smlaier#ifdef INET
775145836Smlaier		case AF_INET:
776145836Smlaier			p.pfra_net = 32;
777145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
778145836Smlaier			break;
779145836Smlaier#endif /* INET */
780145836Smlaier#ifdef INET6
781145836Smlaier		case AF_INET6:
782145836Smlaier			p.pfra_net = 128;
783145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
784145836Smlaier			break;
785145836Smlaier#endif /* INET6 */
786145836Smlaier		}
787145836Smlaier
788145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
789145836Smlaier		    &p, time_second);
790145836Smlaier
791145836Smlaier		/* kill existing states if that's required. */
792145836Smlaier		if ((*state)->rule.ptr->flush) {
793145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
794145836Smlaier
795145836Smlaier			RB_FOREACH(s, pf_state_tree_id, &tree_id) {
796145836Smlaier				/*
797145836Smlaier				 * Kill states from this source.  (Only those
798145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
799145836Smlaier				 * set)
800145836Smlaier				 */
801145836Smlaier				if (s->af == (*state)->af &&
802145836Smlaier				    (((*state)->direction == PF_OUT &&
803145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
804145836Smlaier				    &s->lan.addr, s->af)) ||
805145836Smlaier				    ((*state)->direction == PF_IN &&
806145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
807145836Smlaier				    &s->ext.addr, s->af))) &&
808145836Smlaier				    ((*state)->rule.ptr->flush &
809145836Smlaier				    PF_FLUSH_GLOBAL ||
810145836Smlaier				    (*state)->rule.ptr == s->rule.ptr)) {
811145836Smlaier					s->timeout = PFTM_PURGE;
812145836Smlaier					s->src.state = s->dst.state =
813145836Smlaier					    TCPS_CLOSED;
814145836Smlaier					killed++;
815145836Smlaier				}
816145836Smlaier			}
817145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
818145836Smlaier				printf(", %u states killed", killed);
819145836Smlaier		}
820145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
821145836Smlaier			printf("\n");
822145836Smlaier	}
823145836Smlaier
824145836Smlaier	/* kill this state */
825145836Smlaier	(*state)->timeout = PFTM_PURGE;
826145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
827145836Smlaier	return (1);
828145836Smlaier}
829145836Smlaier
830145836Smlaierint
831130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
832130613Smlaier    struct pf_addr *src, sa_family_t af)
833126258Smlaier{
834130613Smlaier	struct pf_src_node	k;
835126258Smlaier
836130613Smlaier	if (*sn == NULL) {
837130613Smlaier		k.af = af;
838130613Smlaier		PF_ACPY(&k.addr, src, af);
839130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
840130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
841130613Smlaier			k.rule.ptr = rule;
842130613Smlaier		else
843130613Smlaier			k.rule.ptr = NULL;
844130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
845130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
846130613Smlaier	}
847130613Smlaier	if (*sn == NULL) {
848130613Smlaier		if (!rule->max_src_nodes ||
849130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
850130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
851145836Smlaier		else
852145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
853130613Smlaier		if ((*sn) == NULL)
854130613Smlaier			return (-1);
855130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
856145836Smlaier
857145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
858145836Smlaier		    rule->max_src_conn_rate.limit,
859145836Smlaier		    rule->max_src_conn_rate.seconds);
860145836Smlaier
861130613Smlaier		(*sn)->af = af;
862130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
863130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
864130613Smlaier			(*sn)->rule.ptr = rule;
865130613Smlaier		else
866130613Smlaier			(*sn)->rule.ptr = NULL;
867130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
868130613Smlaier		if (RB_INSERT(pf_src_tree,
869130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
870130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
871130613Smlaier				printf("pf: src_tree insert failed: ");
872130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
873130613Smlaier				printf("\n");
874130613Smlaier			}
875130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
876130613Smlaier			return (-1);
877130613Smlaier		}
878130613Smlaier		(*sn)->creation = time_second;
879130613Smlaier		(*sn)->ruletype = rule->action;
880130613Smlaier		if ((*sn)->rule.ptr != NULL)
881130613Smlaier			(*sn)->rule.ptr->src_nodes++;
882130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
883130613Smlaier		pf_status.src_nodes++;
884130613Smlaier	} else {
885130613Smlaier		if (rule->max_src_states &&
886145836Smlaier		    (*sn)->states >= rule->max_src_states) {
887145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
888130613Smlaier			return (-1);
889145836Smlaier		}
890130613Smlaier	}
891130613Smlaier	return (0);
892130613Smlaier}
893126258Smlaier
894130613Smlaierint
895130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
896130613Smlaier{
897126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
898130613Smlaier	state->u.s.kif = kif;
899130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
900126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
901126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
902126258Smlaier			printf(" lan: ");
903126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
904126258Smlaier			    state->af);
905126258Smlaier			printf(" gwy: ");
906126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
907126258Smlaier			    state->af);
908126258Smlaier			printf(" ext: ");
909126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
910126258Smlaier			    state->af);
911130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
912130613Smlaier				printf(" (from sync)");
913126258Smlaier			printf("\n");
914126258Smlaier		}
915126258Smlaier		return (-1);
916126258Smlaier	}
917126258Smlaier
918130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
919126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
920126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
921126258Smlaier			printf(" lan: ");
922126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
923126258Smlaier			    state->af);
924126258Smlaier			printf(" gwy: ");
925126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
926126258Smlaier			    state->af);
927126258Smlaier			printf(" ext: ");
928126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
929126258Smlaier			    state->af);
930130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
931130613Smlaier				printf(" (from sync)");
932126258Smlaier			printf("\n");
933126258Smlaier		}
934130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
935126258Smlaier		return (-1);
936126258Smlaier	}
937126258Smlaier
938130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
939130613Smlaier		state->id = htobe64(pf_status.stateid++);
940130613Smlaier		state->creatorid = pf_status.hostid;
941130613Smlaier	}
942130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
943130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
944130613Smlaier#ifdef __FreeBSD__
945130613Smlaier			printf("pf: state insert failed: "
946130613Smlaier			    "id: %016llx creatorid: %08x",
947130613Smlaier			    (long long)be64toh(state->id),
948130613Smlaier			    ntohl(state->creatorid));
949130613Smlaier#else
950130613Smlaier			printf("pf: state insert failed: "
951130613Smlaier			    "id: %016llx creatorid: %08x",
952130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
953130613Smlaier#endif
954130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
955130613Smlaier				printf(" (from sync)");
956130613Smlaier			printf("\n");
957130613Smlaier		}
958130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
959130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
960130613Smlaier		return (-1);
961130613Smlaier	}
962171168Smlaier	TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list);
963126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
964126258Smlaier	pf_status.states++;
965171168Smlaier	pfi_kif_ref(kif, PFI_KIF_REF_STATE);
966126258Smlaier#if NPFSYNC
967126258Smlaier	pfsync_insert_state(state);
968126258Smlaier#endif
969126258Smlaier	return (0);
970126258Smlaier}
971126258Smlaier
972126258Smlaiervoid
973171168Smlaierpf_purge_thread(void *v)
974126258Smlaier{
975171168Smlaier	int nloops = 0, s;
976171168Smlaier
977171168Smlaier	for (;;) {
978171168Smlaier		tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
979171168Smlaier
980127145Smlaier#ifdef __FreeBSD__
981171168Smlaier		sx_slock(&pf_consistency_lock);
982171168Smlaier		PF_LOCK();
983126258Smlaier
984171168Smlaier		if (pf_end_threads) {
985171168Smlaier			pf_purge_expired_states(pf_status.states);
986171168Smlaier			pf_purge_expired_fragments();
987171168Smlaier			pf_purge_expired_src_nodes(0);
988171168Smlaier			pf_end_threads++;
989171168Smlaier
990171168Smlaier			sx_sunlock(&pf_consistency_lock);
991171168Smlaier			PF_UNLOCK();
992171168Smlaier			wakeup(pf_purge_thread);
993172836Sjulian			kproc_exit(0);
994171168Smlaier		}
995126261Smlaier#endif
996171168Smlaier		s = splsoftnet();
997126258Smlaier
998171168Smlaier		/* process a fraction of the state table every second */
999171168Smlaier		pf_purge_expired_states(1 + (pf_status.states
1000171168Smlaier		    / pf_default_rule.timeout[PFTM_INTERVAL]));
1001171168Smlaier
1002171168Smlaier		/* purge other expired types every PFTM_INTERVAL seconds */
1003171168Smlaier		if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
1004171168Smlaier			pf_purge_expired_fragments();
1005171168Smlaier			pf_purge_expired_src_nodes(0);
1006171168Smlaier			nloops = 0;
1007171168Smlaier		}
1008171168Smlaier
1009171168Smlaier		splx(s);
1010127145Smlaier#ifdef __FreeBSD__
1011171168Smlaier		PF_UNLOCK();
1012171168Smlaier		sx_sunlock(&pf_consistency_lock);
1013126261Smlaier#endif
1014171168Smlaier	}
1015126258Smlaier}
1016126258Smlaier
1017126258Smlaieru_int32_t
1018126258Smlaierpf_state_expires(const struct pf_state *state)
1019126258Smlaier{
1020126258Smlaier	u_int32_t	timeout;
1021126258Smlaier	u_int32_t	start;
1022126258Smlaier	u_int32_t	end;
1023126258Smlaier	u_int32_t	states;
1024126258Smlaier
1025126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1026126258Smlaier	if (state->timeout == PFTM_PURGE)
1027126261Smlaier		return (time_second);
1028126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1029126258Smlaier		return (0);
1030127145Smlaier#ifdef __FreeBSD__
1031171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED,
1032171168Smlaier	    ("pf_state_expires: timeout == PFTM_UNLINKED"));
1033126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1034126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1035126261Smlaier#else
1036171168Smlaier	KASSERT(state->timeout != PFTM_UNLINKED);
1037126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1038126261Smlaier#endif
1039126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1040126258Smlaier	if (!timeout)
1041126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1042126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1043126258Smlaier	if (start) {
1044126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1045126258Smlaier		states = state->rule.ptr->states;
1046126258Smlaier	} else {
1047126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1048126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1049126258Smlaier		states = pf_status.states;
1050126258Smlaier	}
1051126258Smlaier	if (end && states > start && start < end) {
1052126258Smlaier		if (states < end)
1053126258Smlaier			return (state->expire + timeout * (end - states) /
1054126258Smlaier			    (end - start));
1055126258Smlaier		else
1056126261Smlaier			return (time_second);
1057126258Smlaier	}
1058126258Smlaier	return (state->expire + timeout);
1059126258Smlaier}
1060126258Smlaier
1061126258Smlaiervoid
1062171168Smlaierpf_purge_expired_src_nodes(int waslocked)
1063126258Smlaier{
1064130613Smlaier	 struct pf_src_node		*cur, *next;
1065171168Smlaier	 int				 locked = waslocked;
1066126258Smlaier
1067130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1068130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1069126258Smlaier
1070130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1071171168Smlaier			 if (! locked) {
1072171168Smlaier#ifdef __FreeBSD__
1073171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1074171168Smlaier					 PF_UNLOCK();
1075171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1076171168Smlaier					 sx_xlock(&pf_consistency_lock);
1077171168Smlaier					 PF_LOCK();
1078171168Smlaier				 }
1079171168Smlaier#else
1080171168Smlaier				 rw_enter_write(&pf_consistency_lock);
1081171168Smlaier#endif
1082171168Smlaier			 	 next = RB_NEXT(pf_src_tree,
1083171168Smlaier				     &tree_src_tracking, cur);
1084171168Smlaier				 locked = 1;
1085171168Smlaier			 }
1086130613Smlaier			 if (cur->rule.ptr != NULL) {
1087130613Smlaier				 cur->rule.ptr->src_nodes--;
1088130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1089130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1090130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1091130613Smlaier			 }
1092130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1093130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1094130613Smlaier			 pf_status.src_nodes--;
1095130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1096130613Smlaier		 }
1097130613Smlaier	 }
1098171168Smlaier
1099171168Smlaier	 if (locked && !waslocked)
1100171168Smlaier#ifdef __FreeBSD__
1101171168Smlaier		sx_downgrade(&pf_consistency_lock);
1102171168Smlaier#else
1103171168Smlaier		rw_exit_write(&pf_consistency_lock);
1104171168Smlaier#endif
1105130613Smlaier}
1106126258Smlaier
1107130613Smlaiervoid
1108130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1109130613Smlaier{
1110130613Smlaier	u_int32_t timeout;
1111126258Smlaier
1112130613Smlaier	if (s->src_node != NULL) {
1113145836Smlaier		if (s->proto == IPPROTO_TCP) {
1114171168Smlaier			if (s->src.tcp_est)
1115145836Smlaier				--s->src_node->conn;
1116145836Smlaier		}
1117130613Smlaier		if (--s->src_node->states <= 0) {
1118130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1119130613Smlaier			if (!timeout)
1120130613Smlaier				timeout =
1121130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1122130613Smlaier			s->src_node->expire = time_second + timeout;
1123130613Smlaier		}
1124130613Smlaier	}
1125130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1126130613Smlaier		if (--s->nat_src_node->states <= 0) {
1127130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1128130613Smlaier			if (!timeout)
1129130613Smlaier				timeout =
1130130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1131130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1132130613Smlaier		}
1133130613Smlaier	}
1134130613Smlaier	s->src_node = s->nat_src_node = NULL;
1135130613Smlaier}
1136126258Smlaier
1137171168Smlaier/* callers should be at splsoftnet */
1138130613Smlaiervoid
1139171168Smlaierpf_unlink_state(struct pf_state *cur)
1140145836Smlaier{
1141148196Smlaier#ifdef __FreeBSD__
1142153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1143148196Smlaier		return;
1144153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1145148196Smlaier#endif
1146171168Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST) {
1147162238Scsjp#ifdef __FreeBSD__
1148162238Scsjp		pf_send_tcp(NULL, cur->rule.ptr, cur->af,
1149162238Scsjp#else
1150145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1151162238Scsjp#endif
1152145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1153145836Smlaier		    cur->ext.port, cur->lan.port,
1154145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1155171168Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
1156171168Smlaier	}
1157145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1158145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1159145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1160145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1161145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1162145836Smlaier#if NPFSYNC
1163171168Smlaier	if (cur->creatorid == pf_status.hostid)
1164171168Smlaier		pfsync_delete_state(cur);
1165145836Smlaier#endif
1166171168Smlaier	cur->timeout = PFTM_UNLINKED;
1167145836Smlaier	pf_src_tree_remove_state(cur);
1168171168Smlaier}
1169171168Smlaier
1170171168Smlaier/* callers should be at splsoftnet and hold the
1171171168Smlaier * write_lock on pf_consistency_lock */
1172171168Smlaiervoid
1173171168Smlaierpf_free_state(struct pf_state *cur)
1174171168Smlaier{
1175171168Smlaier#if NPFSYNC
1176171168Smlaier	if (pfsyncif != NULL &&
1177171168Smlaier	    (pfsyncif->sc_bulk_send_next == cur ||
1178171168Smlaier	    pfsyncif->sc_bulk_terminator == cur))
1179171168Smlaier		return;
1180171168Smlaier#endif
1181171168Smlaier#ifdef __FreeBSD__
1182171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED,
1183171168Smlaier	    ("pf_free_state: cur->timeout != PFTM_UNLINKED"));
1184171168Smlaier#else
1185171168Smlaier	KASSERT(cur->timeout == PFTM_UNLINKED);
1186171168Smlaier#endif
1187145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1188145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1189145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1190145836Smlaier	if (cur->nat_rule.ptr != NULL)
1191145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1192145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1193145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1194145836Smlaier	if (cur->anchor.ptr != NULL)
1195145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1196145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1197145836Smlaier	pf_normalize_tcp_cleanup(cur);
1198171168Smlaier	pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE);
1199171168Smlaier	TAILQ_REMOVE(&state_list, cur, u.s.entry_list);
1200145836Smlaier	if (cur->tag)
1201145836Smlaier		pf_tag_unref(cur->tag);
1202145836Smlaier	pool_put(&pf_state_pl, cur);
1203145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1204145836Smlaier	pf_status.states--;
1205145836Smlaier}
1206145836Smlaier
1207145836Smlaiervoid
1208171168Smlaierpf_purge_expired_states(u_int32_t maxcheck)
1209130613Smlaier{
1210171168Smlaier	static struct pf_state	*cur = NULL;
1211171168Smlaier	struct pf_state		*next;
1212171168Smlaier	int 			 locked = 0;
1213130613Smlaier
1214171168Smlaier	while (maxcheck--) {
1215171168Smlaier		/* wrap to start of list when we hit the end */
1216171168Smlaier		if (cur == NULL) {
1217171168Smlaier			cur = TAILQ_FIRST(&state_list);
1218171168Smlaier			if (cur == NULL)
1219171168Smlaier				break;	/* list empty */
1220171168Smlaier		}
1221171168Smlaier
1222171168Smlaier		/* get next state, as cur may get deleted */
1223171168Smlaier		next = TAILQ_NEXT(cur, u.s.entry_list);
1224171168Smlaier
1225171168Smlaier		if (cur->timeout == PFTM_UNLINKED) {
1226171168Smlaier			/* free unlinked state */
1227171168Smlaier			if (! locked) {
1228171168Smlaier#ifdef __FreeBSD__
1229171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1230171168Smlaier					 PF_UNLOCK();
1231171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1232171168Smlaier					 sx_xlock(&pf_consistency_lock);
1233171168Smlaier					 PF_LOCK();
1234171168Smlaier				 }
1235171168Smlaier#else
1236171168Smlaier				rw_enter_write(&pf_consistency_lock);
1237171168Smlaier#endif
1238171168Smlaier				locked = 1;
1239171168Smlaier			}
1240171168Smlaier			pf_free_state(cur);
1241171168Smlaier		} else if (pf_state_expires(cur) <= time_second) {
1242171168Smlaier			/* unlink and free expired state */
1243171168Smlaier			pf_unlink_state(cur);
1244171168Smlaier			if (! locked) {
1245171168Smlaier#ifdef __FreeBSD__
1246171168Smlaier				 if (!sx_try_upgrade(&pf_consistency_lock)) {
1247171168Smlaier					 PF_UNLOCK();
1248171168Smlaier					 sx_sunlock(&pf_consistency_lock);
1249171168Smlaier					 sx_xlock(&pf_consistency_lock);
1250171168Smlaier					 PF_LOCK();
1251171168Smlaier				 }
1252171168Smlaier#else
1253171168Smlaier				rw_enter_write(&pf_consistency_lock);
1254171168Smlaier#endif
1255171168Smlaier				locked = 1;
1256171168Smlaier			}
1257171168Smlaier			pf_free_state(cur);
1258171168Smlaier		}
1259171168Smlaier		cur = next;
1260126258Smlaier	}
1261171168Smlaier
1262171168Smlaier	if (locked)
1263171168Smlaier#ifdef __FreeBSD__
1264171168Smlaier		sx_downgrade(&pf_consistency_lock);
1265171168Smlaier#else
1266171168Smlaier		rw_exit_write(&pf_consistency_lock);
1267171168Smlaier#endif
1268126258Smlaier}
1269126258Smlaier
1270126258Smlaierint
1271126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1272126258Smlaier{
1273126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1274126258Smlaier		return (0);
1275126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1276126258Smlaier		return (1);
1277126258Smlaier	return (0);
1278126258Smlaier}
1279126258Smlaier
1280126258Smlaiervoid
1281126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1282126258Smlaier{
1283126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1284126258Smlaier		return;
1285126258Smlaier	pfr_detach_table(aw->p.tbl);
1286126258Smlaier	aw->p.tbl = NULL;
1287126258Smlaier}
1288126258Smlaier
1289126258Smlaiervoid
1290126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1291126258Smlaier{
1292126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1293126258Smlaier
1294126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1295126258Smlaier		return;
1296126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1297126258Smlaier		kt = kt->pfrkt_root;
1298126258Smlaier	aw->p.tbl = NULL;
1299126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1300126258Smlaier		kt->pfrkt_cnt : -1;
1301126258Smlaier}
1302126258Smlaier
1303126258Smlaiervoid
1304126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1305126258Smlaier{
1306126258Smlaier	switch (af) {
1307126258Smlaier#ifdef INET
1308126258Smlaier	case AF_INET: {
1309126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1310126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1311126258Smlaier		    (a>>8)&255, a&255);
1312126258Smlaier		if (p) {
1313126258Smlaier			p = ntohs(p);
1314126258Smlaier			printf(":%u", p);
1315126258Smlaier		}
1316126258Smlaier		break;
1317126258Smlaier	}
1318126258Smlaier#endif /* INET */
1319126258Smlaier#ifdef INET6
1320126258Smlaier	case AF_INET6: {
1321126258Smlaier		u_int16_t b;
1322126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1323126258Smlaier		    maxstart = 0, maxend = 0;
1324126258Smlaier		for (i = 0; i < 8; i++) {
1325126258Smlaier			if (!addr->addr16[i]) {
1326126258Smlaier				if (curstart == 255)
1327126258Smlaier					curstart = i;
1328126258Smlaier				else
1329126258Smlaier					curend = i;
1330126258Smlaier			} else {
1331126258Smlaier				if (curstart) {
1332126258Smlaier					if ((curend - curstart) >
1333126258Smlaier					    (maxend - maxstart)) {
1334126258Smlaier						maxstart = curstart;
1335126258Smlaier						maxend = curend;
1336126258Smlaier						curstart = 255;
1337126258Smlaier					}
1338126258Smlaier				}
1339126258Smlaier			}
1340126258Smlaier		}
1341126258Smlaier		for (i = 0; i < 8; i++) {
1342126258Smlaier			if (i >= maxstart && i <= maxend) {
1343126258Smlaier				if (maxend != 7) {
1344126258Smlaier					if (i == maxstart)
1345126258Smlaier						printf(":");
1346126258Smlaier				} else {
1347126258Smlaier					if (i == maxend)
1348126258Smlaier						printf(":");
1349126258Smlaier				}
1350126258Smlaier			} else {
1351126258Smlaier				b = ntohs(addr->addr16[i]);
1352126258Smlaier				printf("%x", b);
1353126258Smlaier				if (i < 7)
1354126258Smlaier					printf(":");
1355126258Smlaier			}
1356126258Smlaier		}
1357126258Smlaier		if (p) {
1358126258Smlaier			p = ntohs(p);
1359126258Smlaier			printf("[%u]", p);
1360126258Smlaier		}
1361126258Smlaier		break;
1362126258Smlaier	}
1363126258Smlaier#endif /* INET6 */
1364126258Smlaier	}
1365126258Smlaier}
1366126258Smlaier
1367126258Smlaiervoid
1368126258Smlaierpf_print_state(struct pf_state *s)
1369126258Smlaier{
1370126258Smlaier	switch (s->proto) {
1371126258Smlaier	case IPPROTO_TCP:
1372126258Smlaier		printf("TCP ");
1373126258Smlaier		break;
1374126258Smlaier	case IPPROTO_UDP:
1375126258Smlaier		printf("UDP ");
1376126258Smlaier		break;
1377126258Smlaier	case IPPROTO_ICMP:
1378126258Smlaier		printf("ICMP ");
1379126258Smlaier		break;
1380126258Smlaier	case IPPROTO_ICMPV6:
1381126258Smlaier		printf("ICMPV6 ");
1382126258Smlaier		break;
1383126258Smlaier	default:
1384126258Smlaier		printf("%u ", s->proto);
1385126258Smlaier		break;
1386126258Smlaier	}
1387126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1388126258Smlaier	printf(" ");
1389126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1390126258Smlaier	printf(" ");
1391126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1392126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1393126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1394126258Smlaier	if (s->src.wscale && s->dst.wscale)
1395126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1396126258Smlaier	printf("]");
1397126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1398126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1399126258Smlaier	if (s->src.wscale && s->dst.wscale)
1400126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1401126258Smlaier	printf("]");
1402126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1403126258Smlaier}
1404126258Smlaier
1405126258Smlaiervoid
1406126258Smlaierpf_print_flags(u_int8_t f)
1407126258Smlaier{
1408126258Smlaier	if (f)
1409126258Smlaier		printf(" ");
1410126258Smlaier	if (f & TH_FIN)
1411126258Smlaier		printf("F");
1412126258Smlaier	if (f & TH_SYN)
1413126258Smlaier		printf("S");
1414126258Smlaier	if (f & TH_RST)
1415126258Smlaier		printf("R");
1416126258Smlaier	if (f & TH_PUSH)
1417126258Smlaier		printf("P");
1418126258Smlaier	if (f & TH_ACK)
1419126258Smlaier		printf("A");
1420126258Smlaier	if (f & TH_URG)
1421126258Smlaier		printf("U");
1422126258Smlaier	if (f & TH_ECE)
1423126258Smlaier		printf("E");
1424126258Smlaier	if (f & TH_CWR)
1425126258Smlaier		printf("W");
1426126258Smlaier}
1427126258Smlaier
1428126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1429126258Smlaier	do {							\
1430126258Smlaier		while (head[i] != cur) {			\
1431126258Smlaier			head[i]->skip[i].ptr = cur;		\
1432126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1433126258Smlaier		}						\
1434126258Smlaier	} while (0)
1435126258Smlaier
1436126258Smlaiervoid
1437126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1438126258Smlaier{
1439126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1440126258Smlaier	int i;
1441126258Smlaier
1442126258Smlaier	cur = TAILQ_FIRST(rules);
1443126258Smlaier	prev = cur;
1444126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1445126258Smlaier		head[i] = cur;
1446126258Smlaier	while (cur != NULL) {
1447126258Smlaier
1448130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1449126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1450126258Smlaier		if (cur->direction != prev->direction)
1451126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1452126258Smlaier		if (cur->af != prev->af)
1453126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1454126258Smlaier		if (cur->proto != prev->proto)
1455126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1456145836Smlaier		if (cur->src.neg != prev->src.neg ||
1457126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1458126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1459126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1460126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1461126258Smlaier		    cur->src.port_op != prev->src.port_op)
1462126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1463145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1464126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1465126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1466126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1467126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1468126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1469126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1470126258Smlaier
1471126258Smlaier		prev = cur;
1472126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1473126258Smlaier	}
1474126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1475126258Smlaier		PF_SET_SKIP_STEPS(i);
1476126258Smlaier}
1477126258Smlaier
1478126258Smlaierint
1479126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1480126258Smlaier{
1481126258Smlaier	if (aw1->type != aw2->type)
1482126258Smlaier		return (1);
1483126258Smlaier	switch (aw1->type) {
1484126258Smlaier	case PF_ADDR_ADDRMASK:
1485126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1486126258Smlaier			return (1);
1487126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1488126258Smlaier			return (1);
1489126258Smlaier		return (0);
1490126258Smlaier	case PF_ADDR_DYNIFTL:
1491130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1492126258Smlaier	case PF_ADDR_NOROUTE:
1493171168Smlaier	case PF_ADDR_URPFFAILED:
1494126258Smlaier		return (0);
1495126258Smlaier	case PF_ADDR_TABLE:
1496126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1497171168Smlaier	case PF_ADDR_RTLABEL:
1498171168Smlaier		return (aw1->v.rtlabel != aw2->v.rtlabel);
1499126258Smlaier	default:
1500126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1501126258Smlaier		return (1);
1502126258Smlaier	}
1503126258Smlaier}
1504126258Smlaier
1505126258Smlaieru_int16_t
1506126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1507126258Smlaier{
1508126258Smlaier	u_int32_t	l;
1509126258Smlaier
1510126258Smlaier	if (udp && !cksum)
1511126258Smlaier		return (0x0000);
1512126258Smlaier	l = cksum + old - new;
1513126258Smlaier	l = (l >> 16) + (l & 65535);
1514126258Smlaier	l = l & 65535;
1515126258Smlaier	if (udp && !l)
1516126258Smlaier		return (0xFFFF);
1517126258Smlaier	return (l);
1518126258Smlaier}
1519126258Smlaier
1520126258Smlaiervoid
1521126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1522126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1523126258Smlaier{
1524126258Smlaier	struct pf_addr	ao;
1525126258Smlaier	u_int16_t	po = *p;
1526126258Smlaier
1527126258Smlaier	PF_ACPY(&ao, a, af);
1528126258Smlaier	PF_ACPY(a, an, af);
1529126258Smlaier
1530126258Smlaier	*p = pn;
1531126258Smlaier
1532126258Smlaier	switch (af) {
1533126258Smlaier#ifdef INET
1534126258Smlaier	case AF_INET:
1535126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1536126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1537126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1538126258Smlaier		*p = pn;
1539126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1540126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1541126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1542126258Smlaier		    po, pn, u);
1543126258Smlaier		break;
1544126258Smlaier#endif /* INET */
1545126258Smlaier#ifdef INET6
1546126258Smlaier	case AF_INET6:
1547126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1548126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1549126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1550126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1551126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1552126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1553126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1554126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1555126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1556126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1557126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1558126258Smlaier		    po, pn, u);
1559126258Smlaier		break;
1560126258Smlaier#endif /* INET6 */
1561126258Smlaier	}
1562126258Smlaier}
1563126258Smlaier
1564126258Smlaier
1565126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1566126258Smlaiervoid
1567126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1568126258Smlaier{
1569126258Smlaier	u_int32_t	ao;
1570126258Smlaier
1571126258Smlaier	memcpy(&ao, a, sizeof(ao));
1572126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1573126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1574126258Smlaier	    ao % 65536, an % 65536, u);
1575126258Smlaier}
1576126258Smlaier
1577126258Smlaier#ifdef INET6
1578126258Smlaiervoid
1579126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1580126258Smlaier{
1581126258Smlaier	struct pf_addr	ao;
1582126258Smlaier
1583126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1584126258Smlaier	PF_ACPY(a, an, AF_INET6);
1585126258Smlaier
1586126258Smlaier	*c = 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(*c,
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}
1598126258Smlaier#endif /* INET6 */
1599126258Smlaier
1600126258Smlaiervoid
1601126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1602126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1603126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1604126258Smlaier{
1605126258Smlaier	struct pf_addr	oia, ooa;
1606126258Smlaier
1607126258Smlaier	PF_ACPY(&oia, ia, af);
1608126258Smlaier	PF_ACPY(&ooa, oa, af);
1609126258Smlaier
1610126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1611126258Smlaier	if (ip != NULL) {
1612126258Smlaier		u_int16_t	oip = *ip;
1613127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1614126258Smlaier
1615126258Smlaier		if (pc != NULL)
1616126258Smlaier			opc = *pc;
1617126258Smlaier		*ip = np;
1618126258Smlaier		if (pc != NULL)
1619126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1620126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1621126258Smlaier		if (pc != NULL)
1622126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1623126258Smlaier	}
1624126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1625126258Smlaier	PF_ACPY(ia, na, af);
1626126258Smlaier	switch (af) {
1627126258Smlaier#ifdef INET
1628126258Smlaier	case AF_INET: {
1629126258Smlaier		u_int32_t	 oh2c = *h2c;
1630126258Smlaier
1631126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1632126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1633126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1634126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1635126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1636126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1637126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1638126258Smlaier		break;
1639126258Smlaier	}
1640126258Smlaier#endif /* INET */
1641126258Smlaier#ifdef INET6
1642126258Smlaier	case AF_INET6:
1643126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1644126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1645126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1646126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1647126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1648126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1649126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1650126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1651126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1652126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1653126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1654126258Smlaier		break;
1655126258Smlaier#endif /* INET6 */
1656126258Smlaier	}
1657126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1658126258Smlaier	PF_ACPY(oa, na, af);
1659126258Smlaier	switch (af) {
1660126258Smlaier#ifdef INET
1661126258Smlaier	case AF_INET:
1662126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1663126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1664126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1665126258Smlaier		break;
1666126258Smlaier#endif /* INET */
1667126258Smlaier#ifdef INET6
1668126258Smlaier	case AF_INET6:
1669126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1670126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1671126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1672126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1673126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1674126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1675126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1676126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1677126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1678126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1679126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1680126258Smlaier		break;
1681126258Smlaier#endif /* INET6 */
1682126258Smlaier	}
1683126258Smlaier}
1684126258Smlaier
1685171168Smlaier
1686171168Smlaier/*
1687171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option
1688171168Smlaier * (credits to Krzysztof Pfaff for report and patch)
1689171168Smlaier */
1690171168Smlaierint
1691171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
1692171168Smlaier    struct tcphdr *th, struct pf_state_peer *dst)
1693171168Smlaier{
1694171168Smlaier	int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
1695171168Smlaier#ifdef __FreeBSD__
1696171168Smlaier	u_int8_t opts[TCP_MAXOLEN], *opt = opts;
1697171168Smlaier#else
1698171168Smlaier	u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
1699171168Smlaier#endif
1700171168Smlaier	int copyback = 0, i, olen;
1701171168Smlaier	struct sackblk sack;
1702171168Smlaier
1703171168Smlaier#define TCPOLEN_SACKLEN	(TCPOLEN_SACK + 2)
1704171168Smlaier	if (hlen < TCPOLEN_SACKLEN ||
1705171168Smlaier	    !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
1706171168Smlaier		return 0;
1707171168Smlaier
1708171168Smlaier	while (hlen >= TCPOLEN_SACKLEN) {
1709171168Smlaier		olen = opt[1];
1710171168Smlaier		switch (*opt) {
1711171168Smlaier		case TCPOPT_EOL:	/* FALLTHROUGH */
1712171168Smlaier		case TCPOPT_NOP:
1713171168Smlaier			opt++;
1714171168Smlaier			hlen--;
1715171168Smlaier			break;
1716171168Smlaier		case TCPOPT_SACK:
1717171168Smlaier			if (olen > hlen)
1718171168Smlaier				olen = hlen;
1719171168Smlaier			if (olen >= TCPOLEN_SACKLEN) {
1720171168Smlaier				for (i = 2; i + TCPOLEN_SACK <= olen;
1721171168Smlaier				    i += TCPOLEN_SACK) {
1722171168Smlaier					memcpy(&sack, &opt[i], sizeof(sack));
1723171168Smlaier					pf_change_a(&sack.start, &th->th_sum,
1724171168Smlaier					    htonl(ntohl(sack.start) -
1725171168Smlaier					    dst->seqdiff), 0);
1726171168Smlaier					pf_change_a(&sack.end, &th->th_sum,
1727171168Smlaier					    htonl(ntohl(sack.end) -
1728171168Smlaier					    dst->seqdiff), 0);
1729171168Smlaier					memcpy(&opt[i], &sack, sizeof(sack));
1730171168Smlaier				}
1731171168Smlaier				copyback = 1;
1732171168Smlaier			}
1733171168Smlaier			/* FALLTHROUGH */
1734171168Smlaier		default:
1735171168Smlaier			if (olen < 2)
1736171168Smlaier				olen = 2;
1737171168Smlaier			hlen -= olen;
1738171168Smlaier			opt += olen;
1739171168Smlaier		}
1740171168Smlaier	}
1741171168Smlaier
1742171168Smlaier	if (copyback)
1743171168Smlaier#ifdef __FreeBSD__
1744171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts);
1745171168Smlaier#else
1746171168Smlaier		m_copyback(m, off + sizeof(*th), thoptlen, opts);
1747171168Smlaier#endif
1748171168Smlaier	return (copyback);
1749171168Smlaier}
1750171168Smlaier
1751126258Smlaiervoid
1752162238Scsjp#ifdef __FreeBSD__
1753162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
1754162238Scsjp#else
1755126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1756162238Scsjp#endif
1757126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1758126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1759145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1760171168Smlaier    u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
1761126258Smlaier{
1762126258Smlaier	struct mbuf	*m;
1763171168Smlaier	int		 len, tlen;
1764126258Smlaier#ifdef INET
1765171168Smlaier	struct ip	*h;
1766126258Smlaier#endif /* INET */
1767126258Smlaier#ifdef INET6
1768171168Smlaier	struct ip6_hdr	*h6;
1769126258Smlaier#endif /* INET6 */
1770171168Smlaier	struct tcphdr	*th;
1771171168Smlaier	char		*opt;
1772171168Smlaier	struct pf_mtag	*pf_mtag;
1773126258Smlaier
1774171168Smlaier#ifdef __FreeBSD__
1775171168Smlaier	KASSERT(
1776171168Smlaier#ifdef INET
1777171168Smlaier	    af == AF_INET
1778171168Smlaier#else
1779171168Smlaier	    0
1780171168Smlaier#endif
1781171168Smlaier	    ||
1782171168Smlaier#ifdef INET6
1783171168Smlaier	    af == AF_INET6
1784171168Smlaier#else
1785171168Smlaier	    0
1786171168Smlaier#endif
1787171168Smlaier	    , ("Unsupported AF %d", af));
1788171168Smlaier	len = 0;
1789171168Smlaier	th = NULL;
1790171168Smlaier#ifdef INET
1791171168Smlaier	h = NULL;
1792171168Smlaier#endif
1793171168Smlaier#ifdef INET6
1794171168Smlaier	h6 = NULL;
1795171168Smlaier#endif
1796171168Smlaier#endif
1797171168Smlaier
1798126258Smlaier	/* maximum segment size tcp option */
1799126258Smlaier	tlen = sizeof(struct tcphdr);
1800126258Smlaier	if (mss)
1801126258Smlaier		tlen += 4;
1802126258Smlaier
1803126258Smlaier	switch (af) {
1804126258Smlaier#ifdef INET
1805126258Smlaier	case AF_INET:
1806126258Smlaier		len = sizeof(struct ip) + tlen;
1807126258Smlaier		break;
1808126258Smlaier#endif /* INET */
1809126258Smlaier#ifdef INET6
1810126258Smlaier	case AF_INET6:
1811126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1812126258Smlaier		break;
1813126258Smlaier#endif /* INET6 */
1814126258Smlaier	}
1815126258Smlaier
1816126258Smlaier	/* create outgoing mbuf */
1817132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1818132280Smlaier	if (m == NULL)
1819132280Smlaier		return;
1820162238Scsjp#ifdef __FreeBSD__
1821162238Scsjp#ifdef MAC
1822162238Scsjp	if (replyto)
1823173102Srwatson		mac_netinet_firewall_reply(replyto, m);
1824162238Scsjp	else
1825173018Srwatson		mac_netinet_firewall_send(m);
1826162238Scsjp#else
1827162238Scsjp	(void)replyto;
1828162238Scsjp#endif
1829162238Scsjp#endif
1830171168Smlaier	if ((pf_mtag = pf_get_mtag(m)) == NULL) {
1831171168Smlaier		m_freem(m);
1832171168Smlaier		return;
1833171168Smlaier	}
1834171168Smlaier	if (tag)
1835145836Smlaier#ifdef __FreeBSD__
1836145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1837132280Smlaier#else
1838171168Smlaier		pf_mtag->flags |= PF_TAG_GENERATED;
1839171168Smlaier#endif
1840145836Smlaier
1841171168Smlaier	pf_mtag->tag = rtag;
1842171168Smlaier
1843171168Smlaier	if (r != NULL && r->rtableid >= 0)
1844178888Sjulian#ifdef __FreeBSD__
1845178888Sjulian	{
1846178888Sjulian		M_SETFIB(m, r->rtableid);
1847178888Sjulian#endif
1848171168Smlaier		pf_mtag->rtableid = r->rtableid;
1849178888Sjulian#ifdef __FreeBSD__
1850178888Sjulian	}
1851178888Sjulian#endif
1852126258Smlaier#ifdef ALTQ
1853126258Smlaier	if (r != NULL && r->qid) {
1854171168Smlaier		pf_mtag->qid = r->qid;
1855171168Smlaier		/* add hints for ecn */
1856171168Smlaier		pf_mtag->af = af;
1857171168Smlaier		pf_mtag->hdr = mtod(m, struct ip *);
1858126258Smlaier	}
1859145836Smlaier#endif /* ALTQ */
1860126258Smlaier	m->m_data += max_linkhdr;
1861126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1862126258Smlaier	m->m_pkthdr.rcvif = NULL;
1863126258Smlaier	bzero(m->m_data, len);
1864126258Smlaier	switch (af) {
1865126258Smlaier#ifdef INET
1866126258Smlaier	case AF_INET:
1867126258Smlaier		h = mtod(m, struct ip *);
1868126258Smlaier
1869126258Smlaier		/* IP header fields included in the TCP checksum */
1870126258Smlaier		h->ip_p = IPPROTO_TCP;
1871126258Smlaier		h->ip_len = htons(tlen);
1872126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1873126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1874126258Smlaier
1875126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1876126258Smlaier		break;
1877126258Smlaier#endif /* INET */
1878126258Smlaier#ifdef INET6
1879126258Smlaier	case AF_INET6:
1880126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1881126258Smlaier
1882126258Smlaier		/* IP header fields included in the TCP checksum */
1883126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1884126258Smlaier		h6->ip6_plen = htons(tlen);
1885126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1886126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1887126258Smlaier
1888126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1889126258Smlaier		break;
1890126258Smlaier#endif /* INET6 */
1891126258Smlaier	}
1892126258Smlaier
1893126258Smlaier	/* TCP header */
1894126258Smlaier	th->th_sport = sport;
1895126258Smlaier	th->th_dport = dport;
1896126258Smlaier	th->th_seq = htonl(seq);
1897126258Smlaier	th->th_ack = htonl(ack);
1898126258Smlaier	th->th_off = tlen >> 2;
1899126258Smlaier	th->th_flags = flags;
1900126258Smlaier	th->th_win = htons(win);
1901126258Smlaier
1902126258Smlaier	if (mss) {
1903126258Smlaier		opt = (char *)(th + 1);
1904126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1905126258Smlaier		opt[1] = 4;
1906126258Smlaier		HTONS(mss);
1907126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1908126258Smlaier	}
1909126258Smlaier
1910126258Smlaier	switch (af) {
1911126258Smlaier#ifdef INET
1912126258Smlaier	case AF_INET:
1913126258Smlaier		/* TCP checksum */
1914126258Smlaier		th->th_sum = in_cksum(m, len);
1915126258Smlaier
1916126258Smlaier		/* Finish the IP header */
1917126258Smlaier		h->ip_v = 4;
1918126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1919126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1920127145Smlaier#ifdef __FreeBSD__
1921181803Sbz		h->ip_off = V_path_mtu_discovery ? IP_DF : 0;
1922130613Smlaier		h->ip_len = len;
1923126261Smlaier#else
1924126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1925130613Smlaier		h->ip_len = htons(len);
1926126261Smlaier#endif
1927181803Sbz		h->ip_ttl = ttl ? ttl : V_ip_defttl;
1928126258Smlaier		h->ip_sum = 0;
1929145836Smlaier		if (eh == NULL) {
1930127145Smlaier#ifdef __FreeBSD__
1931145836Smlaier			PF_UNLOCK();
1932145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1933145836Smlaier			    (void *)NULL, (void *)NULL);
1934145836Smlaier			PF_LOCK();
1935126261Smlaier#else /* ! __FreeBSD__ */
1936145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1937145836Smlaier			    (void *)NULL, (void *)NULL);
1938126261Smlaier#endif
1939145836Smlaier		} else {
1940145836Smlaier			struct route		 ro;
1941145836Smlaier			struct rtentry		 rt;
1942145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1943145836Smlaier
1944145836Smlaier			if (ifp == NULL) {
1945145836Smlaier				m_freem(m);
1946145836Smlaier				return;
1947145836Smlaier			}
1948145836Smlaier			rt.rt_ifp = ifp;
1949145836Smlaier			ro.ro_rt = &rt;
1950145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1951145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1952145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1953145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1954145836Smlaier			e->ether_type = eh->ether_type;
1955145836Smlaier#ifdef __FreeBSD__
1956145836Smlaier			PF_UNLOCK();
1957145836Smlaier			/* XXX_IMPORT: later */
1958145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1959145836Smlaier			    (void *)NULL, (void *)NULL);
1960145836Smlaier			PF_LOCK();
1961145836Smlaier#else /* ! __FreeBSD__ */
1962145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
1963145836Smlaier			    (void *)NULL, (void *)NULL);
1964145836Smlaier#endif
1965145836Smlaier		}
1966126258Smlaier		break;
1967126258Smlaier#endif /* INET */
1968126258Smlaier#ifdef INET6
1969126258Smlaier	case AF_INET6:
1970126258Smlaier		/* TCP checksum */
1971126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1972126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1973126258Smlaier
1974126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1975126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1976126258Smlaier
1977127145Smlaier#ifdef __FreeBSD__
1978126261Smlaier		PF_UNLOCK();
1979126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1980126261Smlaier		PF_LOCK();
1981126261Smlaier#else
1982126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1983126261Smlaier#endif
1984126258Smlaier		break;
1985126258Smlaier#endif /* INET6 */
1986126258Smlaier	}
1987126258Smlaier}
1988126258Smlaier
1989126258Smlaiervoid
1990126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1991126258Smlaier    struct pf_rule *r)
1992126258Smlaier{
1993171168Smlaier	struct pf_mtag	*pf_mtag;
1994126258Smlaier	struct mbuf	*m0;
1995127145Smlaier#ifdef __FreeBSD__
1996126261Smlaier	struct ip *ip;
1997126261Smlaier#endif
1998126258Smlaier
1999132280Smlaier#ifdef __FreeBSD__
2000132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
2001132280Smlaier	if (m0 == NULL)
2002132280Smlaier		return;
2003132280Smlaier#else
2004126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
2005171168Smlaier#endif
2006171168Smlaier	if ((pf_mtag = pf_get_mtag(m0)) == NULL)
2007126258Smlaier		return;
2008171168Smlaier#ifdef __FreeBSD__
2009171168Smlaier	/* XXX: revisit */
2010171168Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
2011171168Smlaier#else
2012171168Smlaier	pf_mtag->flags |= PF_TAG_GENERATED;
2013132280Smlaier#endif
2014126258Smlaier
2015171168Smlaier	if (r->rtableid >= 0)
2016178888Sjulian#ifdef __FreeBSD__
2017178888Sjulian	{
2018178888Sjulian		M_SETFIB(m0, r->rtableid);
2019178888Sjulian#endif
2020171168Smlaier		pf_mtag->rtableid = r->rtableid;
2021178888Sjulian#ifdef __FreeBSD__
2022178888Sjulian	}
2023178888Sjulian#endif
2024171168Smlaier
2025126258Smlaier#ifdef ALTQ
2026126258Smlaier	if (r->qid) {
2027171168Smlaier		pf_mtag->qid = r->qid;
2028171168Smlaier		/* add hints for ecn */
2029171168Smlaier		pf_mtag->af = af;
2030171168Smlaier		pf_mtag->hdr = mtod(m0, struct ip *);
2031126258Smlaier	}
2032145836Smlaier#endif /* ALTQ */
2033126258Smlaier
2034126258Smlaier	switch (af) {
2035126258Smlaier#ifdef INET
2036126258Smlaier	case AF_INET:
2037127145Smlaier#ifdef __FreeBSD__
2038126261Smlaier		/* icmp_error() expects host byte ordering */
2039126261Smlaier		ip = mtod(m0, struct ip *);
2040126261Smlaier		NTOHS(ip->ip_len);
2041126261Smlaier		NTOHS(ip->ip_off);
2042126261Smlaier		PF_UNLOCK();
2043145863Sandre		icmp_error(m0, type, code, 0, 0);
2044126261Smlaier		PF_LOCK();
2045145874Smlaier#else
2046171168Smlaier		icmp_error(m0, type, code, 0, 0);
2047126261Smlaier#endif
2048126258Smlaier		break;
2049126258Smlaier#endif /* INET */
2050126258Smlaier#ifdef INET6
2051126258Smlaier	case AF_INET6:
2052127145Smlaier#ifdef __FreeBSD__
2053126261Smlaier		PF_UNLOCK();
2054126261Smlaier#endif
2055126258Smlaier		icmp6_error(m0, type, code, 0);
2056127145Smlaier#ifdef __FreeBSD__
2057126261Smlaier		PF_LOCK();
2058126261Smlaier#endif
2059126258Smlaier		break;
2060126258Smlaier#endif /* INET6 */
2061126258Smlaier	}
2062126258Smlaier}
2063126258Smlaier
2064126258Smlaier/*
2065126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
2066126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
2067126258Smlaier * are different.
2068126258Smlaier */
2069126258Smlaierint
2070126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
2071126258Smlaier    struct pf_addr *b, sa_family_t af)
2072126258Smlaier{
2073126258Smlaier	int	match = 0;
2074126258Smlaier
2075126258Smlaier	switch (af) {
2076126258Smlaier#ifdef INET
2077126258Smlaier	case AF_INET:
2078126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
2079126258Smlaier		    (b->addr32[0] & m->addr32[0]))
2080126258Smlaier			match++;
2081126258Smlaier		break;
2082126258Smlaier#endif /* INET */
2083126258Smlaier#ifdef INET6
2084126258Smlaier	case AF_INET6:
2085126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
2086126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
2087126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
2088126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
2089126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
2090126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
2091126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
2092126258Smlaier		     (b->addr32[3] & m->addr32[3])))
2093126258Smlaier			match++;
2094126258Smlaier		break;
2095126258Smlaier#endif /* INET6 */
2096126258Smlaier	}
2097126258Smlaier	if (match) {
2098126258Smlaier		if (n)
2099126258Smlaier			return (0);
2100126258Smlaier		else
2101126258Smlaier			return (1);
2102126258Smlaier	} else {
2103126258Smlaier		if (n)
2104126258Smlaier			return (1);
2105126258Smlaier		else
2106126258Smlaier			return (0);
2107126258Smlaier	}
2108126258Smlaier}
2109126258Smlaier
2110126258Smlaierint
2111126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
2112126258Smlaier{
2113126258Smlaier	switch (op) {
2114126258Smlaier	case PF_OP_IRG:
2115126258Smlaier		return ((p > a1) && (p < a2));
2116126258Smlaier	case PF_OP_XRG:
2117126258Smlaier		return ((p < a1) || (p > a2));
2118126258Smlaier	case PF_OP_RRG:
2119126258Smlaier		return ((p >= a1) && (p <= a2));
2120126258Smlaier	case PF_OP_EQ:
2121126258Smlaier		return (p == a1);
2122126258Smlaier	case PF_OP_NE:
2123126258Smlaier		return (p != a1);
2124126258Smlaier	case PF_OP_LT:
2125126258Smlaier		return (p < a1);
2126126258Smlaier	case PF_OP_LE:
2127126258Smlaier		return (p <= a1);
2128126258Smlaier	case PF_OP_GT:
2129126258Smlaier		return (p > a1);
2130126258Smlaier	case PF_OP_GE:
2131126258Smlaier		return (p >= a1);
2132126258Smlaier	}
2133126258Smlaier	return (0); /* never reached */
2134126258Smlaier}
2135126258Smlaier
2136126258Smlaierint
2137126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
2138126258Smlaier{
2139126258Smlaier	NTOHS(a1);
2140126258Smlaier	NTOHS(a2);
2141126258Smlaier	NTOHS(p);
2142126258Smlaier	return (pf_match(op, a1, a2, p));
2143126258Smlaier}
2144126258Smlaier
2145126258Smlaierint
2146126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
2147126258Smlaier{
2148126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2149126258Smlaier		return (0);
2150126258Smlaier	return (pf_match(op, a1, a2, u));
2151126258Smlaier}
2152126258Smlaier
2153126258Smlaierint
2154126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
2155126258Smlaier{
2156126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
2157126258Smlaier		return (0);
2158126258Smlaier	return (pf_match(op, a1, a2, g));
2159126258Smlaier}
2160126258Smlaier
2161171168Smlaier#ifndef __FreeBSD__
2162171168Smlaierstruct pf_mtag *
2163171168Smlaierpf_find_mtag(struct mbuf *m)
2164126258Smlaier{
2165126258Smlaier	struct m_tag	*mtag;
2166126258Smlaier
2167171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL)
2168126258Smlaier		return (NULL);
2169171168Smlaier
2170171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2171126258Smlaier}
2172126258Smlaier
2173171168Smlaierstruct pf_mtag *
2174171168Smlaierpf_get_mtag(struct mbuf *m)
2175126258Smlaier{
2176171168Smlaier	struct m_tag	*mtag;
2177171168Smlaier
2178171168Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) {
2179171168Smlaier		mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag),
2180171168Smlaier		    M_NOWAIT);
2181171168Smlaier		if (mtag == NULL)
2182171168Smlaier			return (NULL);
2183171168Smlaier		bzero(mtag + 1, sizeof(struct pf_mtag));
2184171168Smlaier		m_tag_prepend(m, mtag);
2185126258Smlaier	}
2186126258Smlaier
2187171168Smlaier	return ((struct pf_mtag *)(mtag + 1));
2188171168Smlaier}
2189171168Smlaier#endif
2190171168Smlaier
2191171168Smlaierint
2192171168Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag,
2193171168Smlaier    int *tag)
2194171168Smlaier{
2195171168Smlaier	if (*tag == -1)
2196171168Smlaier		*tag = pf_mtag->tag;
2197171168Smlaier
2198126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
2199126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
2200126258Smlaier}
2201126258Smlaier
2202126258Smlaierint
2203171168Smlaierpf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid)
2204126258Smlaier{
2205171168Smlaier	if (tag <= 0 && rtableid < 0)
2206126258Smlaier		return (0);
2207126258Smlaier
2208171168Smlaier	if (pf_mtag == NULL)
2209171168Smlaier		if ((pf_mtag = pf_get_mtag(m)) == NULL)
2210126258Smlaier			return (1);
2211171168Smlaier	if (tag > 0)
2212171168Smlaier		pf_mtag->tag = tag;
2213171168Smlaier	if (rtableid >= 0)
2214178888Sjulian#ifdef __FreeBSD__
2215178888Sjulian	{
2216178888Sjulian		M_SETFIB(m, rtableid);
2217178888Sjulian#endif
2218171168Smlaier		pf_mtag->rtableid = rtableid;
2219178888Sjulian#ifdef __FreeBSD__
2220178888Sjulian	}
2221178888Sjulian#endif
2222126258Smlaier
2223126258Smlaier	return (0);
2224126258Smlaier}
2225126258Smlaier
2226145836Smlaierstatic void
2227145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
2228171168Smlaier    struct pf_rule **r, struct pf_rule **a,  int *match)
2229145836Smlaier{
2230145836Smlaier	struct pf_anchor_stackframe	*f;
2231126258Smlaier
2232171168Smlaier	(*r)->anchor->match = 0;
2233171168Smlaier	if (match)
2234171168Smlaier		*match = 0;
2235145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
2236145836Smlaier	    sizeof(pf_anchor_stack[0])) {
2237145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
2238145836Smlaier		*r = TAILQ_NEXT(*r, entries);
2239145836Smlaier		return;
2240145836Smlaier	} else if (*depth == 0 && a != NULL)
2241145836Smlaier		*a = *r;
2242145836Smlaier	f = pf_anchor_stack + (*depth)++;
2243145836Smlaier	f->rs = *rs;
2244145836Smlaier	f->r = *r;
2245145836Smlaier	if ((*r)->anchor_wildcard) {
2246145836Smlaier		f->parent = &(*r)->anchor->children;
2247145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2248145836Smlaier		    NULL) {
2249145836Smlaier			*r = NULL;
2250145836Smlaier			return;
2251145836Smlaier		}
2252145836Smlaier		*rs = &f->child->ruleset;
2253145836Smlaier	} else {
2254145836Smlaier		f->parent = NULL;
2255145836Smlaier		f->child = NULL;
2256145836Smlaier		*rs = &(*r)->anchor->ruleset;
2257145836Smlaier	}
2258145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2259145836Smlaier}
2260126258Smlaier
2261171168Smlaierint
2262145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2263171168Smlaier    struct pf_rule **r, struct pf_rule **a, int *match)
2264145836Smlaier{
2265145836Smlaier	struct pf_anchor_stackframe	*f;
2266171168Smlaier	int quick = 0;
2267145836Smlaier
2268145836Smlaier	do {
2269145836Smlaier		if (*depth <= 0)
2270145836Smlaier			break;
2271145836Smlaier		f = pf_anchor_stack + *depth - 1;
2272145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2273171168Smlaier			if (f->child->match ||
2274171168Smlaier			    (match != NULL && *match)) {
2275171168Smlaier				f->r->anchor->match = 1;
2276171168Smlaier				*match = 0;
2277171168Smlaier			}
2278145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2279145836Smlaier			if (f->child != NULL) {
2280145836Smlaier				*rs = &f->child->ruleset;
2281145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2282145836Smlaier				if (*r == NULL)
2283145836Smlaier					continue;
2284145836Smlaier				else
2285145836Smlaier					break;
2286145836Smlaier			}
2287145836Smlaier		}
2288145836Smlaier		(*depth)--;
2289145836Smlaier		if (*depth == 0 && a != NULL)
2290145836Smlaier			*a = NULL;
2291145836Smlaier		*rs = f->rs;
2292171168Smlaier		if (f->r->anchor->match || (match  != NULL && *match))
2293171168Smlaier			quick = f->r->quick;
2294145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2295145836Smlaier	} while (*r == NULL);
2296171168Smlaier
2297171168Smlaier	return (quick);
2298145836Smlaier}
2299145836Smlaier
2300126258Smlaier#ifdef INET6
2301126258Smlaiervoid
2302126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2303126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2304126258Smlaier{
2305126258Smlaier	switch (af) {
2306126258Smlaier#ifdef INET
2307126258Smlaier	case AF_INET:
2308126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2309126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2310126258Smlaier		break;
2311126258Smlaier#endif /* INET */
2312126258Smlaier	case AF_INET6:
2313126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2314126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2315126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2316126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2317126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2318126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2319126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2320126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2321126258Smlaier		break;
2322126258Smlaier	}
2323126258Smlaier}
2324126258Smlaier
2325126258Smlaiervoid
2326130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2327126258Smlaier{
2328126258Smlaier	switch (af) {
2329126258Smlaier#ifdef INET
2330126258Smlaier	case AF_INET:
2331126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2332126258Smlaier		break;
2333126258Smlaier#endif /* INET */
2334126258Smlaier	case AF_INET6:
2335126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2336126258Smlaier			addr->addr32[3] = 0;
2337126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2338126258Smlaier				addr->addr32[2] = 0;
2339126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2340126258Smlaier					addr->addr32[1] = 0;
2341126258Smlaier					addr->addr32[0] =
2342126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2343126258Smlaier				} else
2344126258Smlaier					addr->addr32[1] =
2345126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2346126258Smlaier			} else
2347126258Smlaier				addr->addr32[2] =
2348126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2349126258Smlaier		} else
2350126258Smlaier			addr->addr32[3] =
2351126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2352126258Smlaier		break;
2353126258Smlaier	}
2354126258Smlaier}
2355126258Smlaier#endif /* INET6 */
2356126258Smlaier
2357126258Smlaier#define mix(a,b,c) \
2358126258Smlaier	do {					\
2359126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2360126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2361126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2362126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2363126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2364126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2365126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2366126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2367126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2368126258Smlaier	} while (0)
2369126258Smlaier
2370126258Smlaier/*
2371126258Smlaier * hash function based on bridge_hash in if_bridge.c
2372126258Smlaier */
2373126258Smlaiervoid
2374126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2375126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2376126258Smlaier{
2377126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2378126258Smlaier
2379126258Smlaier	switch (af) {
2380126258Smlaier#ifdef INET
2381126258Smlaier	case AF_INET:
2382126258Smlaier		a += inaddr->addr32[0];
2383126258Smlaier		b += key->key32[1];
2384126258Smlaier		mix(a, b, c);
2385126258Smlaier		hash->addr32[0] = c + key->key32[2];
2386126258Smlaier		break;
2387126258Smlaier#endif /* INET */
2388126258Smlaier#ifdef INET6
2389126258Smlaier	case AF_INET6:
2390126258Smlaier		a += inaddr->addr32[0];
2391126258Smlaier		b += inaddr->addr32[2];
2392126258Smlaier		mix(a, b, c);
2393126258Smlaier		hash->addr32[0] = c;
2394126258Smlaier		a += inaddr->addr32[1];
2395126258Smlaier		b += inaddr->addr32[3];
2396126258Smlaier		c += key->key32[1];
2397126258Smlaier		mix(a, b, c);
2398126258Smlaier		hash->addr32[1] = c;
2399126258Smlaier		a += inaddr->addr32[2];
2400126258Smlaier		b += inaddr->addr32[1];
2401126258Smlaier		c += key->key32[2];
2402126258Smlaier		mix(a, b, c);
2403126258Smlaier		hash->addr32[2] = c;
2404126258Smlaier		a += inaddr->addr32[3];
2405126258Smlaier		b += inaddr->addr32[0];
2406126258Smlaier		c += key->key32[3];
2407126258Smlaier		mix(a, b, c);
2408126258Smlaier		hash->addr32[3] = c;
2409126258Smlaier		break;
2410126258Smlaier#endif /* INET6 */
2411126258Smlaier	}
2412126258Smlaier}
2413126258Smlaier
2414126258Smlaierint
2415130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2416130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2417126258Smlaier{
2418126258Smlaier	unsigned char		 hash[16];
2419130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2420130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2421130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2422126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2423130613Smlaier	struct pf_src_node	 k;
2424126258Smlaier
2425130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2426130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2427130613Smlaier		k.af = af;
2428130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2429130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2430130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2431130613Smlaier			k.rule.ptr = r;
2432130613Smlaier		else
2433130613Smlaier			k.rule.ptr = NULL;
2434130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2435130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2436130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2437130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2438130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2439130613Smlaier				printf("pf_map_addr: src tracking maps ");
2440130613Smlaier				pf_print_host(&k.addr, 0, af);
2441130613Smlaier				printf(" to ");
2442130613Smlaier				pf_print_host(naddr, 0, af);
2443130613Smlaier				printf("\n");
2444130613Smlaier			}
2445130613Smlaier			return (0);
2446130613Smlaier		}
2447130613Smlaier	}
2448130613Smlaier
2449126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2450126258Smlaier		return (1);
2451130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2452145836Smlaier		switch (af) {
2453145836Smlaier#ifdef INET
2454145836Smlaier		case AF_INET:
2455130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2456130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2457130613Smlaier			    PF_POOL_ROUNDROBIN)
2458130613Smlaier				return (1);
2459130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2460130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2461145836Smlaier			break;
2462145836Smlaier#endif /* INET */
2463145836Smlaier#ifdef INET6
2464145836Smlaier		case AF_INET6:
2465130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2466130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2467130613Smlaier			    PF_POOL_ROUNDROBIN)
2468130613Smlaier				return (1);
2469130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2470130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2471145836Smlaier			break;
2472145836Smlaier#endif /* INET6 */
2473130613Smlaier		}
2474130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2475126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2476126258Smlaier			return (1); /* unsupported */
2477126258Smlaier	} else {
2478126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2479126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2480126258Smlaier	}
2481126258Smlaier
2482126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2483126258Smlaier	case PF_POOL_NONE:
2484126258Smlaier		PF_ACPY(naddr, raddr, af);
2485126258Smlaier		break;
2486126258Smlaier	case PF_POOL_BITMASK:
2487126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2488126258Smlaier		break;
2489126258Smlaier	case PF_POOL_RANDOM:
2490126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2491126258Smlaier			switch (af) {
2492126258Smlaier#ifdef INET
2493126258Smlaier			case AF_INET:
2494145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2495126258Smlaier				break;
2496126258Smlaier#endif /* INET */
2497126258Smlaier#ifdef INET6
2498126258Smlaier			case AF_INET6:
2499126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2500145836Smlaier					rpool->counter.addr32[3] =
2501145836Smlaier					    htonl(arc4random());
2502126258Smlaier				else
2503126258Smlaier					break;
2504126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2505145836Smlaier					rpool->counter.addr32[2] =
2506145836Smlaier					    htonl(arc4random());
2507126258Smlaier				else
2508126258Smlaier					break;
2509126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2510145836Smlaier					rpool->counter.addr32[1] =
2511145836Smlaier					    htonl(arc4random());
2512126258Smlaier				else
2513126258Smlaier					break;
2514126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2515145836Smlaier					rpool->counter.addr32[0] =
2516145836Smlaier					    htonl(arc4random());
2517126258Smlaier				break;
2518126258Smlaier#endif /* INET6 */
2519126258Smlaier			}
2520126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2521126258Smlaier			PF_ACPY(init_addr, naddr, af);
2522126258Smlaier
2523126258Smlaier		} else {
2524126258Smlaier			PF_AINC(&rpool->counter, af);
2525126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2526126258Smlaier		}
2527126258Smlaier		break;
2528126258Smlaier	case PF_POOL_SRCHASH:
2529126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2530126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2531126258Smlaier		break;
2532126258Smlaier	case PF_POOL_ROUNDROBIN:
2533126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2534126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2535126258Smlaier			    &rpool->tblidx, &rpool->counter,
2536126258Smlaier			    &raddr, &rmask, af))
2537126258Smlaier				goto get_addr;
2538130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2539130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2540130613Smlaier			    &rpool->tblidx, &rpool->counter,
2541130613Smlaier			    &raddr, &rmask, af))
2542130613Smlaier				goto get_addr;
2543126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2544126258Smlaier			goto get_addr;
2545126258Smlaier
2546126258Smlaier	try_next:
2547126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2548126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2549126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2550126258Smlaier			rpool->tblidx = -1;
2551126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2552126258Smlaier			    &rpool->tblidx, &rpool->counter,
2553126258Smlaier			    &raddr, &rmask, af)) {
2554130613Smlaier				/* table contains no address of type 'af' */
2555126258Smlaier				if (rpool->cur != acur)
2556126258Smlaier					goto try_next;
2557126258Smlaier				return (1);
2558126258Smlaier			}
2559130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2560130613Smlaier			rpool->tblidx = -1;
2561130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2562130613Smlaier			    &rpool->tblidx, &rpool->counter,
2563130613Smlaier			    &raddr, &rmask, af)) {
2564130613Smlaier				/* table contains no address of type 'af' */
2565130613Smlaier				if (rpool->cur != acur)
2566130613Smlaier					goto try_next;
2567130613Smlaier				return (1);
2568130613Smlaier			}
2569126258Smlaier		} else {
2570126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2571126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2572126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2573126258Smlaier		}
2574126258Smlaier
2575126258Smlaier	get_addr:
2576126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2577139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2578139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2579126258Smlaier		PF_AINC(&rpool->counter, af);
2580126258Smlaier		break;
2581126258Smlaier	}
2582130613Smlaier	if (*sn != NULL)
2583130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2584126258Smlaier
2585126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2586126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2587130613Smlaier		printf("pf_map_addr: selected address ");
2588126258Smlaier		pf_print_host(naddr, 0, af);
2589126258Smlaier		printf("\n");
2590126258Smlaier	}
2591126258Smlaier
2592126258Smlaier	return (0);
2593126258Smlaier}
2594126258Smlaier
2595126258Smlaierint
2596130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2597126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2598130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2599130613Smlaier    struct pf_src_node **sn)
2600126258Smlaier{
2601171168Smlaier	struct pf_state_cmp	key;
2602126258Smlaier	struct pf_addr		init_addr;
2603126258Smlaier	u_int16_t		cut;
2604126258Smlaier
2605126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2606130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2607126258Smlaier		return (1);
2608126258Smlaier
2609149884Smlaier	if (proto == IPPROTO_ICMP) {
2610149884Smlaier		low = 1;
2611149884Smlaier		high = 65535;
2612149884Smlaier	}
2613149884Smlaier
2614126258Smlaier	do {
2615126258Smlaier		key.af = af;
2616126258Smlaier		key.proto = proto;
2617130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2618130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2619130613Smlaier		key.ext.port = dport;
2620126258Smlaier
2621126258Smlaier		/*
2622126258Smlaier		 * port search; start random, step;
2623126258Smlaier		 * similar 2 portloop in in_pcbbind
2624126258Smlaier		 */
2625149884Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
2626149884Smlaier		    proto == IPPROTO_ICMP)) {
2627139045Sdhartmei			key.gwy.port = dport;
2628130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2629126258Smlaier				return (0);
2630126258Smlaier		} else if (low == 0 && high == 0) {
2631130613Smlaier			key.gwy.port = *nport;
2632130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2633126258Smlaier				return (0);
2634126258Smlaier		} else if (low == high) {
2635130613Smlaier			key.gwy.port = htons(low);
2636130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2637126258Smlaier				*nport = htons(low);
2638126258Smlaier				return (0);
2639126258Smlaier			}
2640126258Smlaier		} else {
2641126258Smlaier			u_int16_t tmp;
2642126258Smlaier
2643126258Smlaier			if (low > high) {
2644126258Smlaier				tmp = low;
2645126258Smlaier				low = high;
2646126258Smlaier				high = tmp;
2647126258Smlaier			}
2648126258Smlaier			/* low < high */
2649145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2650126258Smlaier			/* low <= cut <= high */
2651126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2652130613Smlaier				key.gwy.port = htons(tmp);
2653130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2654126258Smlaier				    NULL) {
2655126258Smlaier					*nport = htons(tmp);
2656126258Smlaier					return (0);
2657126258Smlaier				}
2658126258Smlaier			}
2659126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2660130613Smlaier				key.gwy.port = htons(tmp);
2661130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2662126258Smlaier				    NULL) {
2663126258Smlaier					*nport = htons(tmp);
2664126258Smlaier					return (0);
2665126258Smlaier				}
2666126258Smlaier			}
2667126258Smlaier		}
2668126258Smlaier
2669130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2670126258Smlaier		case PF_POOL_RANDOM:
2671126258Smlaier		case PF_POOL_ROUNDROBIN:
2672130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2673126258Smlaier				return (1);
2674126258Smlaier			break;
2675126258Smlaier		case PF_POOL_NONE:
2676126258Smlaier		case PF_POOL_SRCHASH:
2677126258Smlaier		case PF_POOL_BITMASK:
2678126258Smlaier		default:
2679126258Smlaier			return (1);
2680126258Smlaier		}
2681126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2682126258Smlaier
2683126258Smlaier	return (1);					/* none available */
2684126258Smlaier}
2685126258Smlaier
2686126258Smlaierstruct pf_rule *
2687126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2688130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2689126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2690126258Smlaier{
2691145836Smlaier	struct pf_rule		*r, *rm = NULL;
2692126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2693145836Smlaier	int			 tag = -1;
2694171168Smlaier	int			 rtableid = -1;
2695145836Smlaier	int			 asd = 0;
2696126258Smlaier
2697126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2698126258Smlaier	while (r && rm == NULL) {
2699126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2700126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2701126258Smlaier
2702126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2703126258Smlaier			src = &r->dst;
2704126258Smlaier			if (r->rpool.cur != NULL)
2705126258Smlaier				xdst = &r->rpool.cur->addr;
2706126258Smlaier		} else {
2707126258Smlaier			src = &r->src;
2708126258Smlaier			dst = &r->dst;
2709126258Smlaier		}
2710126258Smlaier
2711126258Smlaier		r->evaluations++;
2712171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
2713126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2714126258Smlaier		else if (r->direction && r->direction != direction)
2715126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2716126258Smlaier		else if (r->af && r->af != pd->af)
2717126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2718126258Smlaier		else if (r->proto && r->proto != pd->proto)
2719126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2720171168Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
2721171168Smlaier		    src->neg, kif))
2722126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2723126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2724126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2725126258Smlaier		    src->port[0], src->port[1], sport))
2726126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2727126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2728126258Smlaier		else if (dst != NULL &&
2729171168Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
2730126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2731171168Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
2732171168Smlaier		    0, NULL))
2733126258Smlaier			r = TAILQ_NEXT(r, entries);
2734126258Smlaier		else if (dst != NULL && dst->port_op &&
2735126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2736126258Smlaier		    dst->port[1], dport))
2737126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2738171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
2739145836Smlaier			r = TAILQ_NEXT(r, entries);
2740126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2741126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2742126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2743126258Smlaier			r = TAILQ_NEXT(r, entries);
2744145836Smlaier		else {
2745145836Smlaier			if (r->tag)
2746145836Smlaier				tag = r->tag;
2747171168Smlaier			if (r->rtableid >= 0)
2748171168Smlaier				rtableid = r->rtableid;
2749145836Smlaier			if (r->anchor == NULL) {
2750126258Smlaier				rm = r;
2751145836Smlaier			} else
2752171168Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num,
2753171168Smlaier				    &r, NULL, NULL);
2754145836Smlaier		}
2755145836Smlaier		if (r == NULL)
2756171168Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
2757171168Smlaier			    NULL, NULL);
2758126258Smlaier	}
2759171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid))
2760145836Smlaier		return (NULL);
2761126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2762126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2763126258Smlaier		return (NULL);
2764126258Smlaier	return (rm);
2765126258Smlaier}
2766126258Smlaier
2767126258Smlaierstruct pf_rule *
2768126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2769130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2770126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2771126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2772126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2773126258Smlaier{
2774126258Smlaier	struct pf_rule	*r = NULL;
2775126258Smlaier
2776126258Smlaier	if (direction == PF_OUT) {
2777130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2778126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2779126258Smlaier		if (r == NULL)
2780130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2781126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2782126258Smlaier	} else {
2783130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2784126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2785126258Smlaier		if (r == NULL)
2786130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2787126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2788126258Smlaier	}
2789126258Smlaier
2790126258Smlaier	if (r != NULL) {
2791126258Smlaier		switch (r->action) {
2792126258Smlaier		case PF_NONAT:
2793126258Smlaier		case PF_NOBINAT:
2794126258Smlaier		case PF_NORDR:
2795126258Smlaier			return (NULL);
2796126258Smlaier		case PF_NAT:
2797130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2798126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2799130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2800126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2801126258Smlaier				    ("pf: NAT proxy port allocation "
2802126258Smlaier				    "(%u-%u) failed\n",
2803126258Smlaier				    r->rpool.proxy_port[0],
2804126258Smlaier				    r->rpool.proxy_port[1]));
2805126258Smlaier				return (NULL);
2806126258Smlaier			}
2807126258Smlaier			break;
2808126258Smlaier		case PF_BINAT:
2809126258Smlaier			switch (direction) {
2810126258Smlaier			case PF_OUT:
2811130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2812145836Smlaier					switch (pd->af) {
2813145836Smlaier#ifdef INET
2814145836Smlaier					case AF_INET:
2815130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2816130613Smlaier						    pfid_acnt4 < 1)
2817130613Smlaier							return (NULL);
2818130613Smlaier						PF_POOLMASK(naddr,
2819130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2820130613Smlaier						    pfid_addr4,
2821130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2822130613Smlaier						    pfid_mask4,
2823130613Smlaier						    saddr, AF_INET);
2824145836Smlaier						break;
2825145836Smlaier#endif /* INET */
2826145836Smlaier#ifdef INET6
2827145836Smlaier					case AF_INET6:
2828130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2829130613Smlaier						    pfid_acnt6 < 1)
2830130613Smlaier							return (NULL);
2831130613Smlaier						PF_POOLMASK(naddr,
2832130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2833130613Smlaier						    pfid_addr6,
2834130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2835130613Smlaier						    pfid_mask6,
2836130613Smlaier						    saddr, AF_INET6);
2837145836Smlaier						break;
2838145836Smlaier#endif /* INET6 */
2839130613Smlaier					}
2840130613Smlaier				} else
2841126258Smlaier					PF_POOLMASK(naddr,
2842126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2843126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2844126258Smlaier					    saddr, pd->af);
2845126258Smlaier				break;
2846126258Smlaier			case PF_IN:
2847138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2848145836Smlaier					switch (pd->af) {
2849145836Smlaier#ifdef INET
2850145836Smlaier					case AF_INET:
2851130613Smlaier						if (r->src.addr.p.dyn->
2852130613Smlaier						    pfid_acnt4 < 1)
2853130613Smlaier							return (NULL);
2854130613Smlaier						PF_POOLMASK(naddr,
2855130613Smlaier						    &r->src.addr.p.dyn->
2856130613Smlaier						    pfid_addr4,
2857130613Smlaier						    &r->src.addr.p.dyn->
2858130613Smlaier						    pfid_mask4,
2859130613Smlaier						    daddr, AF_INET);
2860145836Smlaier						break;
2861145836Smlaier#endif /* INET */
2862145836Smlaier#ifdef INET6
2863145836Smlaier					case AF_INET6:
2864130613Smlaier						if (r->src.addr.p.dyn->
2865130613Smlaier						    pfid_acnt6 < 1)
2866130613Smlaier							return (NULL);
2867130613Smlaier						PF_POOLMASK(naddr,
2868130613Smlaier						    &r->src.addr.p.dyn->
2869130613Smlaier						    pfid_addr6,
2870130613Smlaier						    &r->src.addr.p.dyn->
2871130613Smlaier						    pfid_mask6,
2872130613Smlaier						    daddr, AF_INET6);
2873145836Smlaier						break;
2874145836Smlaier#endif /* INET6 */
2875130613Smlaier					}
2876130613Smlaier				} else
2877126258Smlaier					PF_POOLMASK(naddr,
2878126258Smlaier					    &r->src.addr.v.a.addr,
2879126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2880126258Smlaier					    pd->af);
2881126258Smlaier				break;
2882126258Smlaier			}
2883126258Smlaier			break;
2884126258Smlaier		case PF_RDR: {
2885140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2886126258Smlaier				return (NULL);
2887149884Smlaier			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
2888149884Smlaier			    PF_POOL_BITMASK)
2889149884Smlaier				PF_POOLMASK(naddr, naddr,
2890149884Smlaier				    &r->rpool.cur->addr.v.a.mask, daddr,
2891149884Smlaier				    pd->af);
2892126258Smlaier
2893126258Smlaier			if (r->rpool.proxy_port[1]) {
2894126258Smlaier				u_int32_t	tmp_nport;
2895126258Smlaier
2896126258Smlaier				tmp_nport = ((ntohs(dport) -
2897126258Smlaier				    ntohs(r->dst.port[0])) %
2898126258Smlaier				    (r->rpool.proxy_port[1] -
2899126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2900126258Smlaier				    r->rpool.proxy_port[0];
2901126258Smlaier
2902126258Smlaier				/* wrap around if necessary */
2903126258Smlaier				if (tmp_nport > 65535)
2904126258Smlaier					tmp_nport -= 65535;
2905126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2906126258Smlaier			} else if (r->rpool.proxy_port[0])
2907126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2908126258Smlaier			break;
2909126258Smlaier		}
2910126258Smlaier		default:
2911126258Smlaier			return (NULL);
2912126258Smlaier		}
2913126258Smlaier	}
2914126258Smlaier
2915126258Smlaier	return (r);
2916126258Smlaier}
2917126258Smlaier
2918126258Smlaierint
2919135920Smlaier#ifdef __FreeBSD__
2920171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg)
2921135920Smlaier#else
2922171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd)
2923135920Smlaier#endif
2924126258Smlaier{
2925126258Smlaier	struct pf_addr		*saddr, *daddr;
2926126258Smlaier	u_int16_t		 sport, dport;
2927127145Smlaier#ifdef __FreeBSD__
2928126261Smlaier	struct inpcbinfo	*pi;
2929126261Smlaier#else
2930126258Smlaier	struct inpcbtable	*tb;
2931126261Smlaier#endif
2932126258Smlaier	struct inpcb		*inp;
2933126258Smlaier
2934171168Smlaier	if (pd == NULL)
2935171168Smlaier		return (-1);
2936171168Smlaier	pd->lookup.uid = UID_MAX;
2937171168Smlaier	pd->lookup.gid = GID_MAX;
2938171168Smlaier	pd->lookup.pid = NO_PID;		/* XXX: revisit */
2939135920Smlaier#ifdef __FreeBSD__
2940135920Smlaier	if (inp_arg != NULL) {
2941178325Srwatson		INP_LOCK_ASSERT(inp_arg);
2942135920Smlaier		if (inp_arg->inp_socket) {
2943171168Smlaier			pd->lookup.uid = inp_arg->inp_socket->so_cred->cr_uid;
2944171168Smlaier			pd->lookup.gid =
2945171168Smlaier			    inp_arg->inp_socket->so_cred->cr_groups[0];
2946135920Smlaier			return (1);
2947135920Smlaier		} else
2948171168Smlaier			return (-1);
2949135920Smlaier	}
2950135920Smlaier#endif
2951130613Smlaier	switch (pd->proto) {
2952126258Smlaier	case IPPROTO_TCP:
2953171168Smlaier		if (pd->hdr.tcp == NULL)
2954171168Smlaier			return (-1);
2955126258Smlaier		sport = pd->hdr.tcp->th_sport;
2956126258Smlaier		dport = pd->hdr.tcp->th_dport;
2957127145Smlaier#ifdef __FreeBSD__
2958181803Sbz		pi = &V_tcbinfo;
2959126261Smlaier#else
2960126258Smlaier		tb = &tcbtable;
2961126261Smlaier#endif
2962126258Smlaier		break;
2963126258Smlaier	case IPPROTO_UDP:
2964171168Smlaier		if (pd->hdr.udp == NULL)
2965171168Smlaier			return (-1);
2966126258Smlaier		sport = pd->hdr.udp->uh_sport;
2967126258Smlaier		dport = pd->hdr.udp->uh_dport;
2968127145Smlaier#ifdef __FreeBSD__
2969181803Sbz		pi = &V_udbinfo;
2970126261Smlaier#else
2971126258Smlaier		tb = &udbtable;
2972126261Smlaier#endif
2973126258Smlaier		break;
2974126258Smlaier	default:
2975171168Smlaier		return (-1);
2976126258Smlaier	}
2977126258Smlaier	if (direction == PF_IN) {
2978126258Smlaier		saddr = pd->src;
2979126258Smlaier		daddr = pd->dst;
2980126258Smlaier	} else {
2981126258Smlaier		u_int16_t	p;
2982126258Smlaier
2983126258Smlaier		p = sport;
2984126258Smlaier		sport = dport;
2985126258Smlaier		dport = p;
2986126258Smlaier		saddr = pd->dst;
2987126258Smlaier		daddr = pd->src;
2988126258Smlaier	}
2989130613Smlaier	switch (pd->af) {
2990145836Smlaier#ifdef INET
2991126258Smlaier	case AF_INET:
2992127145Smlaier#ifdef __FreeBSD__
2993126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2994126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2995126261Smlaier			dport, 0, NULL);
2996126261Smlaier		if (inp == NULL) {
2997126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2998126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2999126261Smlaier			if(inp == NULL) {
3000126261Smlaier				INP_INFO_RUNLOCK(pi);
3001171168Smlaier				return (-1);
3002126261Smlaier			}
3003126261Smlaier		}
3004126261Smlaier#else
3005126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
3006126258Smlaier		if (inp == NULL) {
3007130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
3008126258Smlaier			if (inp == NULL)
3009171168Smlaier				return (-1);
3010126258Smlaier		}
3011126261Smlaier#endif
3012126258Smlaier		break;
3013145836Smlaier#endif /* INET */
3014126258Smlaier#ifdef INET6
3015126258Smlaier	case AF_INET6:
3016127145Smlaier#ifdef __FreeBSD__
3017126261Smlaier		INP_INFO_RLOCK(pi);
3018126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3019126261Smlaier			&daddr->v6, dport, 0, NULL);
3020126261Smlaier		if (inp == NULL) {
3021126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
3022126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
3023126261Smlaier			if (inp == NULL) {
3024126261Smlaier				INP_INFO_RUNLOCK(pi);
3025171168Smlaier				return (-1);
3026126261Smlaier			}
3027126261Smlaier		}
3028126261Smlaier#else
3029126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
3030126258Smlaier		    dport);
3031126258Smlaier		if (inp == NULL) {
3032130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
3033126258Smlaier			if (inp == NULL)
3034171168Smlaier				return (-1);
3035126258Smlaier		}
3036126261Smlaier#endif
3037126258Smlaier		break;
3038126258Smlaier#endif /* INET6 */
3039126258Smlaier
3040126258Smlaier	default:
3041171168Smlaier		return (-1);
3042126258Smlaier	}
3043127145Smlaier#ifdef __FreeBSD__
3044178325Srwatson	INP_RLOCK(inp);
3045178325Srwatson	INP_INFO_RUNLOCK(pi);
3046136925Smlaier	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
3047178325Srwatson		INP_RUNLOCK(inp);
3048171168Smlaier		return (-1);
3049136925Smlaier	}
3050171168Smlaier	pd->lookup.uid = inp->inp_socket->so_cred->cr_uid;
3051171168Smlaier	pd->lookup.gid = inp->inp_socket->so_cred->cr_groups[0];
3052178325Srwatson	INP_RUNLOCK(inp);
3053126261Smlaier#else
3054171168Smlaier	pd->lookup.uid = inp->inp_socket->so_euid;
3055171168Smlaier	pd->lookup.gid = inp->inp_socket->so_egid;
3056171168Smlaier	pd->lookup.pid = inp->inp_socket->so_cpid;
3057126261Smlaier#endif
3058126258Smlaier	return (1);
3059126258Smlaier}
3060126258Smlaier
3061126258Smlaieru_int8_t
3062126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3063126258Smlaier{
3064126258Smlaier	int		 hlen;
3065126258Smlaier	u_int8_t	 hdr[60];
3066126258Smlaier	u_int8_t	*opt, optlen;
3067126258Smlaier	u_int8_t	 wscale = 0;
3068126258Smlaier
3069126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
3070126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3071126258Smlaier		return (0);
3072126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3073126258Smlaier		return (0);
3074126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3075126258Smlaier	hlen -= sizeof(struct tcphdr);
3076126258Smlaier	while (hlen >= 3) {
3077126258Smlaier		switch (*opt) {
3078126258Smlaier		case TCPOPT_EOL:
3079126258Smlaier		case TCPOPT_NOP:
3080126258Smlaier			++opt;
3081126258Smlaier			--hlen;
3082126258Smlaier			break;
3083126258Smlaier		case TCPOPT_WINDOW:
3084126258Smlaier			wscale = opt[2];
3085126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
3086126258Smlaier				wscale = TCP_MAX_WINSHIFT;
3087126258Smlaier			wscale |= PF_WSCALE_FLAG;
3088130613Smlaier			/* FALLTHROUGH */
3089126258Smlaier		default:
3090126258Smlaier			optlen = opt[1];
3091126258Smlaier			if (optlen < 2)
3092126258Smlaier				optlen = 2;
3093126258Smlaier			hlen -= optlen;
3094126258Smlaier			opt += optlen;
3095130613Smlaier			break;
3096126258Smlaier		}
3097126258Smlaier	}
3098126258Smlaier	return (wscale);
3099126258Smlaier}
3100126258Smlaier
3101126258Smlaieru_int16_t
3102126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
3103126258Smlaier{
3104126258Smlaier	int		 hlen;
3105126258Smlaier	u_int8_t	 hdr[60];
3106126258Smlaier	u_int8_t	*opt, optlen;
3107181803Sbz	u_int16_t	 mss = V_tcp_mssdflt;
3108126258Smlaier
3109126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
3110126258Smlaier	if (hlen <= sizeof(struct tcphdr))
3111126258Smlaier		return (0);
3112126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
3113126258Smlaier		return (0);
3114126258Smlaier	opt = hdr + sizeof(struct tcphdr);
3115126258Smlaier	hlen -= sizeof(struct tcphdr);
3116126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
3117126258Smlaier		switch (*opt) {
3118126258Smlaier		case TCPOPT_EOL:
3119126258Smlaier		case TCPOPT_NOP:
3120126258Smlaier			++opt;
3121126258Smlaier			--hlen;
3122126258Smlaier			break;
3123126258Smlaier		case TCPOPT_MAXSEG:
3124126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
3125145030Sglebius			NTOHS(mss);
3126130613Smlaier			/* FALLTHROUGH */
3127126258Smlaier		default:
3128126258Smlaier			optlen = opt[1];
3129126258Smlaier			if (optlen < 2)
3130126258Smlaier				optlen = 2;
3131126258Smlaier			hlen -= optlen;
3132126258Smlaier			opt += optlen;
3133130613Smlaier			break;
3134126258Smlaier		}
3135126258Smlaier	}
3136126258Smlaier	return (mss);
3137126258Smlaier}
3138126258Smlaier
3139126258Smlaieru_int16_t
3140126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
3141126258Smlaier{
3142126258Smlaier#ifdef INET
3143126258Smlaier	struct sockaddr_in	*dst;
3144126258Smlaier	struct route		 ro;
3145126258Smlaier#endif /* INET */
3146126258Smlaier#ifdef INET6
3147126258Smlaier	struct sockaddr_in6	*dst6;
3148126258Smlaier	struct route_in6	 ro6;
3149126258Smlaier#endif /* INET6 */
3150126258Smlaier	struct rtentry		*rt = NULL;
3151127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
3152181803Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3153126258Smlaier
3154126258Smlaier	switch (af) {
3155126258Smlaier#ifdef INET
3156126258Smlaier	case AF_INET:
3157126258Smlaier		hlen = sizeof(struct ip);
3158126258Smlaier		bzero(&ro, sizeof(ro));
3159126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
3160126258Smlaier		dst->sin_family = AF_INET;
3161126258Smlaier		dst->sin_len = sizeof(*dst);
3162126258Smlaier		dst->sin_addr = addr->v4;
3163127145Smlaier#ifdef __FreeBSD__
3164126261Smlaier#ifdef RTF_PRCLONING
3165126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
3166126261Smlaier#else /* !RTF_PRCLONING */
3167178888Sjulian		in_rtalloc_ign(&ro, RTF_CLONING, 0);
3168126261Smlaier#endif
3169126261Smlaier#else /* ! __FreeBSD__ */
3170126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
3171126261Smlaier#endif
3172126258Smlaier		rt = ro.ro_rt;
3173126258Smlaier		break;
3174126258Smlaier#endif /* INET */
3175126258Smlaier#ifdef INET6
3176126258Smlaier	case AF_INET6:
3177126258Smlaier		hlen = sizeof(struct ip6_hdr);
3178126258Smlaier		bzero(&ro6, sizeof(ro6));
3179126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
3180126258Smlaier		dst6->sin6_family = AF_INET6;
3181126258Smlaier		dst6->sin6_len = sizeof(*dst6);
3182126258Smlaier		dst6->sin6_addr = addr->v6;
3183127145Smlaier#ifdef __FreeBSD__
3184126261Smlaier#ifdef RTF_PRCLONING
3185126261Smlaier		rtalloc_ign((struct route *)&ro6,
3186126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
3187126261Smlaier#else /* !RTF_PRCLONING */
3188126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
3189126261Smlaier#endif
3190126261Smlaier#else /* ! __FreeBSD__ */
3191126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
3192126261Smlaier#endif
3193126258Smlaier		rt = ro6.ro_rt;
3194126258Smlaier		break;
3195126258Smlaier#endif /* INET6 */
3196126258Smlaier	}
3197126258Smlaier
3198126258Smlaier	if (rt && rt->rt_ifp) {
3199126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
3200181803Sbz		mss = max(V_tcp_mssdflt, mss);
3201126258Smlaier		RTFREE(rt);
3202126258Smlaier	}
3203126258Smlaier	mss = min(mss, offer);
3204126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
3205126258Smlaier	return (mss);
3206126258Smlaier}
3207126258Smlaier
3208126258Smlaiervoid
3209126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
3210126258Smlaier{
3211126258Smlaier	struct pf_rule *r = s->rule.ptr;
3212126258Smlaier
3213130613Smlaier	s->rt_kif = NULL;
3214126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
3215126258Smlaier		return;
3216126258Smlaier	switch (s->af) {
3217126258Smlaier#ifdef INET
3218126258Smlaier	case AF_INET:
3219130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
3220130613Smlaier		    &s->nat_src_node);
3221130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3222126258Smlaier		break;
3223126258Smlaier#endif /* INET */
3224126258Smlaier#ifdef INET6
3225126258Smlaier	case AF_INET6:
3226130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
3227130613Smlaier		    &s->nat_src_node);
3228130613Smlaier		s->rt_kif = r->rpool.cur->kif;
3229126258Smlaier		break;
3230126258Smlaier#endif /* INET6 */
3231126258Smlaier	}
3232126258Smlaier}
3233126258Smlaier
3234126258Smlaierint
3235126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
3236130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3237135920Smlaier#ifdef __FreeBSD__
3238135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3239145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3240135920Smlaier#else
3241145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3242145836Smlaier    struct ifqueue *ifq)
3243135920Smlaier#endif
3244126258Smlaier{
3245130613Smlaier	struct pf_rule		*nr = NULL;
3246126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3247126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3248126258Smlaier	u_int16_t		 bport, nport = 0;
3249126258Smlaier	sa_family_t		 af = pd->af;
3250126258Smlaier	struct pf_rule		*r, *a = NULL;
3251126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3252130613Smlaier	struct pf_src_node	*nsn = NULL;
3253126258Smlaier	u_short			 reason;
3254126258Smlaier	int			 rewrite = 0;
3255171168Smlaier	int			 tag = -1, rtableid = -1;
3256181803Sbz	u_int16_t		 mss = V_tcp_mssdflt;
3257145836Smlaier	int			 asd = 0;
3258171168Smlaier	int			 match = 0;
3259126258Smlaier
3260145836Smlaier	if (pf_check_congestion(ifq)) {
3261145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3262145836Smlaier		return (PF_DROP);
3263145836Smlaier	}
3264145836Smlaier
3265171168Smlaier#ifdef __FreeBSD__
3266171168Smlaier	if (inp != NULL)
3267171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3268171168Smlaier	else if (debug_pfugidhack) {
3269171168Smlaier		PF_UNLOCK();
3270171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3271171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3272171168Smlaier		PF_LOCK();
3273171168Smlaier	}
3274165631Smlaier#endif
3275165631Smlaier
3276126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3277126258Smlaier
3278126258Smlaier	if (direction == PF_OUT) {
3279126258Smlaier		bport = nport = th->th_sport;
3280126258Smlaier		/* check outgoing packet for BINAT/NAT */
3281130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3282126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3283130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3284130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3285126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3286130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3287126258Smlaier			rewrite++;
3288130613Smlaier			if (nr->natpass)
3289126258Smlaier				r = NULL;
3290130613Smlaier			pd->nat_rule = nr;
3291126258Smlaier		}
3292126258Smlaier	} else {
3293126258Smlaier		bport = nport = th->th_dport;
3294126258Smlaier		/* check incoming packet for BINAT/RDR */
3295130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3296130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3297130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3298130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3299126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3300130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3301126258Smlaier			rewrite++;
3302130613Smlaier			if (nr->natpass)
3303126258Smlaier				r = NULL;
3304130613Smlaier			pd->nat_rule = nr;
3305126258Smlaier		}
3306126258Smlaier	}
3307126258Smlaier
3308126258Smlaier	while (r != NULL) {
3309126258Smlaier		r->evaluations++;
3310171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3311126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3312126258Smlaier		else if (r->direction && r->direction != direction)
3313126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3314126258Smlaier		else if (r->af && r->af != af)
3315126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3316126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3317126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3318171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3319171168Smlaier		    r->src.neg, kif))
3320126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3321126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3322126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3323126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3324171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3325171168Smlaier		    r->dst.neg, NULL))
3326126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3327126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3328126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3329126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3330171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3331126258Smlaier			r = TAILQ_NEXT(r, entries);
3332126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3333126258Smlaier			r = TAILQ_NEXT(r, entries);
3334126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3335126258Smlaier			r = TAILQ_NEXT(r, entries);
3336171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3337135920Smlaier#ifdef __FreeBSD__
3338171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3339135920Smlaier#else
3340171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3341135920Smlaier#endif
3342126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3343171168Smlaier		    pd->lookup.uid))
3344126258Smlaier			r = TAILQ_NEXT(r, entries);
3345171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3346135920Smlaier#ifdef __FreeBSD__
3347171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3348135920Smlaier#else
3349171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3350135920Smlaier#endif
3351126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3352171168Smlaier		    pd->lookup.gid))
3353126258Smlaier			r = TAILQ_NEXT(r, entries);
3354145836Smlaier		else if (r->prob && r->prob <= arc4random())
3355126258Smlaier			r = TAILQ_NEXT(r, entries);
3356171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3357126258Smlaier			r = TAILQ_NEXT(r, entries);
3358126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3359126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3360126258Smlaier			r = TAILQ_NEXT(r, entries);
3361126258Smlaier		else {
3362126258Smlaier			if (r->tag)
3363126258Smlaier				tag = r->tag;
3364171168Smlaier			if (r->rtableid >= 0)
3365171168Smlaier				rtableid = r->rtableid;
3366126258Smlaier			if (r->anchor == NULL) {
3367171168Smlaier				match = 1;
3368126258Smlaier				*rm = r;
3369126258Smlaier				*am = a;
3370126258Smlaier				*rsm = ruleset;
3371126258Smlaier				if ((*rm)->quick)
3372126258Smlaier					break;
3373126258Smlaier				r = TAILQ_NEXT(r, entries);
3374126258Smlaier			} else
3375145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3376171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3377126258Smlaier		}
3378171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3379171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3380171168Smlaier			break;
3381126258Smlaier	}
3382126258Smlaier	r = *rm;
3383126258Smlaier	a = *am;
3384126258Smlaier	ruleset = *rsm;
3385126258Smlaier
3386126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3387126258Smlaier
3388171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3389126258Smlaier		if (rewrite)
3390171168Smlaier#ifdef __FreeBSD__
3391126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3392171168Smlaier#else
3393171168Smlaier			m_copyback(m, off, sizeof(*th), th);
3394171168Smlaier#endif
3395171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3396171168Smlaier		    a, ruleset, pd);
3397126258Smlaier	}
3398126258Smlaier
3399126258Smlaier	if ((r->action == PF_DROP) &&
3400126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3401126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3402126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3403126258Smlaier		/* undo NAT changes, if they have taken place */
3404130613Smlaier		if (nr != NULL) {
3405130613Smlaier			if (direction == PF_OUT) {
3406130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3407130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3408130613Smlaier				rewrite++;
3409130613Smlaier			} else {
3410130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3411130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3412130613Smlaier				rewrite++;
3413130613Smlaier			}
3414126258Smlaier		}
3415126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3416126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3417126258Smlaier		    !(th->th_flags & TH_RST)) {
3418126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3419126258Smlaier
3420126258Smlaier			if (th->th_flags & TH_SYN)
3421126258Smlaier				ack++;
3422126258Smlaier			if (th->th_flags & TH_FIN)
3423126258Smlaier				ack++;
3424162238Scsjp#ifdef __FreeBSD__
3425162238Scsjp			pf_send_tcp(m, r, af, pd->dst,
3426162238Scsjp#else
3427126258Smlaier			pf_send_tcp(r, af, pd->dst,
3428162238Scsjp#endif
3429126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3430126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3431171168Smlaier			    r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
3432126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3433126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3434126258Smlaier			    r->return_icmp & 255, af, r);
3435126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3436126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3437126258Smlaier			    r->return_icmp6 & 255, af, r);
3438126258Smlaier	}
3439126258Smlaier
3440126258Smlaier	if (r->action == PF_DROP)
3441126258Smlaier		return (PF_DROP);
3442126258Smlaier
3443171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3444126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3445126258Smlaier		return (PF_DROP);
3446126258Smlaier	}
3447126258Smlaier
3448130613Smlaier	if (r->keep_state || nr != NULL ||
3449126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3450126258Smlaier		/* create new state */
3451126258Smlaier		u_int16_t	 len;
3452126258Smlaier		struct pf_state	*s = NULL;
3453130613Smlaier		struct pf_src_node *sn = NULL;
3454126258Smlaier
3455126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3456130613Smlaier
3457130613Smlaier		/* check maximums */
3458145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3459145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3460145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3461130613Smlaier			goto cleanup;
3462145836Smlaier		}
3463171168Smlaier		/* src node for filter rule */
3464130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3465130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3466145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3467145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3468130613Smlaier			goto cleanup;
3469145836Smlaier		}
3470130613Smlaier		/* src node for translation rule */
3471130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3472130613Smlaier		    ((direction == PF_OUT &&
3473130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3474145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3475145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3476130613Smlaier			goto cleanup;
3477145836Smlaier		}
3478130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3479126258Smlaier		if (s == NULL) {
3480145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3481130613Smlaiercleanup:
3482130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3483130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3484130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3485130613Smlaier				pf_status.src_nodes--;
3486130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3487130613Smlaier			}
3488130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3489130613Smlaier			    nsn->expire == 0) {
3490130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3491130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3492130613Smlaier				pf_status.src_nodes--;
3493130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3494130613Smlaier			}
3495126258Smlaier			return (PF_DROP);
3496126258Smlaier		}
3497126258Smlaier		bzero(s, sizeof(*s));
3498126258Smlaier		s->rule.ptr = r;
3499130613Smlaier		s->nat_rule.ptr = nr;
3500126258Smlaier		s->anchor.ptr = a;
3501145836Smlaier		STATE_INC_COUNTERS(s);
3502126258Smlaier		s->allow_opts = r->allow_opts;
3503171168Smlaier		s->log = r->log & PF_LOG_ALL;
3504171168Smlaier		if (nr != NULL)
3505171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3506126258Smlaier		s->proto = IPPROTO_TCP;
3507126258Smlaier		s->direction = direction;
3508126258Smlaier		s->af = af;
3509126258Smlaier		if (direction == PF_OUT) {
3510126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3511126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3512126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3513126258Smlaier			s->ext.port = th->th_dport;
3514130613Smlaier			if (nr != NULL) {
3515130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3516126258Smlaier				s->lan.port = bport;
3517126258Smlaier			} else {
3518126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3519126258Smlaier				s->lan.port = s->gwy.port;
3520126258Smlaier			}
3521126258Smlaier		} else {
3522126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3523126258Smlaier			s->lan.port = th->th_dport;
3524126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3525126258Smlaier			s->ext.port = th->th_sport;
3526130613Smlaier			if (nr != NULL) {
3527130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3528126258Smlaier				s->gwy.port = bport;
3529126258Smlaier			} else {
3530126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3531126258Smlaier				s->gwy.port = s->lan.port;
3532126258Smlaier			}
3533126258Smlaier		}
3534126258Smlaier
3535126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3536126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3537126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3538126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3539126258Smlaier			/* Generate sequence number modulator */
3540171168Smlaier#ifdef __FreeBSD__
3541171168Smlaier			while ((s->src.seqdiff =
3542171168Smlaier			    pf_new_isn(s) - s->src.seqlo) == 0)
3543171168Smlaier				;
3544171168Smlaier#else
3545171168Smlaier			while ((s->src.seqdiff =
3546171168Smlaier			    tcp_rndiss_next() - s->src.seqlo) == 0)
3547126258Smlaier				;
3548171168Smlaier#endif
3549126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3550126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3551126258Smlaier			rewrite = 1;
3552126258Smlaier		} else
3553126258Smlaier			s->src.seqdiff = 0;
3554126258Smlaier		if (th->th_flags & TH_SYN) {
3555126258Smlaier			s->src.seqhi++;
3556126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3557126258Smlaier		}
3558126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3559126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3560126258Smlaier			/* Remove scale factor from initial window */
3561126258Smlaier			int win = s->src.max_win;
3562126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3563126258Smlaier			s->src.max_win = (win - 1) >>
3564126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3565126258Smlaier		}
3566126258Smlaier		if (th->th_flags & TH_FIN)
3567126258Smlaier			s->src.seqhi++;
3568126258Smlaier		s->dst.seqhi = 1;
3569126258Smlaier		s->dst.max_win = 1;
3570126258Smlaier		s->src.state = TCPS_SYN_SENT;
3571126258Smlaier		s->dst.state = TCPS_CLOSED;
3572126261Smlaier		s->creation = time_second;
3573126261Smlaier		s->expire = time_second;
3574126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3575126258Smlaier		pf_set_rt_ifp(s, saddr);
3576130613Smlaier		if (sn != NULL) {
3577130613Smlaier			s->src_node = sn;
3578130613Smlaier			s->src_node->states++;
3579130613Smlaier		}
3580130613Smlaier		if (nsn != NULL) {
3581130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3582130613Smlaier			s->nat_src_node = nsn;
3583130613Smlaier			s->nat_src_node->states++;
3584130613Smlaier		}
3585126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3586126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3587126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3588130613Smlaier			pf_src_tree_remove_state(s);
3589145836Smlaier			STATE_DEC_COUNTERS(s);
3590126258Smlaier			pool_put(&pf_state_pl, s);
3591126258Smlaier			return (PF_DROP);
3592126258Smlaier		}
3593126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3594145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3595145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3596145836Smlaier			/* This really shouldn't happen!!! */
3597145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3598145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3599126258Smlaier			pf_normalize_tcp_cleanup(s);
3600130613Smlaier			pf_src_tree_remove_state(s);
3601145836Smlaier			STATE_DEC_COUNTERS(s);
3602126258Smlaier			pool_put(&pf_state_pl, s);
3603126258Smlaier			return (PF_DROP);
3604126258Smlaier		}
3605130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3606126258Smlaier			pf_normalize_tcp_cleanup(s);
3607145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3608130613Smlaier			pf_src_tree_remove_state(s);
3609145836Smlaier			STATE_DEC_COUNTERS(s);
3610126258Smlaier			pool_put(&pf_state_pl, s);
3611126258Smlaier			return (PF_DROP);
3612126258Smlaier		} else
3613126258Smlaier			*sm = s;
3614145836Smlaier		if (tag > 0) {
3615145836Smlaier			pf_tag_ref(tag);
3616145836Smlaier			s->tag = tag;
3617145836Smlaier		}
3618126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3619126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3620126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3621130613Smlaier			if (nr != NULL) {
3622130613Smlaier				if (direction == PF_OUT) {
3623130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3624130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3625130613Smlaier					    bport, 0, af);
3626130613Smlaier				} else {
3627130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3628130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3629130613Smlaier					    bport, 0, af);
3630130613Smlaier				}
3631130613Smlaier			}
3632145836Smlaier			s->src.seqhi = htonl(arc4random());
3633126258Smlaier			/* Find mss option */
3634126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3635126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3636126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3637126258Smlaier			s->src.mss = mss;
3638162238Scsjp#ifdef __FreeBSD__
3639162238Scsjp			pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
3640162238Scsjp#else
3641126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3642162238Scsjp#endif
3643130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3644171168Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
3645145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3646126258Smlaier			return (PF_SYNPROXY_DROP);
3647126258Smlaier		}
3648126258Smlaier	}
3649126258Smlaier
3650126258Smlaier	/* copy back packet headers if we performed NAT operations */
3651126258Smlaier	if (rewrite)
3652126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3653126258Smlaier
3654126258Smlaier	return (PF_PASS);
3655126258Smlaier}
3656126258Smlaier
3657126258Smlaierint
3658126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3659130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3660135920Smlaier#ifdef __FreeBSD__
3661135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3662145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3663135920Smlaier#else
3664145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3665145836Smlaier    struct ifqueue *ifq)
3666135920Smlaier#endif
3667126258Smlaier{
3668130613Smlaier	struct pf_rule		*nr = NULL;
3669126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3670126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3671126258Smlaier	u_int16_t		 bport, nport = 0;
3672126258Smlaier	sa_family_t		 af = pd->af;
3673126258Smlaier	struct pf_rule		*r, *a = NULL;
3674126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3675130613Smlaier	struct pf_src_node	*nsn = NULL;
3676126258Smlaier	u_short			 reason;
3677126258Smlaier	int			 rewrite = 0;
3678171168Smlaier	int			 tag = -1, rtableid = -1;
3679145836Smlaier	int			 asd = 0;
3680171168Smlaier	int			 match = 0;
3681126258Smlaier
3682145836Smlaier	if (pf_check_congestion(ifq)) {
3683145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3684145836Smlaier		return (PF_DROP);
3685145836Smlaier	}
3686145836Smlaier
3687171168Smlaier#ifdef __FreeBSD__
3688171168Smlaier	if (inp != NULL)
3689171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3690171168Smlaier	else if (debug_pfugidhack) {
3691171168Smlaier		PF_UNLOCK();
3692171168Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n"));
3693171168Smlaier		pd->lookup.done = pf_socket_lookup(direction, pd, inp);
3694171168Smlaier		PF_LOCK();
3695171168Smlaier	}
3696165631Smlaier#endif
3697165631Smlaier
3698126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3699126258Smlaier
3700126258Smlaier	if (direction == PF_OUT) {
3701126258Smlaier		bport = nport = uh->uh_sport;
3702126258Smlaier		/* check outgoing packet for BINAT/NAT */
3703130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3704126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3705130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3706130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3707126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3708130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3709126258Smlaier			rewrite++;
3710130613Smlaier			if (nr->natpass)
3711126258Smlaier				r = NULL;
3712130613Smlaier			pd->nat_rule = nr;
3713126258Smlaier		}
3714126258Smlaier	} else {
3715126258Smlaier		bport = nport = uh->uh_dport;
3716126258Smlaier		/* check incoming packet for BINAT/RDR */
3717130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3718130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3719130613Smlaier		    &nport)) != NULL) {
3720130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3721126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3722130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3723126258Smlaier			rewrite++;
3724130613Smlaier			if (nr->natpass)
3725126258Smlaier				r = NULL;
3726130613Smlaier			pd->nat_rule = nr;
3727126258Smlaier		}
3728126258Smlaier	}
3729126258Smlaier
3730126258Smlaier	while (r != NULL) {
3731126258Smlaier		r->evaluations++;
3732171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
3733126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3734126258Smlaier		else if (r->direction && r->direction != direction)
3735126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3736126258Smlaier		else if (r->af && r->af != af)
3737126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3738126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3739126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3740171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
3741171168Smlaier		    r->src.neg, kif))
3742126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3743126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3744126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3745126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3746171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
3747171168Smlaier		    r->dst.neg, NULL))
3748126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3749126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3750126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3751126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3752171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
3753126258Smlaier			r = TAILQ_NEXT(r, entries);
3754126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3755126258Smlaier			r = TAILQ_NEXT(r, entries);
3756171168Smlaier		else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
3757135920Smlaier#ifdef __FreeBSD__
3758171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3759135920Smlaier#else
3760171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3761135920Smlaier#endif
3762126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3763171168Smlaier		    pd->lookup.uid))
3764126258Smlaier			r = TAILQ_NEXT(r, entries);
3765171168Smlaier		else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
3766135920Smlaier#ifdef __FreeBSD__
3767171168Smlaier		    pf_socket_lookup(direction, pd, inp), 1)) &&
3768135920Smlaier#else
3769171168Smlaier		    pf_socket_lookup(direction, pd), 1)) &&
3770135920Smlaier#endif
3771126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3772171168Smlaier		    pd->lookup.gid))
3773126258Smlaier			r = TAILQ_NEXT(r, entries);
3774145836Smlaier		else if (r->prob && r->prob <= arc4random())
3775126258Smlaier			r = TAILQ_NEXT(r, entries);
3776171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
3777126258Smlaier			r = TAILQ_NEXT(r, entries);
3778126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3779126258Smlaier			r = TAILQ_NEXT(r, entries);
3780126258Smlaier		else {
3781126258Smlaier			if (r->tag)
3782126258Smlaier				tag = r->tag;
3783171168Smlaier			if (r->rtableid >= 0)
3784171168Smlaier				rtableid = r->rtableid;
3785126258Smlaier			if (r->anchor == NULL) {
3786171168Smlaier				match = 1;
3787126258Smlaier				*rm = r;
3788126258Smlaier				*am = a;
3789126258Smlaier				*rsm = ruleset;
3790126258Smlaier				if ((*rm)->quick)
3791126258Smlaier					break;
3792126258Smlaier				r = TAILQ_NEXT(r, entries);
3793126258Smlaier			} else
3794145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3795171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
3796126258Smlaier		}
3797171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
3798171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
3799171168Smlaier			break;
3800126258Smlaier	}
3801126258Smlaier	r = *rm;
3802126258Smlaier	a = *am;
3803126258Smlaier	ruleset = *rsm;
3804126258Smlaier
3805126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3806126258Smlaier
3807171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
3808126258Smlaier		if (rewrite)
3809171168Smlaier#ifdef __FreeBSD__
3810126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3811171168Smlaier#else
3812171168Smlaier			m_copyback(m, off, sizeof(*uh), uh);
3813171168Smlaier#endif
3814171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
3815171168Smlaier		    a, ruleset, pd);
3816126258Smlaier	}
3817126258Smlaier
3818126258Smlaier	if ((r->action == PF_DROP) &&
3819126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3820126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3821126258Smlaier		/* undo NAT changes, if they have taken place */
3822130613Smlaier		if (nr != NULL) {
3823130613Smlaier			if (direction == PF_OUT) {
3824130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3825130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3826130613Smlaier				rewrite++;
3827130613Smlaier			} else {
3828130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3829130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3830130613Smlaier				rewrite++;
3831130613Smlaier			}
3832126258Smlaier		}
3833126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3834126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3835126258Smlaier			    r->return_icmp & 255, af, r);
3836126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3837126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3838126258Smlaier			    r->return_icmp6 & 255, af, r);
3839126258Smlaier	}
3840126258Smlaier
3841126258Smlaier	if (r->action == PF_DROP)
3842126258Smlaier		return (PF_DROP);
3843126258Smlaier
3844171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
3845126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3846126258Smlaier		return (PF_DROP);
3847126258Smlaier	}
3848126258Smlaier
3849130613Smlaier	if (r->keep_state || nr != NULL) {
3850126258Smlaier		/* create new state */
3851126258Smlaier		struct pf_state	*s = NULL;
3852130613Smlaier		struct pf_src_node *sn = NULL;
3853126258Smlaier
3854130613Smlaier		/* check maximums */
3855145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3856145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3857145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3858130613Smlaier			goto cleanup;
3859145836Smlaier		}
3860171168Smlaier		/* src node for filter rule */
3861130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3862130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3863145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3864145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3865130613Smlaier			goto cleanup;
3866145836Smlaier		}
3867130613Smlaier		/* src node for translation rule */
3868130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3869130613Smlaier		    ((direction == PF_OUT &&
3870130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3871145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3872145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3873130613Smlaier			goto cleanup;
3874145836Smlaier		}
3875130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3876126258Smlaier		if (s == NULL) {
3877145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3878130613Smlaiercleanup:
3879130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3880130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3881130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3882130613Smlaier				pf_status.src_nodes--;
3883130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3884130613Smlaier			}
3885130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3886130613Smlaier			    nsn->expire == 0) {
3887130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3888130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3889130613Smlaier				pf_status.src_nodes--;
3890130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3891130613Smlaier			}
3892126258Smlaier			return (PF_DROP);
3893126258Smlaier		}
3894126258Smlaier		bzero(s, sizeof(*s));
3895126258Smlaier		s->rule.ptr = r;
3896130613Smlaier		s->nat_rule.ptr = nr;
3897126258Smlaier		s->anchor.ptr = a;
3898145836Smlaier		STATE_INC_COUNTERS(s);
3899126258Smlaier		s->allow_opts = r->allow_opts;
3900171168Smlaier		s->log = r->log & PF_LOG_ALL;
3901171168Smlaier		if (nr != NULL)
3902171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
3903126258Smlaier		s->proto = IPPROTO_UDP;
3904126258Smlaier		s->direction = direction;
3905126258Smlaier		s->af = af;
3906126258Smlaier		if (direction == PF_OUT) {
3907126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3908126258Smlaier			s->gwy.port = uh->uh_sport;
3909126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3910126258Smlaier			s->ext.port = uh->uh_dport;
3911130613Smlaier			if (nr != NULL) {
3912130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3913126258Smlaier				s->lan.port = bport;
3914126258Smlaier			} else {
3915126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3916126258Smlaier				s->lan.port = s->gwy.port;
3917126258Smlaier			}
3918126258Smlaier		} else {
3919126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3920126258Smlaier			s->lan.port = uh->uh_dport;
3921126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3922126258Smlaier			s->ext.port = uh->uh_sport;
3923130613Smlaier			if (nr != NULL) {
3924130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3925126258Smlaier				s->gwy.port = bport;
3926126258Smlaier			} else {
3927126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3928126258Smlaier				s->gwy.port = s->lan.port;
3929126258Smlaier			}
3930126258Smlaier		}
3931126258Smlaier		s->src.state = PFUDPS_SINGLE;
3932126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3933126261Smlaier		s->creation = time_second;
3934126261Smlaier		s->expire = time_second;
3935126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3936126258Smlaier		pf_set_rt_ifp(s, saddr);
3937130613Smlaier		if (sn != NULL) {
3938130613Smlaier			s->src_node = sn;
3939130613Smlaier			s->src_node->states++;
3940130613Smlaier		}
3941130613Smlaier		if (nsn != NULL) {
3942130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3943130613Smlaier			s->nat_src_node = nsn;
3944130613Smlaier			s->nat_src_node->states++;
3945130613Smlaier		}
3946130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3947145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3948130613Smlaier			pf_src_tree_remove_state(s);
3949145836Smlaier			STATE_DEC_COUNTERS(s);
3950126258Smlaier			pool_put(&pf_state_pl, s);
3951126258Smlaier			return (PF_DROP);
3952126258Smlaier		} else
3953126258Smlaier			*sm = s;
3954145836Smlaier		if (tag > 0) {
3955145836Smlaier			pf_tag_ref(tag);
3956145836Smlaier			s->tag = tag;
3957145836Smlaier		}
3958126258Smlaier	}
3959126258Smlaier
3960126258Smlaier	/* copy back packet headers if we performed NAT operations */
3961126258Smlaier	if (rewrite)
3962126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3963126258Smlaier
3964126258Smlaier	return (PF_PASS);
3965126258Smlaier}
3966126258Smlaier
3967126258Smlaierint
3968126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3969130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3970145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3971145836Smlaier    struct ifqueue *ifq)
3972126258Smlaier{
3973130613Smlaier	struct pf_rule		*nr = NULL;
3974126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3975126258Smlaier	struct pf_rule		*r, *a = NULL;
3976126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3977130613Smlaier	struct pf_src_node	*nsn = NULL;
3978126258Smlaier	u_short			 reason;
3979149893Smlaier	u_int16_t		 icmpid = 0, bport, nport = 0;
3980126258Smlaier	sa_family_t		 af = pd->af;
3981127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3982127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3983126258Smlaier	int			 state_icmp = 0;
3984171168Smlaier	int			 tag = -1, rtableid = -1;
3985126258Smlaier#ifdef INET6
3986126258Smlaier	int			 rewrite = 0;
3987126258Smlaier#endif /* INET6 */
3988145836Smlaier	int			 asd = 0;
3989171168Smlaier	int			 match = 0;
3990126258Smlaier
3991145836Smlaier	if (pf_check_congestion(ifq)) {
3992145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3993145836Smlaier		return (PF_DROP);
3994145836Smlaier	}
3995145836Smlaier
3996126258Smlaier	switch (pd->proto) {
3997126258Smlaier#ifdef INET
3998126258Smlaier	case IPPROTO_ICMP:
3999126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4000126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
4001126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4002126258Smlaier
4003126258Smlaier		if (icmptype == ICMP_UNREACH ||
4004126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4005126258Smlaier		    icmptype == ICMP_REDIRECT ||
4006126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4007126258Smlaier		    icmptype == ICMP_PARAMPROB)
4008126258Smlaier			state_icmp++;
4009126258Smlaier		break;
4010126258Smlaier#endif /* INET */
4011126258Smlaier#ifdef INET6
4012126258Smlaier	case IPPROTO_ICMPV6:
4013126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4014126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
4015126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4016126258Smlaier
4017126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4018126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4019126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4020126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4021126258Smlaier			state_icmp++;
4022126258Smlaier		break;
4023126258Smlaier#endif /* INET6 */
4024126258Smlaier	}
4025126258Smlaier
4026126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4027126258Smlaier
4028126258Smlaier	if (direction == PF_OUT) {
4029149884Smlaier		bport = nport = icmpid;
4030126258Smlaier		/* check outgoing packet for BINAT/NAT */
4031130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4032149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4033149884Smlaier		    NULL) {
4034130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4035126258Smlaier			switch (af) {
4036126258Smlaier#ifdef INET
4037126258Smlaier			case AF_INET:
4038126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4039130613Smlaier				    pd->naddr.v4.s_addr, 0);
4040149884Smlaier				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
4041149884Smlaier				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
4042149884Smlaier				pd->hdr.icmp->icmp_id = nport;
4043149893Smlaier				m_copyback(m, off, ICMP_MINLEN,
4044149893Smlaier				    (caddr_t)pd->hdr.icmp);
4045126258Smlaier				break;
4046126258Smlaier#endif /* INET */
4047126258Smlaier#ifdef INET6
4048126258Smlaier			case AF_INET6:
4049126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
4050130613Smlaier				    &pd->naddr, 0);
4051126258Smlaier				rewrite++;
4052126258Smlaier				break;
4053126258Smlaier#endif /* INET6 */
4054126258Smlaier			}
4055130613Smlaier			if (nr->natpass)
4056126258Smlaier				r = NULL;
4057130613Smlaier			pd->nat_rule = nr;
4058126258Smlaier		}
4059126258Smlaier	} else {
4060149884Smlaier		bport = nport = icmpid;
4061126258Smlaier		/* check incoming packet for BINAT/RDR */
4062130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4063149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
4064149884Smlaier		    NULL) {
4065130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4066126258Smlaier			switch (af) {
4067126258Smlaier#ifdef INET
4068126258Smlaier			case AF_INET:
4069126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4070130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4071126258Smlaier				break;
4072126258Smlaier#endif /* INET */
4073126258Smlaier#ifdef INET6
4074126258Smlaier			case AF_INET6:
4075126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
4076130613Smlaier				    &pd->naddr, 0);
4077126258Smlaier				rewrite++;
4078126258Smlaier				break;
4079126258Smlaier#endif /* INET6 */
4080126258Smlaier			}
4081130613Smlaier			if (nr->natpass)
4082126258Smlaier				r = NULL;
4083130613Smlaier			pd->nat_rule = nr;
4084126258Smlaier		}
4085126258Smlaier	}
4086126258Smlaier
4087126258Smlaier	while (r != NULL) {
4088126258Smlaier		r->evaluations++;
4089171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4090126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4091126258Smlaier		else if (r->direction && r->direction != direction)
4092126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4093126258Smlaier		else if (r->af && r->af != af)
4094126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4095126258Smlaier		else if (r->proto && r->proto != pd->proto)
4096126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4097171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
4098171168Smlaier		    r->src.neg, kif))
4099126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4100171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
4101171168Smlaier		    r->dst.neg, NULL))
4102126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4103126258Smlaier		else if (r->type && r->type != icmptype + 1)
4104126258Smlaier			r = TAILQ_NEXT(r, entries);
4105126258Smlaier		else if (r->code && r->code != icmpcode + 1)
4106126258Smlaier			r = TAILQ_NEXT(r, entries);
4107171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4108126258Smlaier			r = TAILQ_NEXT(r, entries);
4109126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4110126258Smlaier			r = TAILQ_NEXT(r, entries);
4111145836Smlaier		else if (r->prob && r->prob <= arc4random())
4112126258Smlaier			r = TAILQ_NEXT(r, entries);
4113171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4114126258Smlaier			r = TAILQ_NEXT(r, entries);
4115126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4116126258Smlaier			r = TAILQ_NEXT(r, entries);
4117126258Smlaier		else {
4118126258Smlaier			if (r->tag)
4119126258Smlaier				tag = r->tag;
4120171168Smlaier			if (r->rtableid >= 0)
4121171168Smlaier				rtableid = r->rtableid;
4122126258Smlaier			if (r->anchor == NULL) {
4123171168Smlaier				match = 1;
4124126258Smlaier				*rm = r;
4125126258Smlaier				*am = a;
4126126258Smlaier				*rsm = ruleset;
4127126258Smlaier				if ((*rm)->quick)
4128126258Smlaier					break;
4129126258Smlaier				r = TAILQ_NEXT(r, entries);
4130126258Smlaier			} else
4131145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4132171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4133126258Smlaier		}
4134171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4135171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4136171168Smlaier			break;
4137126258Smlaier	}
4138126258Smlaier	r = *rm;
4139126258Smlaier	a = *am;
4140126258Smlaier	ruleset = *rsm;
4141126258Smlaier
4142126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4143126258Smlaier
4144171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log)) {
4145126258Smlaier#ifdef INET6
4146126258Smlaier		if (rewrite)
4147126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
4148126261Smlaier			    (caddr_t)pd->hdr.icmp6);
4149126258Smlaier#endif /* INET6 */
4150171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4151171168Smlaier		    a, ruleset, pd);
4152126258Smlaier	}
4153126258Smlaier
4154126258Smlaier	if (r->action != PF_PASS)
4155126258Smlaier		return (PF_DROP);
4156126258Smlaier
4157171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4158126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4159126258Smlaier		return (PF_DROP);
4160126258Smlaier	}
4161126258Smlaier
4162130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
4163126258Smlaier		/* create new state */
4164126258Smlaier		struct pf_state	*s = NULL;
4165130613Smlaier		struct pf_src_node *sn = NULL;
4166126258Smlaier
4167130613Smlaier		/* check maximums */
4168145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4169145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4170145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4171130613Smlaier			goto cleanup;
4172145836Smlaier		}
4173171168Smlaier		/* src node for filter rule */
4174130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4175130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4176145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4177145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4178130613Smlaier			goto cleanup;
4179145836Smlaier		}
4180130613Smlaier		/* src node for translation rule */
4181130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4182130613Smlaier		    ((direction == PF_OUT &&
4183130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4184145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4185145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4186130613Smlaier			goto cleanup;
4187145836Smlaier		}
4188130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4189126258Smlaier		if (s == NULL) {
4190145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4191130613Smlaiercleanup:
4192130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4193130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4194130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4195130613Smlaier				pf_status.src_nodes--;
4196130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4197130613Smlaier			}
4198130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4199130613Smlaier			    nsn->expire == 0) {
4200130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4201130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4202130613Smlaier				pf_status.src_nodes--;
4203130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4204130613Smlaier			}
4205126258Smlaier			return (PF_DROP);
4206126258Smlaier		}
4207126258Smlaier		bzero(s, sizeof(*s));
4208126258Smlaier		s->rule.ptr = r;
4209130613Smlaier		s->nat_rule.ptr = nr;
4210126258Smlaier		s->anchor.ptr = a;
4211145836Smlaier		STATE_INC_COUNTERS(s);
4212126258Smlaier		s->allow_opts = r->allow_opts;
4213171168Smlaier		s->log = r->log & PF_LOG_ALL;
4214171168Smlaier		if (nr != NULL)
4215171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4216126258Smlaier		s->proto = pd->proto;
4217126258Smlaier		s->direction = direction;
4218126258Smlaier		s->af = af;
4219126258Smlaier		if (direction == PF_OUT) {
4220126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4221149884Smlaier			s->gwy.port = nport;
4222126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4223149884Smlaier			s->ext.port = 0;
4224149884Smlaier			if (nr != NULL) {
4225130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4226149884Smlaier				s->lan.port = bport;
4227149884Smlaier			} else {
4228126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4229149884Smlaier				s->lan.port = s->gwy.port;
4230149884Smlaier			}
4231126258Smlaier		} else {
4232126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4233149884Smlaier			s->lan.port = nport;
4234126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4235149884Smlaier			s->ext.port = 0;
4236149884Smlaier			if (nr != NULL) {
4237130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4238149884Smlaier				s->gwy.port = bport;
4239149884Smlaier			} else {
4240126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4241149884Smlaier				s->gwy.port = s->lan.port;
4242149884Smlaier			}
4243126258Smlaier		}
4244126261Smlaier		s->creation = time_second;
4245126261Smlaier		s->expire = time_second;
4246126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
4247126258Smlaier		pf_set_rt_ifp(s, saddr);
4248130613Smlaier		if (sn != NULL) {
4249130613Smlaier			s->src_node = sn;
4250130613Smlaier			s->src_node->states++;
4251130613Smlaier		}
4252130613Smlaier		if (nsn != NULL) {
4253130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4254130613Smlaier			s->nat_src_node = nsn;
4255130613Smlaier			s->nat_src_node->states++;
4256130613Smlaier		}
4257130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4258145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4259130613Smlaier			pf_src_tree_remove_state(s);
4260145836Smlaier			STATE_DEC_COUNTERS(s);
4261126258Smlaier			pool_put(&pf_state_pl, s);
4262126258Smlaier			return (PF_DROP);
4263126258Smlaier		} else
4264126258Smlaier			*sm = s;
4265145836Smlaier		if (tag > 0) {
4266145836Smlaier			pf_tag_ref(tag);
4267145836Smlaier			s->tag = tag;
4268145836Smlaier		}
4269126258Smlaier	}
4270126258Smlaier
4271126258Smlaier#ifdef INET6
4272126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
4273126258Smlaier	if (rewrite)
4274126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
4275126261Smlaier		    (caddr_t)pd->hdr.icmp6);
4276126258Smlaier#endif /* INET6 */
4277126258Smlaier
4278126258Smlaier	return (PF_PASS);
4279126258Smlaier}
4280126258Smlaier
4281126258Smlaierint
4282126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
4283130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4284145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
4285126258Smlaier{
4286130613Smlaier	struct pf_rule		*nr = NULL;
4287126258Smlaier	struct pf_rule		*r, *a = NULL;
4288126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4289130613Smlaier	struct pf_src_node	*nsn = NULL;
4290126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
4291126258Smlaier	sa_family_t		 af = pd->af;
4292126258Smlaier	u_short			 reason;
4293171168Smlaier	int			 tag = -1, rtableid = -1;
4294145836Smlaier	int			 asd = 0;
4295171168Smlaier	int			 match = 0;
4296126258Smlaier
4297145836Smlaier	if (pf_check_congestion(ifq)) {
4298145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
4299145836Smlaier		return (PF_DROP);
4300145836Smlaier	}
4301145836Smlaier
4302126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4303126258Smlaier
4304126258Smlaier	if (direction == PF_OUT) {
4305126258Smlaier		/* check outgoing packet for BINAT/NAT */
4306130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4307130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4308130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4309126258Smlaier			switch (af) {
4310126258Smlaier#ifdef INET
4311126258Smlaier			case AF_INET:
4312126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4313130613Smlaier				    pd->naddr.v4.s_addr, 0);
4314126258Smlaier				break;
4315126258Smlaier#endif /* INET */
4316126258Smlaier#ifdef INET6
4317126258Smlaier			case AF_INET6:
4318130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
4319126258Smlaier				break;
4320126258Smlaier#endif /* INET6 */
4321126258Smlaier			}
4322130613Smlaier			if (nr->natpass)
4323126258Smlaier				r = NULL;
4324130613Smlaier			pd->nat_rule = nr;
4325126258Smlaier		}
4326126258Smlaier	} else {
4327126258Smlaier		/* check incoming packet for BINAT/RDR */
4328130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4329130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4330130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4331126258Smlaier			switch (af) {
4332126258Smlaier#ifdef INET
4333126258Smlaier			case AF_INET:
4334126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4335130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4336126258Smlaier				break;
4337126258Smlaier#endif /* INET */
4338126258Smlaier#ifdef INET6
4339126258Smlaier			case AF_INET6:
4340130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
4341126258Smlaier				break;
4342126258Smlaier#endif /* INET6 */
4343126258Smlaier			}
4344130613Smlaier			if (nr->natpass)
4345126258Smlaier				r = NULL;
4346130613Smlaier			pd->nat_rule = nr;
4347126258Smlaier		}
4348126258Smlaier	}
4349126258Smlaier
4350126258Smlaier	while (r != NULL) {
4351126258Smlaier		r->evaluations++;
4352171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4353126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4354126258Smlaier		else if (r->direction && r->direction != direction)
4355126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4356126258Smlaier		else if (r->af && r->af != af)
4357126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4358126258Smlaier		else if (r->proto && r->proto != pd->proto)
4359126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4360171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4361171168Smlaier		    r->src.neg, kif))
4362126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4363171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4364171168Smlaier		    r->dst.neg, NULL))
4365126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4366171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4367126258Smlaier			r = TAILQ_NEXT(r, entries);
4368126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4369126258Smlaier			r = TAILQ_NEXT(r, entries);
4370145836Smlaier		else if (r->prob && r->prob <= arc4random())
4371126258Smlaier			r = TAILQ_NEXT(r, entries);
4372171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4373126258Smlaier			r = TAILQ_NEXT(r, entries);
4374126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4375126258Smlaier			r = TAILQ_NEXT(r, entries);
4376126258Smlaier		else {
4377126258Smlaier			if (r->tag)
4378126258Smlaier				tag = r->tag;
4379171168Smlaier			if (r->rtableid >= 0)
4380171168Smlaier				rtableid = r->rtableid;
4381126258Smlaier			if (r->anchor == NULL) {
4382171168Smlaier				match = 1;
4383126258Smlaier				*rm = r;
4384126258Smlaier				*am = a;
4385126258Smlaier				*rsm = ruleset;
4386126258Smlaier				if ((*rm)->quick)
4387126258Smlaier					break;
4388126258Smlaier				r = TAILQ_NEXT(r, entries);
4389126258Smlaier			} else
4390145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4391171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4392126258Smlaier		}
4393171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4394171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4395171168Smlaier			break;
4396126258Smlaier	}
4397126258Smlaier	r = *rm;
4398126258Smlaier	a = *am;
4399126258Smlaier	ruleset = *rsm;
4400126258Smlaier
4401126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4402130613Smlaier
4403171168Smlaier	if (r->log || (nr != NULL && nr->natpass && nr->log))
4404171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
4405171168Smlaier		    a, ruleset, pd);
4406126258Smlaier
4407126258Smlaier	if ((r->action == PF_DROP) &&
4408126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4409126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4410126258Smlaier		struct pf_addr *a = NULL;
4411126258Smlaier
4412130613Smlaier		if (nr != NULL) {
4413130613Smlaier			if (direction == PF_OUT)
4414130613Smlaier				a = saddr;
4415130613Smlaier			else
4416130613Smlaier				a = daddr;
4417130613Smlaier		}
4418126258Smlaier		if (a != NULL) {
4419126258Smlaier			switch (af) {
4420126258Smlaier#ifdef INET
4421126258Smlaier			case AF_INET:
4422126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4423130613Smlaier				    pd->baddr.v4.s_addr, 0);
4424126258Smlaier				break;
4425126258Smlaier#endif /* INET */
4426126258Smlaier#ifdef INET6
4427126258Smlaier			case AF_INET6:
4428130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4429126258Smlaier				break;
4430126258Smlaier#endif /* INET6 */
4431126258Smlaier			}
4432126258Smlaier		}
4433126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4434126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4435126258Smlaier			    r->return_icmp & 255, af, r);
4436126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4437126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4438126258Smlaier			    r->return_icmp6 & 255, af, r);
4439126258Smlaier	}
4440126258Smlaier
4441126258Smlaier	if (r->action != PF_PASS)
4442126258Smlaier		return (PF_DROP);
4443126258Smlaier
4444171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) {
4445126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4446126258Smlaier		return (PF_DROP);
4447126258Smlaier	}
4448126258Smlaier
4449130613Smlaier	if (r->keep_state || nr != NULL) {
4450126258Smlaier		/* create new state */
4451126258Smlaier		struct pf_state	*s = NULL;
4452130613Smlaier		struct pf_src_node *sn = NULL;
4453126258Smlaier
4454130613Smlaier		/* check maximums */
4455145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4456145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4457145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4458130613Smlaier			goto cleanup;
4459145836Smlaier		}
4460171168Smlaier		/* src node for filter rule */
4461130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4462130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4463145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4464145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4465130613Smlaier			goto cleanup;
4466145836Smlaier		}
4467130613Smlaier		/* src node for translation rule */
4468130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4469130613Smlaier		    ((direction == PF_OUT &&
4470130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4471145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4472145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4473130613Smlaier			goto cleanup;
4474145836Smlaier		}
4475130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4476126258Smlaier		if (s == NULL) {
4477145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4478130613Smlaiercleanup:
4479130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4480130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4481130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4482130613Smlaier				pf_status.src_nodes--;
4483130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4484130613Smlaier			}
4485130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4486130613Smlaier			    nsn->expire == 0) {
4487130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4488130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4489130613Smlaier				pf_status.src_nodes--;
4490130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4491130613Smlaier			}
4492126258Smlaier			return (PF_DROP);
4493126258Smlaier		}
4494126258Smlaier		bzero(s, sizeof(*s));
4495126258Smlaier		s->rule.ptr = r;
4496130613Smlaier		s->nat_rule.ptr = nr;
4497126258Smlaier		s->anchor.ptr = a;
4498145836Smlaier		STATE_INC_COUNTERS(s);
4499126258Smlaier		s->allow_opts = r->allow_opts;
4500171168Smlaier		s->log = r->log & PF_LOG_ALL;
4501171168Smlaier		if (nr != NULL)
4502171168Smlaier			s->log |= nr->log & PF_LOG_ALL;
4503126258Smlaier		s->proto = pd->proto;
4504126258Smlaier		s->direction = direction;
4505126258Smlaier		s->af = af;
4506126258Smlaier		if (direction == PF_OUT) {
4507126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4508126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4509130613Smlaier			if (nr != NULL)
4510130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4511126258Smlaier			else
4512126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4513126258Smlaier		} else {
4514126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4515126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4516130613Smlaier			if (nr != NULL)
4517130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4518126258Smlaier			else
4519126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4520126258Smlaier		}
4521126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4522126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4523126261Smlaier		s->creation = time_second;
4524126261Smlaier		s->expire = time_second;
4525126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4526126258Smlaier		pf_set_rt_ifp(s, saddr);
4527130613Smlaier		if (sn != NULL) {
4528130613Smlaier			s->src_node = sn;
4529130613Smlaier			s->src_node->states++;
4530130613Smlaier		}
4531130613Smlaier		if (nsn != NULL) {
4532130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4533130613Smlaier			s->nat_src_node = nsn;
4534130613Smlaier			s->nat_src_node->states++;
4535130613Smlaier		}
4536130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4537145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4538130613Smlaier			pf_src_tree_remove_state(s);
4539145836Smlaier			STATE_DEC_COUNTERS(s);
4540126258Smlaier			pool_put(&pf_state_pl, s);
4541126258Smlaier			return (PF_DROP);
4542126258Smlaier		} else
4543126258Smlaier			*sm = s;
4544145836Smlaier		if (tag > 0) {
4545145836Smlaier			pf_tag_ref(tag);
4546145836Smlaier			s->tag = tag;
4547145836Smlaier		}
4548126258Smlaier	}
4549126258Smlaier
4550126258Smlaier	return (PF_PASS);
4551126258Smlaier}
4552126258Smlaier
4553126258Smlaierint
4554130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4555126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4556126258Smlaier    struct pf_ruleset **rsm)
4557126258Smlaier{
4558126258Smlaier	struct pf_rule		*r, *a = NULL;
4559126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4560126258Smlaier	sa_family_t		 af = pd->af;
4561126258Smlaier	u_short			 reason;
4562126258Smlaier	int			 tag = -1;
4563145836Smlaier	int			 asd = 0;
4564171168Smlaier	int			 match = 0;
4565126258Smlaier
4566126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4567126258Smlaier	while (r != NULL) {
4568126258Smlaier		r->evaluations++;
4569171168Smlaier		if (pfi_kif_match(r->kif, kif) == r->ifnot)
4570126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4571126258Smlaier		else if (r->direction && r->direction != direction)
4572126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4573126258Smlaier		else if (r->af && r->af != af)
4574126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4575126258Smlaier		else if (r->proto && r->proto != pd->proto)
4576126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4577171168Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
4578171168Smlaier		    r->src.neg, kif))
4579126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4580171168Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
4581171168Smlaier		    r->dst.neg, NULL))
4582126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4583171168Smlaier		else if (r->tos && !(r->tos == pd->tos))
4584126258Smlaier			r = TAILQ_NEXT(r, entries);
4585173815Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4586126258Smlaier			r = TAILQ_NEXT(r, entries);
4587173815Smlaier		else if (pd->proto == IPPROTO_UDP &&
4588173815Smlaier		    (r->src.port_op || r->dst.port_op))
4589173815Smlaier			r = TAILQ_NEXT(r, entries);
4590173815Smlaier		else if (pd->proto == IPPROTO_TCP &&
4591173815Smlaier		    (r->src.port_op || r->dst.port_op || r->flagset))
4592173815Smlaier			r = TAILQ_NEXT(r, entries);
4593173815Smlaier		else if ((pd->proto == IPPROTO_ICMP ||
4594173815Smlaier		    pd->proto == IPPROTO_ICMPV6) &&
4595173815Smlaier		    (r->type || r->code))
4596173815Smlaier			r = TAILQ_NEXT(r, entries);
4597145836Smlaier		else if (r->prob && r->prob <= arc4random())
4598126258Smlaier			r = TAILQ_NEXT(r, entries);
4599171168Smlaier		else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
4600126258Smlaier			r = TAILQ_NEXT(r, entries);
4601126258Smlaier		else {
4602126258Smlaier			if (r->anchor == NULL) {
4603171168Smlaier				match = 1;
4604126258Smlaier				*rm = r;
4605126258Smlaier				*am = a;
4606126258Smlaier				*rsm = ruleset;
4607126258Smlaier				if ((*rm)->quick)
4608126258Smlaier					break;
4609126258Smlaier				r = TAILQ_NEXT(r, entries);
4610126258Smlaier			} else
4611145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4612171168Smlaier				    PF_RULESET_FILTER, &r, &a, &match);
4613126258Smlaier		}
4614171168Smlaier		if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
4615171168Smlaier		    PF_RULESET_FILTER, &r, &a, &match))
4616171168Smlaier			break;
4617126258Smlaier	}
4618126258Smlaier	r = *rm;
4619126258Smlaier	a = *am;
4620126258Smlaier	ruleset = *rsm;
4621126258Smlaier
4622126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4623130613Smlaier
4624126258Smlaier	if (r->log)
4625171168Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
4626171168Smlaier		    pd);
4627126258Smlaier
4628126258Smlaier	if (r->action != PF_PASS)
4629126258Smlaier		return (PF_DROP);
4630126258Smlaier
4631171168Smlaier	if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) {
4632126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4633126258Smlaier		return (PF_DROP);
4634126258Smlaier	}
4635126258Smlaier
4636126258Smlaier	return (PF_PASS);
4637126258Smlaier}
4638126258Smlaier
4639126258Smlaierint
4640130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4641130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4642126258Smlaier    u_short *reason)
4643126258Smlaier{
4644171168Smlaier	struct pf_state_cmp	 key;
4645126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4646126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4647145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4648126258Smlaier	u_int8_t		 sws, dws;
4649130613Smlaier	int			 ackskew;
4650126258Smlaier	int			 copyback = 0;
4651126258Smlaier	struct pf_state_peer	*src, *dst;
4652126258Smlaier
4653126258Smlaier	key.af = pd->af;
4654126258Smlaier	key.proto = IPPROTO_TCP;
4655130613Smlaier	if (direction == PF_IN)	{
4656130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4657130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4658130613Smlaier		key.ext.port = th->th_sport;
4659130613Smlaier		key.gwy.port = th->th_dport;
4660130613Smlaier	} else {
4661130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4662130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4663130613Smlaier		key.lan.port = th->th_sport;
4664130613Smlaier		key.ext.port = th->th_dport;
4665130613Smlaier	}
4666126258Smlaier
4667126258Smlaier	STATE_LOOKUP();
4668126258Smlaier
4669126258Smlaier	if (direction == (*state)->direction) {
4670126258Smlaier		src = &(*state)->src;
4671126258Smlaier		dst = &(*state)->dst;
4672126258Smlaier	} else {
4673126258Smlaier		src = &(*state)->dst;
4674126258Smlaier		dst = &(*state)->src;
4675126258Smlaier	}
4676126258Smlaier
4677126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4678145836Smlaier		if (direction != (*state)->direction) {
4679145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4680126258Smlaier			return (PF_SYNPROXY_DROP);
4681145836Smlaier		}
4682126258Smlaier		if (th->th_flags & TH_SYN) {
4683145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4684145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4685126258Smlaier				return (PF_DROP);
4686145836Smlaier			}
4687162238Scsjp#ifdef __FreeBSD__
4688162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4689162238Scsjp#else
4690126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4691162238Scsjp#endif
4692126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4693126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4694145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4695171168Smlaier			    0, NULL, NULL);
4696145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4697126258Smlaier			return (PF_SYNPROXY_DROP);
4698126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4699126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4700145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4701145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4702126258Smlaier			return (PF_DROP);
4703145836Smlaier		} else if ((*state)->src_node != NULL &&
4704145836Smlaier		    pf_src_connlimit(state)) {
4705145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4706145836Smlaier			return (PF_DROP);
4707145836Smlaier		} else
4708126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4709126258Smlaier	}
4710126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4711126258Smlaier		struct pf_state_host *src, *dst;
4712126258Smlaier
4713126258Smlaier		if (direction == PF_OUT) {
4714126258Smlaier			src = &(*state)->gwy;
4715126258Smlaier			dst = &(*state)->ext;
4716126258Smlaier		} else {
4717126258Smlaier			src = &(*state)->ext;
4718126258Smlaier			dst = &(*state)->lan;
4719126258Smlaier		}
4720126258Smlaier		if (direction == (*state)->direction) {
4721126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4722126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4723145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4724145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4725126258Smlaier				return (PF_DROP);
4726145836Smlaier			}
4727126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4728126258Smlaier			if ((*state)->dst.seqhi == 1)
4729145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4730162238Scsjp#ifdef __FreeBSD__
4731162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4732162238Scsjp			    &src->addr,
4733162238Scsjp#else
4734126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4735162238Scsjp#endif
4736126258Smlaier			    &dst->addr, src->port, dst->port,
4737130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4738171168Smlaier			    (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
4739145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4740126258Smlaier			return (PF_SYNPROXY_DROP);
4741126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4742126258Smlaier		    (TH_SYN|TH_ACK)) ||
4743145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4744145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4745126258Smlaier			return (PF_DROP);
4746145836Smlaier		} else {
4747126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4748126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4749162238Scsjp#ifdef __FreeBSD__
4750162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4751162238Scsjp#else
4752126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4753162238Scsjp#endif
4754126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4755126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4756145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4757171168Smlaier			    (*state)->tag, NULL, NULL);
4758162238Scsjp#ifdef __FreeBSD__
4759162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4760162238Scsjp			    &src->addr,
4761162238Scsjp#else
4762126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4763162238Scsjp#endif
4764126258Smlaier			    &dst->addr, src->port, dst->port,
4765126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4766145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4767171168Smlaier			    0, NULL, NULL);
4768126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4769126258Smlaier			    (*state)->src.seqlo;
4770126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4771126258Smlaier			    (*state)->dst.seqlo;
4772126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4773145875Smlaier			    (*state)->dst.max_win;
4774145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4775145836Smlaier			    (*state)->src.max_win;
4776126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4777126258Smlaier			(*state)->src.state = (*state)->dst.state =
4778126258Smlaier			    TCPS_ESTABLISHED;
4779145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4780126258Smlaier			return (PF_SYNPROXY_DROP);
4781126258Smlaier		}
4782126258Smlaier	}
4783126258Smlaier
4784181295Smlaier	if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) &&
4785181295Smlaier	    dst->state >= TCPS_FIN_WAIT_2 &&
4786181295Smlaier	    src->state >= TCPS_FIN_WAIT_2) {
4787181295Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4788181295Smlaier			printf("pf: state reuse ");
4789181295Smlaier			pf_print_state(*state);
4790181295Smlaier			pf_print_flags(th->th_flags);
4791181295Smlaier			printf("\n");
4792181295Smlaier		}
4793181295Smlaier		/* XXX make sure it's the same direction ?? */
4794181295Smlaier		(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
4795181295Smlaier		pf_unlink_state(*state);
4796181295Smlaier		*state = NULL;
4797181295Smlaier		return (PF_DROP);
4798181295Smlaier	}
4799181295Smlaier
4800126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4801126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4802126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4803126258Smlaier	} else
4804126258Smlaier		sws = dws = 0;
4805126258Smlaier
4806126258Smlaier	/*
4807126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4808126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4809126258Smlaier	 *	tcp_filtering.ps
4810126258Smlaier	 */
4811126258Smlaier
4812145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4813126258Smlaier	if (src->seqlo == 0) {
4814126258Smlaier		/* First packet from this end. Set its state */
4815126258Smlaier
4816126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4817126258Smlaier		    src->scrub == NULL) {
4818126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4819126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4820126258Smlaier				return (PF_DROP);
4821126258Smlaier			}
4822126258Smlaier		}
4823126258Smlaier
4824126258Smlaier		/* Deferred generation of sequence number modulator */
4825126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4826171168Smlaier#ifdef __FreeBSD__
4827171168Smlaier			while ((src->seqdiff = pf_new_isn(*state) - seq) == 0)
4828126258Smlaier				;
4829171168Smlaier#else
4830171168Smlaier			while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
4831171168Smlaier				;
4832171168Smlaier#endif
4833126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4834126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4835126258Smlaier			    src->seqdiff), 0);
4836126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4837126258Smlaier			copyback = 1;
4838126258Smlaier		} else {
4839126258Smlaier			ack = ntohl(th->th_ack);
4840126258Smlaier		}
4841126258Smlaier
4842126258Smlaier		end = seq + pd->p_len;
4843126258Smlaier		if (th->th_flags & TH_SYN) {
4844126258Smlaier			end++;
4845126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4846126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4847126258Smlaier				    pd->af);
4848126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4849126258Smlaier					/* Remove scale factor from initial
4850126258Smlaier					 * window */
4851126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4852126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4853126258Smlaier					    >> sws;
4854126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4855126258Smlaier				} else {
4856126258Smlaier					/* fixup other window */
4857126258Smlaier					dst->max_win <<= dst->wscale &
4858126258Smlaier					    PF_WSCALE_MASK;
4859126258Smlaier					/* in case of a retrans SYN|ACK */
4860126258Smlaier					dst->wscale = 0;
4861126258Smlaier				}
4862126258Smlaier			}
4863126258Smlaier		}
4864126258Smlaier		if (th->th_flags & TH_FIN)
4865126258Smlaier			end++;
4866126258Smlaier
4867126258Smlaier		src->seqlo = seq;
4868126258Smlaier		if (src->state < TCPS_SYN_SENT)
4869126258Smlaier			src->state = TCPS_SYN_SENT;
4870126258Smlaier
4871126258Smlaier		/*
4872126258Smlaier		 * May need to slide the window (seqhi may have been set by
4873126258Smlaier		 * the crappy stack check or if we picked up the connection
4874126258Smlaier		 * after establishment)
4875126258Smlaier		 */
4876126258Smlaier		if (src->seqhi == 1 ||
4877126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4878126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4879126258Smlaier		if (win > src->max_win)
4880126258Smlaier			src->max_win = win;
4881126258Smlaier
4882126258Smlaier	} else {
4883126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4884126258Smlaier		if (src->seqdiff) {
4885126258Smlaier			/* Modulate sequence numbers */
4886126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4887126258Smlaier			    src->seqdiff), 0);
4888126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4889126258Smlaier			copyback = 1;
4890126258Smlaier		}
4891126258Smlaier		end = seq + pd->p_len;
4892126258Smlaier		if (th->th_flags & TH_SYN)
4893126258Smlaier			end++;
4894126258Smlaier		if (th->th_flags & TH_FIN)
4895126258Smlaier			end++;
4896126258Smlaier	}
4897126258Smlaier
4898126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4899126258Smlaier		/* Let it pass through the ack skew check */
4900126258Smlaier		ack = dst->seqlo;
4901126258Smlaier	} else if ((ack == 0 &&
4902126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4903126258Smlaier	    /* broken tcp stacks do not set ack */
4904126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4905126258Smlaier		/*
4906126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4907126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4908126258Smlaier		 */
4909126258Smlaier		ack = dst->seqlo;
4910126258Smlaier	}
4911126258Smlaier
4912126258Smlaier	if (seq == end) {
4913126258Smlaier		/* Ease sequencing restrictions on no data packets */
4914126258Smlaier		seq = src->seqlo;
4915126258Smlaier		end = seq;
4916126258Smlaier	}
4917126258Smlaier
4918126258Smlaier	ackskew = dst->seqlo - ack;
4919126258Smlaier
4920171168Smlaier
4921171168Smlaier	/*
4922171168Smlaier	 * Need to demodulate the sequence numbers in any TCP SACK options
4923171168Smlaier	 * (Selective ACK). We could optionally validate the SACK values
4924171168Smlaier	 * against the current ACK window, either forwards or backwards, but
4925171168Smlaier	 * I'm not confident that SACK has been implemented properly
4926171168Smlaier	 * everywhere. It wouldn't surprise me if several stacks accidently
4927171168Smlaier	 * SACK too far backwards of previously ACKed data. There really aren't
4928171168Smlaier	 * any security implications of bad SACKing unless the target stack
4929171168Smlaier	 * doesn't validate the option length correctly. Someone trying to
4930171168Smlaier	 * spoof into a TCP connection won't bother blindly sending SACK
4931171168Smlaier	 * options anyway.
4932171168Smlaier	 */
4933171168Smlaier	if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
4934171168Smlaier		if (pf_modulate_sack(m, off, pd, th, dst))
4935171168Smlaier			copyback = 1;
4936171168Smlaier	}
4937171168Smlaier
4938171168Smlaier
4939126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4940126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4941126258Smlaier	    /* Last octet inside other's window space */
4942126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4943126258Smlaier	    /* Retrans: not more than one window back */
4944126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4945126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4946145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4947126258Smlaier	    /* Acking not more than one window forward */
4948145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4949171168Smlaier	    (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
4950171168Smlaier	    /* Require an exact/+1 sequence match on resets when possible */
4951126258Smlaier
4952145836Smlaier		if (dst->scrub || src->scrub) {
4953145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4954145836Smlaier			    *state, src, dst, &copyback))
4955145836Smlaier				return (PF_DROP);
4956145836Smlaier		}
4957145836Smlaier
4958126258Smlaier		/* update max window */
4959126258Smlaier		if (src->max_win < win)
4960126258Smlaier			src->max_win = win;
4961126258Smlaier		/* synchronize sequencing */
4962126258Smlaier		if (SEQ_GT(end, src->seqlo))
4963126258Smlaier			src->seqlo = end;
4964126258Smlaier		/* slide the window of what the other end can send */
4965126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4966126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4967126258Smlaier
4968126258Smlaier
4969126258Smlaier		/* update states */
4970126258Smlaier		if (th->th_flags & TH_SYN)
4971126258Smlaier			if (src->state < TCPS_SYN_SENT)
4972126258Smlaier				src->state = TCPS_SYN_SENT;
4973126258Smlaier		if (th->th_flags & TH_FIN)
4974126258Smlaier			if (src->state < TCPS_CLOSING)
4975126258Smlaier				src->state = TCPS_CLOSING;
4976126258Smlaier		if (th->th_flags & TH_ACK) {
4977145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4978126258Smlaier				dst->state = TCPS_ESTABLISHED;
4979145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4980145836Smlaier				    (*state)->src_node != NULL &&
4981145836Smlaier				    pf_src_connlimit(state)) {
4982145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4983145836Smlaier					return (PF_DROP);
4984145836Smlaier				}
4985145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4986126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4987126258Smlaier		}
4988126258Smlaier		if (th->th_flags & TH_RST)
4989126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4990126258Smlaier
4991126258Smlaier		/* update expire time */
4992126261Smlaier		(*state)->expire = time_second;
4993126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4994126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4995126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4996171168Smlaier		else if (src->state >= TCPS_CLOSING &&
4997171168Smlaier		    dst->state >= TCPS_CLOSING)
4998126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4999126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
5000126258Smlaier		    dst->state < TCPS_ESTABLISHED)
5001126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
5002126258Smlaier		else if (src->state >= TCPS_CLOSING ||
5003126258Smlaier		    dst->state >= TCPS_CLOSING)
5004126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
5005126258Smlaier		else
5006126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
5007126258Smlaier
5008126258Smlaier		/* Fall through to PASS packet */
5009126258Smlaier
5010126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
5011126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
5012126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
5013126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
5014126258Smlaier	    /* Within a window forward of the originating packet */
5015126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
5016126258Smlaier	    /* Within a window backward of the originating packet */
5017126258Smlaier
5018126258Smlaier		/*
5019126258Smlaier		 * This currently handles three situations:
5020126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
5021126258Smlaier		 *     replies.
5022126258Smlaier		 *  2) When PF catches an already established stream (the
5023126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
5024126258Smlaier		 *     changed...)
5025126258Smlaier		 *  3) Packets get funky immediately after the connection
5026126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
5027126258Smlaier		 *     that web servers like to spew after a close)
5028126258Smlaier		 *
5029126258Smlaier		 * This must be a little more careful than the above code
5030126258Smlaier		 * since packet floods will also be caught here. We don't
5031126258Smlaier		 * update the TTL here to mitigate the damage of a packet
5032126258Smlaier		 * flood and so the same code can handle awkward establishment
5033126258Smlaier		 * and a loosened connection close.
5034126258Smlaier		 * In the establishment case, a correct peer response will
5035126258Smlaier		 * validate the connection, go through the normal state code
5036126258Smlaier		 * and keep updating the state TTL.
5037126258Smlaier		 */
5038126258Smlaier
5039126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
5040126258Smlaier			printf("pf: loose state match: ");
5041126258Smlaier			pf_print_state(*state);
5042126258Smlaier			pf_print_flags(th->th_flags);
5043171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5044171168Smlaier			    "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
5045171168Smlaier#ifdef __FreeBSD__
5046171168Smlaier			    ackskew, (unsigned long long)(*state)->packets[0],
5047171168Smlaier			    (unsigned long long)(*state)->packets[1]);
5048171168Smlaier#else
5049171168Smlaier			    ackskew, (*state)->packets[0],
5050171168Smlaier			    (*state)->packets[1]);
5051171168Smlaier#endif
5052126258Smlaier		}
5053126258Smlaier
5054145836Smlaier		if (dst->scrub || src->scrub) {
5055145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
5056145836Smlaier			    *state, src, dst, &copyback))
5057145836Smlaier				return (PF_DROP);
5058145836Smlaier		}
5059145836Smlaier
5060126258Smlaier		/* update max window */
5061126258Smlaier		if (src->max_win < win)
5062126258Smlaier			src->max_win = win;
5063126258Smlaier		/* synchronize sequencing */
5064126258Smlaier		if (SEQ_GT(end, src->seqlo))
5065126258Smlaier			src->seqlo = end;
5066126258Smlaier		/* slide the window of what the other end can send */
5067126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
5068126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
5069126258Smlaier
5070126258Smlaier		/*
5071126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
5072126258Smlaier		 * SYN and not an already established connection.
5073126258Smlaier		 */
5074126258Smlaier
5075126258Smlaier		if (th->th_flags & TH_FIN)
5076126258Smlaier			if (src->state < TCPS_CLOSING)
5077126258Smlaier				src->state = TCPS_CLOSING;
5078126258Smlaier		if (th->th_flags & TH_RST)
5079126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
5080126258Smlaier
5081126258Smlaier		/* Fall through to PASS packet */
5082126258Smlaier
5083126258Smlaier	} else {
5084126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
5085126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
5086126258Smlaier			/* Send RST for state mismatches during handshake */
5087145836Smlaier			if (!(th->th_flags & TH_RST))
5088162238Scsjp#ifdef __FreeBSD__
5089162238Scsjp				pf_send_tcp(m, (*state)->rule.ptr, pd->af,
5090162238Scsjp#else
5091126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
5092162238Scsjp#endif
5093126258Smlaier				    pd->dst, pd->src, th->th_dport,
5094145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
5095145836Smlaier				    TH_RST, 0, 0,
5096171168Smlaier				    (*state)->rule.ptr->return_ttl, 1, 0,
5097145836Smlaier				    pd->eh, kif->pfik_ifp);
5098126258Smlaier			src->seqlo = 0;
5099126258Smlaier			src->seqhi = 1;
5100126258Smlaier			src->max_win = 1;
5101126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
5102126258Smlaier			printf("pf: BAD state: ");
5103126258Smlaier			pf_print_state(*state);
5104126258Smlaier			pf_print_flags(th->th_flags);
5105171168Smlaier			printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
5106171168Smlaier			    "pkts=%llu:%llu dir=%s,%s\n",
5107171168Smlaier			    seq, orig_seq, ack, pd->p_len, ackskew,
5108171168Smlaier#ifdef __FreeBSD__
5109171168Smlaier			    (unsigned long long)(*state)->packets[0],
5110171168Smlaier			    (unsigned long long)(*state)->packets[1],
5111171168Smlaier#else
5112126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
5113171168Smlaier#endif
5114126258Smlaier			    direction == PF_IN ? "in" : "out",
5115126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
5116126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
5117126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
5118126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
5119126258Smlaier			    ' ': '2',
5120126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
5121126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
5122126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
5123126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
5124126258Smlaier		}
5125145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
5126126258Smlaier		return (PF_DROP);
5127126258Smlaier	}
5128126258Smlaier
5129126258Smlaier	/* Any packets which have gotten here are to be passed */
5130126258Smlaier
5131126258Smlaier	/* translate source/destination address, if necessary */
5132126258Smlaier	if (STATE_TRANSLATE(*state)) {
5133126258Smlaier		if (direction == PF_OUT)
5134126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
5135126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
5136126258Smlaier			    (*state)->gwy.port, 0, pd->af);
5137126258Smlaier		else
5138126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
5139126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
5140126258Smlaier			    (*state)->lan.port, 0, pd->af);
5141126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5142126258Smlaier	} else if (copyback) {
5143126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
5144126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
5145126258Smlaier	}
5146126258Smlaier
5147126258Smlaier	return (PF_PASS);
5148126258Smlaier}
5149126258Smlaier
5150126258Smlaierint
5151130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
5152130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
5153126258Smlaier{
5154126258Smlaier	struct pf_state_peer	*src, *dst;
5155171168Smlaier	struct pf_state_cmp	 key;
5156126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
5157126258Smlaier
5158126258Smlaier	key.af = pd->af;
5159126258Smlaier	key.proto = IPPROTO_UDP;
5160130613Smlaier	if (direction == PF_IN)	{
5161130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5162130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5163130613Smlaier		key.ext.port = uh->uh_sport;
5164130613Smlaier		key.gwy.port = uh->uh_dport;
5165130613Smlaier	} else {
5166130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5167130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5168130613Smlaier		key.lan.port = uh->uh_sport;
5169130613Smlaier		key.ext.port = uh->uh_dport;
5170130613Smlaier	}
5171126258Smlaier
5172126258Smlaier	STATE_LOOKUP();
5173126258Smlaier
5174126258Smlaier	if (direction == (*state)->direction) {
5175126258Smlaier		src = &(*state)->src;
5176126258Smlaier		dst = &(*state)->dst;
5177126258Smlaier	} else {
5178126258Smlaier		src = &(*state)->dst;
5179126258Smlaier		dst = &(*state)->src;
5180126258Smlaier	}
5181126258Smlaier
5182126258Smlaier	/* update states */
5183126258Smlaier	if (src->state < PFUDPS_SINGLE)
5184126258Smlaier		src->state = PFUDPS_SINGLE;
5185126258Smlaier	if (dst->state == PFUDPS_SINGLE)
5186126258Smlaier		dst->state = PFUDPS_MULTIPLE;
5187126258Smlaier
5188126258Smlaier	/* update expire time */
5189126261Smlaier	(*state)->expire = time_second;
5190126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
5191126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
5192126258Smlaier	else
5193126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
5194126258Smlaier
5195126258Smlaier	/* translate source/destination address, if necessary */
5196126258Smlaier	if (STATE_TRANSLATE(*state)) {
5197126258Smlaier		if (direction == PF_OUT)
5198126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
5199126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
5200126258Smlaier			    (*state)->gwy.port, 1, pd->af);
5201126258Smlaier		else
5202126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
5203126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
5204126258Smlaier			    (*state)->lan.port, 1, pd->af);
5205126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
5206126258Smlaier	}
5207126258Smlaier
5208126258Smlaier	return (PF_PASS);
5209126258Smlaier}
5210126258Smlaier
5211126258Smlaierint
5212130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
5213145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
5214126258Smlaier{
5215126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
5216127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
5217127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
5218127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
5219130613Smlaier	int		 state_icmp = 0;
5220171168Smlaier	struct pf_state_cmp key;
5221126258Smlaier
5222126258Smlaier	switch (pd->proto) {
5223126258Smlaier#ifdef INET
5224126258Smlaier	case IPPROTO_ICMP:
5225126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
5226126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
5227126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
5228126258Smlaier
5229126258Smlaier		if (icmptype == ICMP_UNREACH ||
5230126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
5231126258Smlaier		    icmptype == ICMP_REDIRECT ||
5232126258Smlaier		    icmptype == ICMP_TIMXCEED ||
5233126258Smlaier		    icmptype == ICMP_PARAMPROB)
5234126258Smlaier			state_icmp++;
5235126258Smlaier		break;
5236126258Smlaier#endif /* INET */
5237126258Smlaier#ifdef INET6
5238126258Smlaier	case IPPROTO_ICMPV6:
5239126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
5240126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
5241126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
5242126258Smlaier
5243126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
5244126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
5245126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
5246126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
5247126258Smlaier			state_icmp++;
5248126258Smlaier		break;
5249126258Smlaier#endif /* INET6 */
5250126258Smlaier	}
5251126258Smlaier
5252126258Smlaier	if (!state_icmp) {
5253126258Smlaier
5254126258Smlaier		/*
5255126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
5256126258Smlaier		 * Search for an ICMP state.
5257126258Smlaier		 */
5258126258Smlaier		key.af = pd->af;
5259126258Smlaier		key.proto = pd->proto;
5260130613Smlaier		if (direction == PF_IN)	{
5261130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
5262130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5263149884Smlaier			key.ext.port = 0;
5264130613Smlaier			key.gwy.port = icmpid;
5265130613Smlaier		} else {
5266130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
5267130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
5268130613Smlaier			key.lan.port = icmpid;
5269149884Smlaier			key.ext.port = 0;
5270130613Smlaier		}
5271126258Smlaier
5272126258Smlaier		STATE_LOOKUP();
5273126258Smlaier
5274126261Smlaier		(*state)->expire = time_second;
5275126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
5276126258Smlaier
5277126258Smlaier		/* translate source/destination address, if necessary */
5278149884Smlaier		if (STATE_TRANSLATE(*state)) {
5279126258Smlaier			if (direction == PF_OUT) {
5280126258Smlaier				switch (pd->af) {
5281126258Smlaier#ifdef INET
5282126258Smlaier				case AF_INET:
5283126258Smlaier					pf_change_a(&saddr->v4.s_addr,
5284126258Smlaier					    pd->ip_sum,
5285126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
5286149884Smlaier					pd->hdr.icmp->icmp_cksum =
5287149884Smlaier					    pf_cksum_fixup(
5288149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5289149884Smlaier					    (*state)->gwy.port, 0);
5290149884Smlaier					pd->hdr.icmp->icmp_id =
5291149884Smlaier					    (*state)->gwy.port;
5292149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5293149893Smlaier					    (caddr_t)pd->hdr.icmp);
5294126258Smlaier					break;
5295126258Smlaier#endif /* INET */
5296126258Smlaier#ifdef INET6
5297126258Smlaier				case AF_INET6:
5298126258Smlaier					pf_change_a6(saddr,
5299126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5300126258Smlaier					    &(*state)->gwy.addr, 0);
5301126258Smlaier					m_copyback(m, off,
5302126258Smlaier					    sizeof(struct icmp6_hdr),
5303126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5304126258Smlaier					break;
5305126258Smlaier#endif /* INET6 */
5306126258Smlaier				}
5307126258Smlaier			} else {
5308126258Smlaier				switch (pd->af) {
5309126258Smlaier#ifdef INET
5310126258Smlaier				case AF_INET:
5311126258Smlaier					pf_change_a(&daddr->v4.s_addr,
5312126258Smlaier					    pd->ip_sum,
5313126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
5314149884Smlaier					pd->hdr.icmp->icmp_cksum =
5315149884Smlaier					    pf_cksum_fixup(
5316149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
5317149884Smlaier					    (*state)->lan.port, 0);
5318149884Smlaier					pd->hdr.icmp->icmp_id =
5319149884Smlaier					    (*state)->lan.port;
5320149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
5321149893Smlaier					    (caddr_t)pd->hdr.icmp);
5322126258Smlaier					break;
5323126258Smlaier#endif /* INET */
5324126258Smlaier#ifdef INET6
5325126258Smlaier				case AF_INET6:
5326126258Smlaier					pf_change_a6(daddr,
5327126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
5328126258Smlaier					    &(*state)->lan.addr, 0);
5329126258Smlaier					m_copyback(m, off,
5330126258Smlaier					    sizeof(struct icmp6_hdr),
5331126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5332126258Smlaier					break;
5333126258Smlaier#endif /* INET6 */
5334126258Smlaier				}
5335126258Smlaier			}
5336126258Smlaier		}
5337126258Smlaier
5338126258Smlaier		return (PF_PASS);
5339126258Smlaier
5340126258Smlaier	} else {
5341126258Smlaier		/*
5342126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
5343126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
5344126258Smlaier		 */
5345126258Smlaier
5346126258Smlaier		struct pf_pdesc	pd2;
5347126258Smlaier#ifdef INET
5348126258Smlaier		struct ip	h2;
5349126258Smlaier#endif /* INET */
5350126258Smlaier#ifdef INET6
5351126258Smlaier		struct ip6_hdr	h2_6;
5352126258Smlaier		int		terminal = 0;
5353126258Smlaier#endif /* INET6 */
5354127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
5355127629Smlaier		int		off2 = 0;	/* make the compiler happy */
5356126258Smlaier
5357126258Smlaier		pd2.af = pd->af;
5358126258Smlaier		switch (pd->af) {
5359126258Smlaier#ifdef INET
5360126258Smlaier		case AF_INET:
5361126258Smlaier			/* offset of h2 in mbuf chain */
5362126258Smlaier			ipoff2 = off + ICMP_MINLEN;
5363126258Smlaier
5364126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
5365145836Smlaier			    NULL, reason, pd2.af)) {
5366126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5367126258Smlaier				    ("pf: ICMP error message too short "
5368126258Smlaier				    "(ip)\n"));
5369126258Smlaier				return (PF_DROP);
5370126258Smlaier			}
5371126258Smlaier			/*
5372126258Smlaier			 * ICMP error messages don't refer to non-first
5373126258Smlaier			 * fragments
5374126258Smlaier			 */
5375145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
5376145836Smlaier				REASON_SET(reason, PFRES_FRAG);
5377126258Smlaier				return (PF_DROP);
5378145836Smlaier			}
5379126258Smlaier
5380126258Smlaier			/* offset of protocol header that follows h2 */
5381126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
5382126258Smlaier
5383126258Smlaier			pd2.proto = h2.ip_p;
5384126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
5385126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
5386126258Smlaier			pd2.ip_sum = &h2.ip_sum;
5387126258Smlaier			break;
5388126258Smlaier#endif /* INET */
5389126258Smlaier#ifdef INET6
5390126258Smlaier		case AF_INET6:
5391126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
5392126258Smlaier
5393126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
5394145836Smlaier			    NULL, reason, pd2.af)) {
5395126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5396126258Smlaier				    ("pf: ICMP error message too short "
5397126258Smlaier				    "(ip6)\n"));
5398126258Smlaier				return (PF_DROP);
5399126258Smlaier			}
5400126258Smlaier			pd2.proto = h2_6.ip6_nxt;
5401126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
5402126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
5403126258Smlaier			pd2.ip_sum = NULL;
5404126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
5405126258Smlaier			do {
5406126258Smlaier				switch (pd2.proto) {
5407126258Smlaier				case IPPROTO_FRAGMENT:
5408126258Smlaier					/*
5409126258Smlaier					 * ICMPv6 error messages for
5410126258Smlaier					 * non-first fragments
5411126258Smlaier					 */
5412145836Smlaier					REASON_SET(reason, PFRES_FRAG);
5413126258Smlaier					return (PF_DROP);
5414126258Smlaier				case IPPROTO_AH:
5415126258Smlaier				case IPPROTO_HOPOPTS:
5416126258Smlaier				case IPPROTO_ROUTING:
5417126258Smlaier				case IPPROTO_DSTOPTS: {
5418126258Smlaier					/* get next header and header length */
5419126258Smlaier					struct ip6_ext opt6;
5420126258Smlaier
5421126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5422145836Smlaier					    sizeof(opt6), NULL, reason,
5423145836Smlaier					    pd2.af)) {
5424126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5425126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5426126258Smlaier						return (PF_DROP);
5427126258Smlaier					}
5428126258Smlaier					if (pd2.proto == IPPROTO_AH)
5429126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5430126258Smlaier					else
5431126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5432126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5433126258Smlaier					/* goto the next header */
5434126258Smlaier					break;
5435126258Smlaier				}
5436126258Smlaier				default:
5437126258Smlaier					terminal++;
5438126258Smlaier					break;
5439126258Smlaier				}
5440126258Smlaier			} while (!terminal);
5441126258Smlaier			break;
5442126258Smlaier#endif /* INET6 */
5443171168Smlaier#ifdef __FreeBSD__
5444171168Smlaier		default:
5445171168Smlaier			panic("AF not supported: %d", pd->af);
5446171168Smlaier#endif
5447126258Smlaier		}
5448126258Smlaier
5449126258Smlaier		switch (pd2.proto) {
5450126258Smlaier		case IPPROTO_TCP: {
5451126258Smlaier			struct tcphdr		 th;
5452126258Smlaier			u_int32_t		 seq;
5453126258Smlaier			struct pf_state_peer	*src, *dst;
5454126258Smlaier			u_int8_t		 dws;
5455128129Smlaier			int			 copyback = 0;
5456126258Smlaier
5457126258Smlaier			/*
5458126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5459126258Smlaier			 * expected. Don't access any TCP header fields after
5460126258Smlaier			 * th_seq, an ackskew test is not possible.
5461126258Smlaier			 */
5462145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5463145836Smlaier			    pd2.af)) {
5464126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5465126258Smlaier				    ("pf: ICMP error message too short "
5466126258Smlaier				    "(tcp)\n"));
5467126258Smlaier				return (PF_DROP);
5468126258Smlaier			}
5469126258Smlaier
5470126258Smlaier			key.af = pd2.af;
5471126258Smlaier			key.proto = IPPROTO_TCP;
5472130613Smlaier			if (direction == PF_IN)	{
5473130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5474130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5475130613Smlaier				key.ext.port = th.th_dport;
5476130613Smlaier				key.gwy.port = th.th_sport;
5477130613Smlaier			} else {
5478130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5479130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5480130613Smlaier				key.lan.port = th.th_dport;
5481130613Smlaier				key.ext.port = th.th_sport;
5482130613Smlaier			}
5483126258Smlaier
5484126258Smlaier			STATE_LOOKUP();
5485126258Smlaier
5486126258Smlaier			if (direction == (*state)->direction) {
5487126258Smlaier				src = &(*state)->dst;
5488126258Smlaier				dst = &(*state)->src;
5489126258Smlaier			} else {
5490126258Smlaier				src = &(*state)->src;
5491126258Smlaier				dst = &(*state)->dst;
5492126258Smlaier			}
5493126258Smlaier
5494171929Sdhartmei			if (src->wscale && dst->wscale)
5495126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5496126258Smlaier			else
5497126258Smlaier				dws = 0;
5498126258Smlaier
5499126258Smlaier			/* Demodulate sequence number */
5500126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5501128129Smlaier			if (src->seqdiff) {
5502128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5503126258Smlaier				    htonl(seq), 0);
5504128129Smlaier				copyback = 1;
5505128129Smlaier			}
5506126258Smlaier
5507126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5508126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5509126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5510126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5511126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5512126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5513126258Smlaier					printf(" -> ");
5514126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5515126258Smlaier					printf(" state: ");
5516126258Smlaier					pf_print_state(*state);
5517126258Smlaier					printf(" seq=%u\n", seq);
5518126258Smlaier				}
5519145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5520126258Smlaier				return (PF_DROP);
5521126258Smlaier			}
5522126258Smlaier
5523126258Smlaier			if (STATE_TRANSLATE(*state)) {
5524126258Smlaier				if (direction == PF_IN) {
5525126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5526128129Smlaier					    daddr, &(*state)->lan.addr,
5527126258Smlaier					    (*state)->lan.port, NULL,
5528126258Smlaier					    pd2.ip_sum, icmpsum,
5529126258Smlaier					    pd->ip_sum, 0, pd2.af);
5530126258Smlaier				} else {
5531126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5532126258Smlaier					    saddr, &(*state)->gwy.addr,
5533126258Smlaier					    (*state)->gwy.port, NULL,
5534126258Smlaier					    pd2.ip_sum, icmpsum,
5535126258Smlaier					    pd->ip_sum, 0, pd2.af);
5536126258Smlaier				}
5537128129Smlaier				copyback = 1;
5538128129Smlaier			}
5539128129Smlaier
5540128129Smlaier			if (copyback) {
5541126258Smlaier				switch (pd2.af) {
5542126258Smlaier#ifdef INET
5543126258Smlaier				case AF_INET:
5544126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5545126261Smlaier					    (caddr_t)pd->hdr.icmp);
5546126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5547126261Smlaier					    (caddr_t)&h2);
5548126258Smlaier					break;
5549126258Smlaier#endif /* INET */
5550126258Smlaier#ifdef INET6
5551126258Smlaier				case AF_INET6:
5552126258Smlaier					m_copyback(m, off,
5553126258Smlaier					    sizeof(struct icmp6_hdr),
5554126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5555126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5556126261Smlaier					    (caddr_t)&h2_6);
5557126258Smlaier					break;
5558126258Smlaier#endif /* INET6 */
5559126258Smlaier				}
5560126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5561126258Smlaier			}
5562126258Smlaier
5563126258Smlaier			return (PF_PASS);
5564126258Smlaier			break;
5565126258Smlaier		}
5566126258Smlaier		case IPPROTO_UDP: {
5567126258Smlaier			struct udphdr		uh;
5568126258Smlaier
5569126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5570145836Smlaier			    NULL, reason, pd2.af)) {
5571126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5572126258Smlaier				    ("pf: ICMP error message too short "
5573126258Smlaier				    "(udp)\n"));
5574126258Smlaier				return (PF_DROP);
5575126258Smlaier			}
5576126258Smlaier
5577126258Smlaier			key.af = pd2.af;
5578126258Smlaier			key.proto = IPPROTO_UDP;
5579130613Smlaier			if (direction == PF_IN)	{
5580130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5581130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5582130613Smlaier				key.ext.port = uh.uh_dport;
5583130613Smlaier				key.gwy.port = uh.uh_sport;
5584130613Smlaier			} else {
5585130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5586130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5587130613Smlaier				key.lan.port = uh.uh_dport;
5588130613Smlaier				key.ext.port = uh.uh_sport;
5589130613Smlaier			}
5590126258Smlaier
5591126258Smlaier			STATE_LOOKUP();
5592126258Smlaier
5593126258Smlaier			if (STATE_TRANSLATE(*state)) {
5594126258Smlaier				if (direction == PF_IN) {
5595126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5596126258Smlaier					    daddr, &(*state)->lan.addr,
5597126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5598126258Smlaier					    pd2.ip_sum, icmpsum,
5599126258Smlaier					    pd->ip_sum, 1, pd2.af);
5600126258Smlaier				} else {
5601126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5602126258Smlaier					    saddr, &(*state)->gwy.addr,
5603126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5604126258Smlaier					    pd2.ip_sum, icmpsum,
5605126258Smlaier					    pd->ip_sum, 1, pd2.af);
5606126258Smlaier				}
5607126258Smlaier				switch (pd2.af) {
5608126258Smlaier#ifdef INET
5609126258Smlaier				case AF_INET:
5610126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5611126261Smlaier					    (caddr_t)pd->hdr.icmp);
5612126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5613126261Smlaier					    (caddr_t)&h2);
5614126258Smlaier					break;
5615126258Smlaier#endif /* INET */
5616126258Smlaier#ifdef INET6
5617126258Smlaier				case AF_INET6:
5618126258Smlaier					m_copyback(m, off,
5619126258Smlaier					    sizeof(struct icmp6_hdr),
5620126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5621126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5622126261Smlaier					    (caddr_t)&h2_6);
5623126258Smlaier					break;
5624126258Smlaier#endif /* INET6 */
5625126258Smlaier				}
5626126261Smlaier				m_copyback(m, off2, sizeof(uh),
5627126261Smlaier				    (caddr_t)&uh);
5628126258Smlaier			}
5629126258Smlaier
5630126258Smlaier			return (PF_PASS);
5631126258Smlaier			break;
5632126258Smlaier		}
5633126258Smlaier#ifdef INET
5634126258Smlaier		case IPPROTO_ICMP: {
5635126258Smlaier			struct icmp		iih;
5636126258Smlaier
5637126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5638145836Smlaier			    NULL, reason, pd2.af)) {
5639126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5640126258Smlaier				    ("pf: ICMP error message too short i"
5641126258Smlaier				    "(icmp)\n"));
5642126258Smlaier				return (PF_DROP);
5643126258Smlaier			}
5644126258Smlaier
5645126258Smlaier			key.af = pd2.af;
5646126258Smlaier			key.proto = IPPROTO_ICMP;
5647130613Smlaier			if (direction == PF_IN)	{
5648130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5649130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5650149884Smlaier				key.ext.port = 0;
5651130613Smlaier				key.gwy.port = iih.icmp_id;
5652130613Smlaier			} else {
5653130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5654130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5655130613Smlaier				key.lan.port = iih.icmp_id;
5656149884Smlaier				key.ext.port = 0;
5657130613Smlaier			}
5658126258Smlaier
5659126258Smlaier			STATE_LOOKUP();
5660126258Smlaier
5661126258Smlaier			if (STATE_TRANSLATE(*state)) {
5662126258Smlaier				if (direction == PF_IN) {
5663126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5664126258Smlaier					    daddr, &(*state)->lan.addr,
5665126258Smlaier					    (*state)->lan.port, NULL,
5666126258Smlaier					    pd2.ip_sum, icmpsum,
5667126258Smlaier					    pd->ip_sum, 0, AF_INET);
5668126258Smlaier				} else {
5669126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5670126258Smlaier					    saddr, &(*state)->gwy.addr,
5671126258Smlaier					    (*state)->gwy.port, NULL,
5672126258Smlaier					    pd2.ip_sum, icmpsum,
5673126258Smlaier					    pd->ip_sum, 0, AF_INET);
5674126258Smlaier				}
5675126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5676126261Smlaier				    (caddr_t)pd->hdr.icmp);
5677126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5678126261Smlaier				    (caddr_t)&h2);
5679126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5680126261Smlaier				    (caddr_t)&iih);
5681126258Smlaier			}
5682126258Smlaier
5683126258Smlaier			return (PF_PASS);
5684126258Smlaier			break;
5685126258Smlaier		}
5686126258Smlaier#endif /* INET */
5687126258Smlaier#ifdef INET6
5688126258Smlaier		case IPPROTO_ICMPV6: {
5689126258Smlaier			struct icmp6_hdr	iih;
5690126258Smlaier
5691126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5692145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5693126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5694126258Smlaier				    ("pf: ICMP error message too short "
5695126258Smlaier				    "(icmp6)\n"));
5696126258Smlaier				return (PF_DROP);
5697126258Smlaier			}
5698126258Smlaier
5699126258Smlaier			key.af = pd2.af;
5700126258Smlaier			key.proto = IPPROTO_ICMPV6;
5701130613Smlaier			if (direction == PF_IN)	{
5702130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5703130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5704149884Smlaier				key.ext.port = 0;
5705130613Smlaier				key.gwy.port = iih.icmp6_id;
5706130613Smlaier			} else {
5707130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5708130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5709130613Smlaier				key.lan.port = iih.icmp6_id;
5710149884Smlaier				key.ext.port = 0;
5711130613Smlaier			}
5712126258Smlaier
5713126258Smlaier			STATE_LOOKUP();
5714126258Smlaier
5715126258Smlaier			if (STATE_TRANSLATE(*state)) {
5716126258Smlaier				if (direction == PF_IN) {
5717126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5718126258Smlaier					    daddr, &(*state)->lan.addr,
5719126258Smlaier					    (*state)->lan.port, NULL,
5720126258Smlaier					    pd2.ip_sum, icmpsum,
5721126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5722126258Smlaier				} else {
5723126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5724126258Smlaier					    saddr, &(*state)->gwy.addr,
5725126258Smlaier					    (*state)->gwy.port, NULL,
5726126258Smlaier					    pd2.ip_sum, icmpsum,
5727126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5728126258Smlaier				}
5729126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5730126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5731126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5732126261Smlaier				    (caddr_t)&h2_6);
5733126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5734126261Smlaier				    (caddr_t)&iih);
5735126258Smlaier			}
5736126258Smlaier
5737126258Smlaier			return (PF_PASS);
5738126258Smlaier			break;
5739126258Smlaier		}
5740126258Smlaier#endif /* INET6 */
5741126258Smlaier		default: {
5742126258Smlaier			key.af = pd2.af;
5743126258Smlaier			key.proto = pd2.proto;
5744130613Smlaier			if (direction == PF_IN)	{
5745130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5746130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5747130613Smlaier				key.ext.port = 0;
5748130613Smlaier				key.gwy.port = 0;
5749130613Smlaier			} else {
5750130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5751130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5752130613Smlaier				key.lan.port = 0;
5753130613Smlaier				key.ext.port = 0;
5754130613Smlaier			}
5755126258Smlaier
5756126258Smlaier			STATE_LOOKUP();
5757126258Smlaier
5758126258Smlaier			if (STATE_TRANSLATE(*state)) {
5759126258Smlaier				if (direction == PF_IN) {
5760126258Smlaier					pf_change_icmp(pd2.src, NULL,
5761126258Smlaier					    daddr, &(*state)->lan.addr,
5762126258Smlaier					    0, NULL,
5763126258Smlaier					    pd2.ip_sum, icmpsum,
5764126258Smlaier					    pd->ip_sum, 0, pd2.af);
5765126258Smlaier				} else {
5766126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5767126258Smlaier					    saddr, &(*state)->gwy.addr,
5768126258Smlaier					    0, NULL,
5769126258Smlaier					    pd2.ip_sum, icmpsum,
5770126258Smlaier					    pd->ip_sum, 0, pd2.af);
5771126258Smlaier				}
5772126258Smlaier				switch (pd2.af) {
5773126258Smlaier#ifdef INET
5774126258Smlaier				case AF_INET:
5775126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5776126261Smlaier					    (caddr_t)pd->hdr.icmp);
5777126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5778126261Smlaier					    (caddr_t)&h2);
5779126258Smlaier					break;
5780126258Smlaier#endif /* INET */
5781126258Smlaier#ifdef INET6
5782126258Smlaier				case AF_INET6:
5783126258Smlaier					m_copyback(m, off,
5784126258Smlaier					    sizeof(struct icmp6_hdr),
5785126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5786126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5787126261Smlaier					    (caddr_t)&h2_6);
5788126258Smlaier					break;
5789126258Smlaier#endif /* INET6 */
5790126258Smlaier				}
5791126258Smlaier			}
5792126258Smlaier
5793126258Smlaier			return (PF_PASS);
5794126258Smlaier			break;
5795126258Smlaier		}
5796126258Smlaier		}
5797126258Smlaier	}
5798126258Smlaier}
5799126258Smlaier
5800126258Smlaierint
5801130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5802126258Smlaier    struct pf_pdesc *pd)
5803126258Smlaier{
5804126258Smlaier	struct pf_state_peer	*src, *dst;
5805171168Smlaier	struct pf_state_cmp	 key;
5806126258Smlaier
5807126258Smlaier	key.af = pd->af;
5808126258Smlaier	key.proto = pd->proto;
5809130613Smlaier	if (direction == PF_IN)	{
5810130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5811130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5812130613Smlaier		key.ext.port = 0;
5813130613Smlaier		key.gwy.port = 0;
5814130613Smlaier	} else {
5815130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5816130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5817130613Smlaier		key.lan.port = 0;
5818130613Smlaier		key.ext.port = 0;
5819130613Smlaier	}
5820126258Smlaier
5821126258Smlaier	STATE_LOOKUP();
5822126258Smlaier
5823126258Smlaier	if (direction == (*state)->direction) {
5824126258Smlaier		src = &(*state)->src;
5825126258Smlaier		dst = &(*state)->dst;
5826126258Smlaier	} else {
5827126258Smlaier		src = &(*state)->dst;
5828126258Smlaier		dst = &(*state)->src;
5829126258Smlaier	}
5830126258Smlaier
5831126258Smlaier	/* update states */
5832126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5833126258Smlaier		src->state = PFOTHERS_SINGLE;
5834126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5835126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5836126258Smlaier
5837126258Smlaier	/* update expire time */
5838126261Smlaier	(*state)->expire = time_second;
5839126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5840126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5841126258Smlaier	else
5842126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5843126258Smlaier
5844126258Smlaier	/* translate source/destination address, if necessary */
5845126258Smlaier	if (STATE_TRANSLATE(*state)) {
5846126258Smlaier		if (direction == PF_OUT)
5847126258Smlaier			switch (pd->af) {
5848126258Smlaier#ifdef INET
5849126258Smlaier			case AF_INET:
5850126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5851126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5852126258Smlaier				    0);
5853126258Smlaier				break;
5854126258Smlaier#endif /* INET */
5855126258Smlaier#ifdef INET6
5856126258Smlaier			case AF_INET6:
5857126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5858126258Smlaier				break;
5859126258Smlaier#endif /* INET6 */
5860126258Smlaier			}
5861126258Smlaier		else
5862126258Smlaier			switch (pd->af) {
5863126258Smlaier#ifdef INET
5864126258Smlaier			case AF_INET:
5865126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5866126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5867126258Smlaier				    0);
5868126258Smlaier				break;
5869126258Smlaier#endif /* INET */
5870126258Smlaier#ifdef INET6
5871126258Smlaier			case AF_INET6:
5872126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5873126258Smlaier				break;
5874126258Smlaier#endif /* INET6 */
5875126258Smlaier			}
5876126258Smlaier	}
5877126258Smlaier
5878126258Smlaier	return (PF_PASS);
5879126258Smlaier}
5880126258Smlaier
5881126258Smlaier/*
5882126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5883126258Smlaier * h must be at "ipoff" on the mbuf chain.
5884126258Smlaier */
5885126258Smlaiervoid *
5886126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5887126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5888126258Smlaier{
5889126258Smlaier	switch (af) {
5890126258Smlaier#ifdef INET
5891126258Smlaier	case AF_INET: {
5892126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5893126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5894126258Smlaier
5895126258Smlaier		if (fragoff) {
5896126258Smlaier			if (fragoff >= len)
5897126258Smlaier				ACTION_SET(actionp, PF_PASS);
5898126258Smlaier			else {
5899126258Smlaier				ACTION_SET(actionp, PF_DROP);
5900126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5901126258Smlaier			}
5902126258Smlaier			return (NULL);
5903126258Smlaier		}
5904130613Smlaier		if (m->m_pkthdr.len < off + len ||
5905130613Smlaier		    ntohs(h->ip_len) < off + len) {
5906126258Smlaier			ACTION_SET(actionp, PF_DROP);
5907126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5908126258Smlaier			return (NULL);
5909126258Smlaier		}
5910126258Smlaier		break;
5911126258Smlaier	}
5912126258Smlaier#endif /* INET */
5913126258Smlaier#ifdef INET6
5914126258Smlaier	case AF_INET6: {
5915126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5916126258Smlaier
5917126258Smlaier		if (m->m_pkthdr.len < off + len ||
5918126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5919126258Smlaier		    (unsigned)(off + len)) {
5920126258Smlaier			ACTION_SET(actionp, PF_DROP);
5921126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5922126258Smlaier			return (NULL);
5923126258Smlaier		}
5924126258Smlaier		break;
5925126258Smlaier	}
5926126258Smlaier#endif /* INET6 */
5927126258Smlaier	}
5928126258Smlaier	m_copydata(m, off, len, p);
5929126258Smlaier	return (p);
5930126258Smlaier}
5931126258Smlaier
5932126258Smlaierint
5933171168Smlaierpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
5934126258Smlaier{
5935126258Smlaier	struct sockaddr_in	*dst;
5936171168Smlaier	int			 ret = 1;
5937171168Smlaier	int			 check_mpath;
5938171168Smlaier#ifndef __FreeBSD__
5939171168Smlaier	extern int		 ipmultipath;
5940171168Smlaier#endif
5941145836Smlaier#ifdef INET6
5942171168Smlaier#ifndef __FreeBSD__
5943171168Smlaier	extern int		 ip6_multipath;
5944171168Smlaier#endif
5945145836Smlaier	struct sockaddr_in6	*dst6;
5946145836Smlaier	struct route_in6	 ro;
5947145836Smlaier#else
5948126258Smlaier	struct route		 ro;
5949145836Smlaier#endif
5950171168Smlaier	struct radix_node	*rn;
5951171168Smlaier	struct rtentry		*rt;
5952171168Smlaier	struct ifnet		*ifp;
5953126258Smlaier
5954171168Smlaier	check_mpath = 0;
5955126258Smlaier	bzero(&ro, sizeof(ro));
5956145836Smlaier	switch (af) {
5957145836Smlaier	case AF_INET:
5958145836Smlaier		dst = satosin(&ro.ro_dst);
5959145836Smlaier		dst->sin_family = AF_INET;
5960145836Smlaier		dst->sin_len = sizeof(*dst);
5961145836Smlaier		dst->sin_addr = addr->v4;
5962171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
5963171168Smlaier		if (ipmultipath)
5964171168Smlaier			check_mpath = 1;
5965171168Smlaier#endif
5966145836Smlaier		break;
5967145836Smlaier#ifdef INET6
5968145836Smlaier	case AF_INET6:
5969145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5970145836Smlaier		dst6->sin6_family = AF_INET6;
5971145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5972145836Smlaier		dst6->sin6_addr = addr->v6;
5973171168Smlaier#ifndef __FreeBSD__	/* MULTIPATH_ROUTING */
5974171168Smlaier		if (ip6_multipath)
5975171168Smlaier			check_mpath = 1;
5976171168Smlaier#endif
5977145836Smlaier		break;
5978145836Smlaier#endif /* INET6 */
5979145836Smlaier	default:
5980145836Smlaier		return (0);
5981145836Smlaier	}
5982145836Smlaier
5983171168Smlaier	/* Skip checks for ipsec interfaces */
5984171168Smlaier	if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
5985171168Smlaier		goto out;
5986171168Smlaier
5987127145Smlaier#ifdef __FreeBSD__
5988178888Sjulian/* XXX MRT not always INET */ /* stick with table 0 though */
5989178888Sjulian	if (af == AF_INET)
5990178888Sjulian		in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0);
5991178888Sjulian	else
5992178888Sjulian		rtalloc_ign((struct route *)&ro, RTF_CLONING);
5993126261Smlaier#else /* ! __FreeBSD__ */
5994145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5995126261Smlaier#endif
5996126258Smlaier
5997126258Smlaier	if (ro.ro_rt != NULL) {
5998171168Smlaier		/* No interface given, this is a no-route check */
5999171168Smlaier		if (kif == NULL)
6000171168Smlaier			goto out;
6001171168Smlaier
6002171168Smlaier		if (kif->pfik_ifp == NULL) {
6003171168Smlaier			ret = 0;
6004171168Smlaier			goto out;
6005171168Smlaier		}
6006171168Smlaier
6007171168Smlaier		/* Perform uRPF check if passed input interface */
6008171168Smlaier		ret = 0;
6009171168Smlaier		rn = (struct radix_node *)ro.ro_rt;
6010171168Smlaier		do {
6011171168Smlaier			rt = (struct rtentry *)rn;
6012171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */
6013171168Smlaier			if (rt->rt_ifp->if_type == IFT_CARP)
6014171168Smlaier				ifp = rt->rt_ifp->if_carpdev;
6015171168Smlaier			else
6016171168Smlaier#endif
6017171168Smlaier				ifp = rt->rt_ifp;
6018171168Smlaier
6019171168Smlaier			if (kif->pfik_ifp == ifp)
6020171168Smlaier				ret = 1;
6021171168Smlaier#ifdef __FreeBSD__ /* MULTIPATH_ROUTING */
6022171168Smlaier			rn = NULL;
6023171168Smlaier#else
6024171168Smlaier			rn = rn_mpath_next(rn);
6025171168Smlaier#endif
6026171168Smlaier		} while (check_mpath == 1 && rn != NULL && ret == 0);
6027171168Smlaier	} else
6028171168Smlaier		ret = 0;
6029171168Smlaierout:
6030171168Smlaier	if (ro.ro_rt != NULL)
6031126258Smlaier		RTFREE(ro.ro_rt);
6032171168Smlaier	return (ret);
6033145836Smlaier}
6034145836Smlaier
6035145836Smlaierint
6036145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
6037145836Smlaier{
6038145836Smlaier	struct sockaddr_in	*dst;
6039145836Smlaier#ifdef INET6
6040145836Smlaier	struct sockaddr_in6	*dst6;
6041145836Smlaier	struct route_in6	 ro;
6042145836Smlaier#else
6043145836Smlaier	struct route		 ro;
6044145836Smlaier#endif
6045145836Smlaier	int			 ret = 0;
6046145836Smlaier
6047145836Smlaier	bzero(&ro, sizeof(ro));
6048145836Smlaier	switch (af) {
6049145836Smlaier	case AF_INET:
6050145836Smlaier		dst = satosin(&ro.ro_dst);
6051145836Smlaier		dst->sin_family = AF_INET;
6052145836Smlaier		dst->sin_len = sizeof(*dst);
6053145836Smlaier		dst->sin_addr = addr->v4;
6054145836Smlaier		break;
6055145836Smlaier#ifdef INET6
6056145836Smlaier	case AF_INET6:
6057145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
6058145836Smlaier		dst6->sin6_family = AF_INET6;
6059145836Smlaier		dst6->sin6_len = sizeof(*dst6);
6060145836Smlaier		dst6->sin6_addr = addr->v6;
6061145836Smlaier		break;
6062145836Smlaier#endif /* INET6 */
6063145836Smlaier	default:
6064145836Smlaier		return (0);
6065145836Smlaier	}
6066145836Smlaier
6067145836Smlaier#ifdef __FreeBSD__
6068145836Smlaier# ifdef RTF_PRCLONING
6069145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
6070145836Smlaier# else /* !RTF_PRCLONING */
6071178888Sjulian	if (af == AF_INET)
6072178888Sjulian		in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0);
6073178888Sjulian	else
6074178888Sjulian		rtalloc_ign((struct route *)&ro, RTF_CLONING);
6075145836Smlaier# endif
6076145836Smlaier#else /* ! __FreeBSD__ */
6077145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
6078145836Smlaier#endif
6079145836Smlaier
6080145836Smlaier	if (ro.ro_rt != NULL) {
6081145836Smlaier#ifdef __FreeBSD__
6082145836Smlaier		/* XXX_IMPORT: later */
6083145836Smlaier#else
6084145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
6085145836Smlaier			ret = 1;
6086145836Smlaier#endif
6087145836Smlaier		RTFREE(ro.ro_rt);
6088145836Smlaier	}
6089145836Smlaier
6090126258Smlaier	return (ret);
6091126258Smlaier}
6092126258Smlaier
6093126258Smlaier#ifdef INET
6094126261Smlaier
6095126258Smlaiervoid
6096126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6097171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6098126258Smlaier{
6099126258Smlaier	struct mbuf		*m0, *m1;
6100126258Smlaier	struct route		 iproute;
6101171168Smlaier	struct route		*ro = NULL;
6102126258Smlaier	struct sockaddr_in	*dst;
6103126258Smlaier	struct ip		*ip;
6104126258Smlaier	struct ifnet		*ifp = NULL;
6105126258Smlaier	struct pf_addr		 naddr;
6106130613Smlaier	struct pf_src_node	*sn = NULL;
6107126258Smlaier	int			 error = 0;
6108127145Smlaier#ifdef __FreeBSD__
6109126261Smlaier	int sw_csum;
6110126261Smlaier#endif
6111171168Smlaier#ifdef IPSEC
6112171168Smlaier	struct m_tag		*mtag;
6113171168Smlaier#endif /* IPSEC */
6114126258Smlaier
6115126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6116126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6117126258Smlaier		panic("pf_route: invalid parameters");
6118126258Smlaier
6119171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6120171168Smlaier		m0 = *m;
6121171168Smlaier		*m = NULL;
6122171168Smlaier		goto bad;
6123132303Smlaier	}
6124132303Smlaier
6125126258Smlaier	if (r->rt == PF_DUPTO) {
6126127145Smlaier#ifdef __FreeBSD__
6127132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6128126261Smlaier#else
6129132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6130126261Smlaier#endif
6131126258Smlaier			return;
6132126258Smlaier	} else {
6133126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6134126258Smlaier			return;
6135126258Smlaier		m0 = *m;
6136126258Smlaier	}
6137126258Smlaier
6138145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
6139145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6140145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6141145836Smlaier		goto bad;
6142145836Smlaier	}
6143145836Smlaier
6144126258Smlaier	ip = mtod(m0, struct ip *);
6145126258Smlaier
6146126258Smlaier	ro = &iproute;
6147126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6148126258Smlaier	dst = satosin(&ro->ro_dst);
6149126258Smlaier	dst->sin_family = AF_INET;
6150126258Smlaier	dst->sin_len = sizeof(*dst);
6151126258Smlaier	dst->sin_addr = ip->ip_dst;
6152126258Smlaier
6153126258Smlaier	if (r->rt == PF_FASTROUTE) {
6154178888Sjulian		in_rtalloc(ro, 0);
6155126258Smlaier		if (ro->ro_rt == 0) {
6156181803Sbz			V_ipstat.ips_noroute++;
6157126258Smlaier			goto bad;
6158126258Smlaier		}
6159126258Smlaier
6160126258Smlaier		ifp = ro->ro_rt->rt_ifp;
6161126258Smlaier		ro->ro_rt->rt_use++;
6162126258Smlaier
6163126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
6164126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
6165126258Smlaier	} else {
6166145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
6167145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6168145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
6169145836Smlaier			goto bad;
6170145836Smlaier		}
6171126258Smlaier		if (s == NULL) {
6172130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
6173130613Smlaier			    &naddr, NULL, &sn);
6174126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
6175126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
6176130613Smlaier			ifp = r->rpool.cur->kif ?
6177130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
6178126258Smlaier		} else {
6179126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
6180126258Smlaier				dst->sin_addr.s_addr =
6181126258Smlaier				    s->rt_addr.v4.s_addr;
6182130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6183126258Smlaier		}
6184126258Smlaier	}
6185126258Smlaier	if (ifp == NULL)
6186126258Smlaier		goto bad;
6187126258Smlaier
6188130639Smlaier	if (oifp != ifp) {
6189127145Smlaier#ifdef __FreeBSD__
6190126261Smlaier		PF_UNLOCK();
6191145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6192126261Smlaier			PF_LOCK();
6193126261Smlaier			goto bad;
6194126261Smlaier		} else if (m0 == NULL) {
6195126261Smlaier			PF_LOCK();
6196126261Smlaier			goto done;
6197126261Smlaier		}
6198126261Smlaier		PF_LOCK();
6199126261Smlaier#else
6200145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6201126258Smlaier			goto bad;
6202126258Smlaier		else if (m0 == NULL)
6203126258Smlaier			goto done;
6204126261Smlaier#endif
6205145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
6206145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6207145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
6208145836Smlaier			goto bad;
6209145836Smlaier		}
6210126258Smlaier		ip = mtod(m0, struct ip *);
6211126258Smlaier	}
6212126258Smlaier
6213127145Smlaier#ifdef __FreeBSD__
6214126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
6215126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
6216126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
6217126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
6218126261Smlaier		/*
6219126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
6220126261Smlaier		 */
6221126261Smlaier		NTOHS(ip->ip_len);
6222126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
6223126261Smlaier		in_delayed_cksum(m0);
6224126261Smlaier		HTONS(ip->ip_len);
6225126261Smlaier		HTONS(ip->ip_off);
6226126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
6227126261Smlaier	}
6228126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
6229126261Smlaier
6230126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
6231126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
6232126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
6233126261Smlaier		/*
6234126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
6235126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
6236126261Smlaier		 */
6237126261Smlaier		ip->ip_sum = 0;
6238126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
6239126261Smlaier			/* From KAME */
6240126261Smlaier			if (ip->ip_v == IPVERSION &&
6241126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
6242126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
6243126261Smlaier			} else {
6244126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6245126261Smlaier			}
6246126261Smlaier		}
6247126261Smlaier		PF_UNLOCK();
6248126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
6249126261Smlaier		PF_LOCK();
6250126261Smlaier		goto done;
6251126261Smlaier	}
6252126261Smlaier
6253126261Smlaier#else
6254126258Smlaier	/* Copied from ip_output. */
6255130613Smlaier#ifdef IPSEC
6256130613Smlaier	/*
6257130613Smlaier	 * If deferred crypto processing is needed, check that the
6258130613Smlaier	 * interface supports it.
6259130613Smlaier	 */
6260130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
6261130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
6262130613Smlaier		/* Notify IPsec to do its own crypto. */
6263130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
6264130613Smlaier		goto bad;
6265130613Smlaier	}
6266130613Smlaier#endif /* IPSEC */
6267130613Smlaier
6268130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
6269171168Smlaier	if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
6270130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
6271130613Smlaier		    ifp->if_bridge != NULL) {
6272130613Smlaier			in_delayed_cksum(m0);
6273171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
6274130613Smlaier		}
6275171168Smlaier	} else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
6276130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
6277130613Smlaier		    ifp->if_bridge != NULL) {
6278130613Smlaier			in_delayed_cksum(m0);
6279171168Smlaier			m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
6280130613Smlaier		}
6281130613Smlaier	}
6282130613Smlaier
6283126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
6284126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
6285126258Smlaier		    ifp->if_bridge == NULL) {
6286171168Smlaier			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
6287181803Sbz			V_ipstat.ips_outhwcsum++;
6288126258Smlaier		} else {
6289126258Smlaier			ip->ip_sum = 0;
6290126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
6291126258Smlaier		}
6292126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
6293171168Smlaier		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
6294181803Sbz			V_tcpstat.tcps_outhwcsum++;
6295171168Smlaier		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
6296181803Sbz			V_udpstat.udps_outhwcsum++;
6297126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
6298126258Smlaier		goto done;
6299126258Smlaier	}
6300126261Smlaier#endif
6301126258Smlaier	/*
6302126258Smlaier	 * Too large for interface; fragment if possible.
6303126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
6304126258Smlaier	 */
6305126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
6306181803Sbz		V_ipstat.ips_cantfrag++;
6307126258Smlaier		if (r->rt != PF_DUPTO) {
6308127145Smlaier#ifdef __FreeBSD__
6309126261Smlaier			/* icmp_error() expects host byte ordering */
6310126261Smlaier			NTOHS(ip->ip_len);
6311126261Smlaier			NTOHS(ip->ip_off);
6312126261Smlaier			PF_UNLOCK();
6313126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6314145886Smlaier			    ifp->if_mtu);
6315145874Smlaier			PF_LOCK();
6316145874Smlaier#else
6317145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
6318171168Smlaier			    ifp->if_mtu);
6319126261Smlaier#endif
6320126258Smlaier			goto done;
6321126258Smlaier		} else
6322126258Smlaier			goto bad;
6323126258Smlaier	}
6324126258Smlaier
6325126258Smlaier	m1 = m0;
6326127145Smlaier#ifdef __FreeBSD__
6327126261Smlaier	/*
6328126261Smlaier	 * XXX: is cheaper + less error prone than own function
6329126261Smlaier	 */
6330126261Smlaier	NTOHS(ip->ip_len);
6331126261Smlaier	NTOHS(ip->ip_off);
6332126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
6333126261Smlaier#else
6334126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
6335126261Smlaier#endif
6336127531Smlaier	if (error) {
6337127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
6338127531Smlaier		m0 = NULL;
6339126261Smlaier#endif
6340126258Smlaier		goto bad;
6341127531Smlaier	}
6342126258Smlaier
6343126258Smlaier	for (m0 = m1; m0; m0 = m1) {
6344126258Smlaier		m1 = m0->m_nextpkt;
6345126258Smlaier		m0->m_nextpkt = 0;
6346127145Smlaier#ifdef __FreeBSD__
6347126261Smlaier		if (error == 0) {
6348126261Smlaier			PF_UNLOCK();
6349126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6350126261Smlaier			    NULL);
6351126261Smlaier			PF_LOCK();
6352126261Smlaier		} else
6353126261Smlaier#else
6354126258Smlaier		if (error == 0)
6355126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
6356126258Smlaier			    NULL);
6357126258Smlaier		else
6358126261Smlaier#endif
6359126258Smlaier			m_freem(m0);
6360126258Smlaier	}
6361126258Smlaier
6362126258Smlaier	if (error == 0)
6363181803Sbz		V_ipstat.ips_fragmented++;
6364126258Smlaier
6365126258Smlaierdone:
6366126258Smlaier	if (r->rt != PF_DUPTO)
6367126258Smlaier		*m = NULL;
6368126258Smlaier	if (ro == &iproute && ro->ro_rt)
6369126258Smlaier		RTFREE(ro->ro_rt);
6370126258Smlaier	return;
6371126258Smlaier
6372126258Smlaierbad:
6373126258Smlaier	m_freem(m0);
6374126258Smlaier	goto done;
6375126258Smlaier}
6376126258Smlaier#endif /* INET */
6377126258Smlaier
6378126258Smlaier#ifdef INET6
6379126258Smlaiervoid
6380126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
6381171168Smlaier    struct pf_state *s, struct pf_pdesc *pd)
6382126258Smlaier{
6383126258Smlaier	struct mbuf		*m0;
6384126258Smlaier	struct route_in6	 ip6route;
6385126258Smlaier	struct route_in6	*ro;
6386126258Smlaier	struct sockaddr_in6	*dst;
6387126258Smlaier	struct ip6_hdr		*ip6;
6388126258Smlaier	struct ifnet		*ifp = NULL;
6389126258Smlaier	struct pf_addr		 naddr;
6390130613Smlaier	struct pf_src_node	*sn = NULL;
6391126258Smlaier	int			 error = 0;
6392126258Smlaier
6393126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
6394126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
6395126258Smlaier		panic("pf_route6: invalid parameters");
6396126258Smlaier
6397171168Smlaier	if (pd->pf_mtag->routed++ > 3) {
6398171168Smlaier		m0 = *m;
6399171168Smlaier		*m = NULL;
6400171168Smlaier		goto bad;
6401132303Smlaier	}
6402132303Smlaier
6403126258Smlaier	if (r->rt == PF_DUPTO) {
6404127145Smlaier#ifdef __FreeBSD__
6405132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6406126261Smlaier#else
6407132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6408126261Smlaier#endif
6409126258Smlaier			return;
6410126258Smlaier	} else {
6411126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6412126258Smlaier			return;
6413126258Smlaier		m0 = *m;
6414126258Smlaier	}
6415126258Smlaier
6416145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
6417145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6418145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6419145836Smlaier		goto bad;
6420145836Smlaier	}
6421126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
6422126258Smlaier
6423126258Smlaier	ro = &ip6route;
6424126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6425126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
6426126258Smlaier	dst->sin6_family = AF_INET6;
6427126258Smlaier	dst->sin6_len = sizeof(*dst);
6428126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
6429126258Smlaier
6430171168Smlaier	/* Cheat. XXX why only in the v6 case??? */
6431126258Smlaier	if (r->rt == PF_FASTROUTE) {
6432127145Smlaier#ifdef __FreeBSD__
6433132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
6434126261Smlaier		PF_UNLOCK();
6435126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6436126261Smlaier		PF_LOCK();
6437126261Smlaier#else
6438132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
6439132280Smlaier		if (mtag == NULL)
6440132280Smlaier			goto bad;
6441132280Smlaier		m_tag_prepend(m0, mtag);
6442171168Smlaier		pd->pf_mtag->flags |= PF_TAG_GENERATED;
6443126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
6444126261Smlaier#endif
6445126258Smlaier		return;
6446126258Smlaier	}
6447126258Smlaier
6448145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6449145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6450145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6451145836Smlaier		goto bad;
6452145836Smlaier	}
6453126258Smlaier	if (s == NULL) {
6454130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6455130613Smlaier		    &naddr, NULL, &sn);
6456126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6457126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6458126258Smlaier			    &naddr, AF_INET6);
6459130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6460126258Smlaier	} else {
6461126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6462126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6463126258Smlaier			    &s->rt_addr, AF_INET6);
6464130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6465126258Smlaier	}
6466126258Smlaier	if (ifp == NULL)
6467126258Smlaier		goto bad;
6468126258Smlaier
6469126258Smlaier	if (oifp != ifp) {
6470127145Smlaier#ifdef __FreeBSD__
6471132303Smlaier		PF_UNLOCK();
6472145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6473126261Smlaier			PF_LOCK();
6474132303Smlaier			goto bad;
6475132303Smlaier		} else if (m0 == NULL) {
6476132303Smlaier			PF_LOCK();
6477132303Smlaier			goto done;
6478132303Smlaier		}
6479132303Smlaier		PF_LOCK();
6480126261Smlaier#else
6481145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6482132303Smlaier			goto bad;
6483132303Smlaier		else if (m0 == NULL)
6484132303Smlaier			goto done;
6485126261Smlaier#endif
6486145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6487145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6488145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6489145836Smlaier			goto bad;
6490145836Smlaier		}
6491132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6492126258Smlaier	}
6493126258Smlaier
6494126258Smlaier	/*
6495126258Smlaier	 * If the packet is too large for the outgoing interface,
6496126258Smlaier	 * send back an icmp6 error.
6497126258Smlaier	 */
6498171168Smlaier	if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
6499126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6500126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6501127145Smlaier#ifdef __FreeBSD__
6502126261Smlaier		PF_UNLOCK();
6503126261Smlaier#endif
6504126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
6505127145Smlaier#ifdef __FreeBSD__
6506126261Smlaier		PF_LOCK();
6507126261Smlaier#endif
6508126258Smlaier	} else {
6509126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6510127145Smlaier#ifdef __FreeBSD__
6511126261Smlaier		if (r->rt != PF_DUPTO) {
6512126261Smlaier			PF_UNLOCK();
6513126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6514126261Smlaier			PF_LOCK();
6515126261Smlaier		 } else
6516126261Smlaier#else
6517126258Smlaier		if (r->rt != PF_DUPTO)
6518126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6519126258Smlaier		else
6520126261Smlaier#endif
6521126258Smlaier			goto bad;
6522126258Smlaier	}
6523126258Smlaier
6524126258Smlaierdone:
6525126258Smlaier	if (r->rt != PF_DUPTO)
6526126258Smlaier		*m = NULL;
6527126258Smlaier	return;
6528126258Smlaier
6529126258Smlaierbad:
6530126258Smlaier	m_freem(m0);
6531126258Smlaier	goto done;
6532126258Smlaier}
6533126258Smlaier#endif /* INET6 */
6534126258Smlaier
6535126258Smlaier
6536127145Smlaier#ifdef __FreeBSD__
6537126258Smlaier/*
6538132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6539137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6540132566Smlaier *   ti(4), txp(4), xl(4)
6541132566Smlaier *
6542132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6543132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6544132566Smlaier *   csum_data
6545132566Smlaier * CSUM_DATA_VALID :
6546132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6547132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6548132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6549132566Smlaier *
6550132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6551132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6552132566Smlaier * TCP/UDP layer.
6553132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6554126261Smlaier */
6555126261Smlaierint
6556126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6557126261Smlaier{
6558126261Smlaier	u_int16_t sum = 0;
6559126261Smlaier	int hw_assist = 0;
6560126261Smlaier	struct ip *ip;
6561126261Smlaier
6562126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6563126261Smlaier		return (1);
6564126261Smlaier	if (m->m_pkthdr.len < off + len)
6565126261Smlaier		return (1);
6566126261Smlaier
6567126261Smlaier	switch (p) {
6568126261Smlaier	case IPPROTO_TCP:
6569126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6570126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6571126261Smlaier				sum = m->m_pkthdr.csum_data;
6572126261Smlaier			} else {
6573126261Smlaier				ip = mtod(m, struct ip *);
6574126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6575135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6576135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6577126261Smlaier			}
6578126261Smlaier			sum ^= 0xffff;
6579126261Smlaier			++hw_assist;
6580126261Smlaier		}
6581126261Smlaier		break;
6582126261Smlaier	case IPPROTO_UDP:
6583126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6584126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6585126261Smlaier				sum = m->m_pkthdr.csum_data;
6586126261Smlaier			} else {
6587126261Smlaier				ip = mtod(m, struct ip *);
6588126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6589126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6590126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6591126261Smlaier			}
6592126261Smlaier			sum ^= 0xffff;
6593126261Smlaier			++hw_assist;
6594126261Smlaier                }
6595126261Smlaier		break;
6596126261Smlaier	case IPPROTO_ICMP:
6597126261Smlaier#ifdef INET6
6598126261Smlaier	case IPPROTO_ICMPV6:
6599126261Smlaier#endif /* INET6 */
6600126261Smlaier		break;
6601126261Smlaier	default:
6602126261Smlaier		return (1);
6603126261Smlaier	}
6604126261Smlaier
6605126261Smlaier	if (!hw_assist) {
6606126261Smlaier		switch (af) {
6607126261Smlaier		case AF_INET:
6608126261Smlaier			if (p == IPPROTO_ICMP) {
6609126261Smlaier				if (m->m_len < off)
6610126261Smlaier					return (1);
6611126261Smlaier				m->m_data += off;
6612126261Smlaier				m->m_len -= off;
6613126261Smlaier				sum = in_cksum(m, len);
6614126261Smlaier				m->m_data -= off;
6615126261Smlaier				m->m_len += off;
6616126261Smlaier			} else {
6617126261Smlaier				if (m->m_len < sizeof(struct ip))
6618126261Smlaier					return (1);
6619126261Smlaier				sum = in4_cksum(m, p, off, len);
6620126261Smlaier			}
6621126261Smlaier			break;
6622126261Smlaier#ifdef INET6
6623126261Smlaier		case AF_INET6:
6624126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6625126261Smlaier				return (1);
6626126261Smlaier			sum = in6_cksum(m, p, off, len);
6627126261Smlaier			break;
6628126261Smlaier#endif /* INET6 */
6629126261Smlaier		default:
6630126261Smlaier			return (1);
6631126261Smlaier		}
6632126261Smlaier	}
6633126261Smlaier	if (sum) {
6634126261Smlaier		switch (p) {
6635126261Smlaier		case IPPROTO_TCP:
6636181803Sbz			V_tcpstat.tcps_rcvbadsum++;
6637126261Smlaier			break;
6638126261Smlaier		case IPPROTO_UDP:
6639181803Sbz			V_udpstat.udps_badsum++;
6640126261Smlaier			break;
6641126261Smlaier		case IPPROTO_ICMP:
6642181803Sbz			V_icmpstat.icps_checksum++;
6643126261Smlaier			break;
6644126261Smlaier#ifdef INET6
6645126261Smlaier		case IPPROTO_ICMPV6:
6646181803Sbz			V_icmp6stat.icp6s_checksum++;
6647126261Smlaier			break;
6648126261Smlaier#endif /* INET6 */
6649126261Smlaier		}
6650126261Smlaier		return (1);
6651132566Smlaier	} else {
6652132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6653132566Smlaier			m->m_pkthdr.csum_flags |=
6654132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6655132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6656132566Smlaier		}
6657126261Smlaier	}
6658126261Smlaier	return (0);
6659126261Smlaier}
6660171168Smlaier#else /* !__FreeBSD__ */
6661126261Smlaier/*
6662126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6663126258Smlaier *   off is the offset where the protocol header starts
6664126258Smlaier *   len is the total length of protocol header plus payload
6665126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6666126258Smlaier */
6667126258Smlaierint
6668130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6669130613Smlaier    sa_family_t af)
6670126258Smlaier{
6671126258Smlaier	u_int16_t flag_ok, flag_bad;
6672126258Smlaier	u_int16_t sum;
6673126258Smlaier
6674126258Smlaier	switch (p) {
6675126258Smlaier	case IPPROTO_TCP:
6676126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6677126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6678126258Smlaier		break;
6679126258Smlaier	case IPPROTO_UDP:
6680126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6681126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6682126258Smlaier		break;
6683126258Smlaier	case IPPROTO_ICMP:
6684126258Smlaier#ifdef INET6
6685126258Smlaier	case IPPROTO_ICMPV6:
6686126258Smlaier#endif /* INET6 */
6687126258Smlaier		flag_ok = flag_bad = 0;
6688126258Smlaier		break;
6689126258Smlaier	default:
6690126258Smlaier		return (1);
6691126258Smlaier	}
6692171168Smlaier	if (m->m_pkthdr.csum_flags & flag_ok)
6693126258Smlaier		return (0);
6694171168Smlaier	if (m->m_pkthdr.csum_flags & flag_bad)
6695126258Smlaier		return (1);
6696126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6697126258Smlaier		return (1);
6698126258Smlaier	if (m->m_pkthdr.len < off + len)
6699126258Smlaier		return (1);
6700145836Smlaier	switch (af) {
6701145836Smlaier#ifdef INET
6702126258Smlaier	case AF_INET:
6703126258Smlaier		if (p == IPPROTO_ICMP) {
6704126258Smlaier			if (m->m_len < off)
6705126258Smlaier				return (1);
6706126258Smlaier			m->m_data += off;
6707126258Smlaier			m->m_len -= off;
6708126258Smlaier			sum = in_cksum(m, len);
6709126258Smlaier			m->m_data -= off;
6710126258Smlaier			m->m_len += off;
6711126258Smlaier		} else {
6712126258Smlaier			if (m->m_len < sizeof(struct ip))
6713126258Smlaier				return (1);
6714126258Smlaier			sum = in4_cksum(m, p, off, len);
6715126258Smlaier		}
6716126258Smlaier		break;
6717145836Smlaier#endif /* INET */
6718126258Smlaier#ifdef INET6
6719126258Smlaier	case AF_INET6:
6720126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6721126258Smlaier			return (1);
6722126258Smlaier		sum = in6_cksum(m, p, off, len);
6723126258Smlaier		break;
6724126258Smlaier#endif /* INET6 */
6725126258Smlaier	default:
6726126258Smlaier		return (1);
6727126258Smlaier	}
6728126258Smlaier	if (sum) {
6729171168Smlaier		m->m_pkthdr.csum_flags |= flag_bad;
6730126258Smlaier		switch (p) {
6731126258Smlaier		case IPPROTO_TCP:
6732181803Sbz			V_tcpstat.tcps_rcvbadsum++;
6733126258Smlaier			break;
6734126258Smlaier		case IPPROTO_UDP:
6735181803Sbz			V_udpstat.udps_badsum++;
6736126258Smlaier			break;
6737126258Smlaier		case IPPROTO_ICMP:
6738181803Sbz			V_icmpstat.icps_checksum++;
6739126258Smlaier			break;
6740126258Smlaier#ifdef INET6
6741126258Smlaier		case IPPROTO_ICMPV6:
6742181803Sbz			V_icmp6stat.icp6s_checksum++;
6743126258Smlaier			break;
6744126258Smlaier#endif /* INET6 */
6745126258Smlaier		}
6746126258Smlaier		return (1);
6747126258Smlaier	}
6748171168Smlaier	m->m_pkthdr.csum_flags |= flag_ok;
6749126258Smlaier	return (0);
6750126258Smlaier}
6751171168Smlaier#endif /* __FreeBSD__ */
6752126258Smlaier
6753126258Smlaier#ifdef INET
6754126258Smlaierint
6755135920Smlaier#ifdef __FreeBSD__
6756145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6757145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6758135920Smlaier#else
6759145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6760145836Smlaier    struct ether_header *eh)
6761135920Smlaier#endif
6762126258Smlaier{
6763130613Smlaier	struct pfi_kif		*kif;
6764130613Smlaier	u_short			 action, reason = 0, log = 0;
6765130613Smlaier	struct mbuf		*m = *m0;
6766130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6767130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6768130613Smlaier	struct pf_state		*s = NULL;
6769130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6770130613Smlaier	struct pf_pdesc		 pd;
6771130613Smlaier	int			 off, dirndx, pqid = 0;
6772126258Smlaier
6773127145Smlaier#ifdef __FreeBSD__
6774126261Smlaier	PF_LOCK();
6775126261Smlaier#endif
6776171168Smlaier	if (!pf_status.running)
6777127145Smlaier#ifdef __FreeBSD__
6778171168Smlaier	{
6779126261Smlaier		PF_UNLOCK();
6780126261Smlaier#endif
6781171168Smlaier		return (PF_PASS);
6782171168Smlaier#ifdef __FreeBSD__
6783126261Smlaier	}
6784171168Smlaier#endif
6785126258Smlaier
6786171168Smlaier	memset(&pd, 0, sizeof(pd));
6787171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
6788145836Smlaier#ifdef __FreeBSD__
6789171168Smlaier		PF_UNLOCK();
6790171168Smlaier#endif
6791171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6792171168Smlaier		    ("pf_test: pf_get_mtag returned NULL\n"));
6793171168Smlaier		return (PF_DROP);
6794171168Smlaier	}
6795171168Smlaier#ifdef __FreeBSD__
6796171168Smlaier	if (m->m_flags & M_SKIP_FIREWALL) {
6797171168Smlaier		PF_UNLOCK();
6798171168Smlaier		return (PF_PASS);
6799171168Smlaier	}
6800171168Smlaier#else
6801171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
6802171168Smlaier		return (PF_PASS);
6803171168Smlaier#endif
6804171168Smlaier
6805171168Smlaier#ifdef __FreeBSD__
6806145836Smlaier	/* XXX_IMPORT: later */
6807145836Smlaier#else
6808145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6809145836Smlaier		ifp = ifp->if_carpdev;
6810145836Smlaier#endif
6811145836Smlaier
6812171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
6813130613Smlaier	if (kif == NULL) {
6814130613Smlaier#ifdef __FreeBSD__
6815130613Smlaier		PF_UNLOCK();
6816130613Smlaier#endif
6817145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6818145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6819130613Smlaier		return (PF_DROP);
6820130613Smlaier	}
6821145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6822145836Smlaier#ifdef __FreeBSD__
6823145836Smlaier		PF_UNLOCK();
6824145836Smlaier#endif
6825145836Smlaier		return (PF_PASS);
6826145836Smlaier	}
6827130613Smlaier
6828130613Smlaier#ifdef __FreeBSD__
6829126261Smlaier	M_ASSERTPKTHDR(m);
6830126261Smlaier#else
6831126258Smlaier#ifdef DIAGNOSTIC
6832126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6833126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6834145836Smlaier#endif /* DIAGNOSTIC */
6835145836Smlaier#endif /* __FreeBSD__ */
6836126258Smlaier
6837126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6838126258Smlaier		action = PF_DROP;
6839126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6840126258Smlaier		log = 1;
6841126258Smlaier		goto done;
6842126258Smlaier	}
6843126258Smlaier
6844126258Smlaier	/* We do IP header normalization and packet reassembly here */
6845145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6846126258Smlaier		action = PF_DROP;
6847126258Smlaier		goto done;
6848126258Smlaier	}
6849126258Smlaier	m = *m0;
6850126258Smlaier	h = mtod(m, struct ip *);
6851126258Smlaier
6852126258Smlaier	off = h->ip_hl << 2;
6853126258Smlaier	if (off < (int)sizeof(*h)) {
6854126258Smlaier		action = PF_DROP;
6855126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6856126258Smlaier		log = 1;
6857126258Smlaier		goto done;
6858126258Smlaier	}
6859126258Smlaier
6860126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6861126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6862130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6863126258Smlaier	pd.ip_sum = &h->ip_sum;
6864126258Smlaier	pd.proto = h->ip_p;
6865126258Smlaier	pd.af = AF_INET;
6866126258Smlaier	pd.tos = h->ip_tos;
6867126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6868145836Smlaier	pd.eh = eh;
6869126258Smlaier
6870126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6871126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6872130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6873126258Smlaier		    &pd, &a, &ruleset);
6874126258Smlaier		goto done;
6875126258Smlaier	}
6876126258Smlaier
6877126258Smlaier	switch (h->ip_p) {
6878126258Smlaier
6879126258Smlaier	case IPPROTO_TCP: {
6880126258Smlaier		struct tcphdr	th;
6881126258Smlaier
6882126258Smlaier		pd.hdr.tcp = &th;
6883126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6884126258Smlaier		    &action, &reason, AF_INET)) {
6885126258Smlaier			log = action != PF_PASS;
6886126258Smlaier			goto done;
6887126258Smlaier		}
6888126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6889126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6890171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6891126258Smlaier			action = PF_DROP;
6892126258Smlaier			goto done;
6893126258Smlaier		}
6894126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6895126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6896126258Smlaier			pqid = 1;
6897130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6898126258Smlaier		if (action == PF_DROP)
6899130613Smlaier			goto done;
6900130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6901126258Smlaier		    &reason);
6902126258Smlaier		if (action == PF_PASS) {
6903130613Smlaier#if NPFSYNC
6904130613Smlaier			pfsync_update_state(s);
6905145836Smlaier#endif /* NPFSYNC */
6906126258Smlaier			r = s->rule.ptr;
6907130613Smlaier			a = s->anchor.ptr;
6908126258Smlaier			log = s->log;
6909126258Smlaier		} else if (s == NULL)
6910135920Smlaier#ifdef __FreeBSD__
6911130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6912145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6913135920Smlaier#else
6914135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6915145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6916135920Smlaier#endif
6917126258Smlaier		break;
6918126258Smlaier	}
6919126258Smlaier
6920126258Smlaier	case IPPROTO_UDP: {
6921126258Smlaier		struct udphdr	uh;
6922126258Smlaier
6923126258Smlaier		pd.hdr.udp = &uh;
6924126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6925126258Smlaier		    &action, &reason, AF_INET)) {
6926126258Smlaier			log = action != PF_PASS;
6927126258Smlaier			goto done;
6928126258Smlaier		}
6929126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6930126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6931126258Smlaier			action = PF_DROP;
6932171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6933126258Smlaier			goto done;
6934126258Smlaier		}
6935130613Smlaier		if (uh.uh_dport == 0 ||
6936130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6937130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6938130613Smlaier			action = PF_DROP;
6939171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
6940130613Smlaier			goto done;
6941130613Smlaier		}
6942130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6943126258Smlaier		if (action == PF_PASS) {
6944130613Smlaier#if NPFSYNC
6945130613Smlaier			pfsync_update_state(s);
6946145836Smlaier#endif /* NPFSYNC */
6947126258Smlaier			r = s->rule.ptr;
6948126258Smlaier			a = s->anchor.ptr;
6949126258Smlaier			log = s->log;
6950126258Smlaier		} else if (s == NULL)
6951135920Smlaier#ifdef __FreeBSD__
6952130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6953145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6954135920Smlaier#else
6955135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6956145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6957135920Smlaier#endif
6958126258Smlaier		break;
6959126258Smlaier	}
6960126258Smlaier
6961126258Smlaier	case IPPROTO_ICMP: {
6962126258Smlaier		struct icmp	ih;
6963126258Smlaier
6964126258Smlaier		pd.hdr.icmp = &ih;
6965126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6966126258Smlaier		    &action, &reason, AF_INET)) {
6967126258Smlaier			log = action != PF_PASS;
6968126258Smlaier			goto done;
6969126258Smlaier		}
6970126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6971126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6972126258Smlaier			action = PF_DROP;
6973171168Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6974126258Smlaier			goto done;
6975126258Smlaier		}
6976145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6977145836Smlaier		    &reason);
6978126258Smlaier		if (action == PF_PASS) {
6979130613Smlaier#if NPFSYNC
6980130613Smlaier			pfsync_update_state(s);
6981145836Smlaier#endif /* NPFSYNC */
6982126258Smlaier			r = s->rule.ptr;
6983126258Smlaier			a = s->anchor.ptr;
6984126258Smlaier			log = s->log;
6985126258Smlaier		} else if (s == NULL)
6986145836Smlaier#ifdef __FreeBSD__
6987130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6988145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6989145836Smlaier#else
6990145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6991145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6992145836Smlaier#endif
6993126258Smlaier		break;
6994126258Smlaier	}
6995126258Smlaier
6996126258Smlaier	default:
6997130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6998126258Smlaier		if (action == PF_PASS) {
6999130613Smlaier#if NPFSYNC
7000130613Smlaier			pfsync_update_state(s);
7001145836Smlaier#endif /* NPFSYNC */
7002126258Smlaier			r = s->rule.ptr;
7003126258Smlaier			a = s->anchor.ptr;
7004126258Smlaier			log = s->log;
7005126258Smlaier		} else if (s == NULL)
7006145836Smlaier#ifdef __FreeBSD__
7007130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7008145836Smlaier			    &pd, &a, &ruleset, NULL);
7009145836Smlaier#else
7010145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7011145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
7012145836Smlaier#endif
7013126258Smlaier		break;
7014126258Smlaier	}
7015126258Smlaier
7016126258Smlaierdone:
7017126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
7018126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
7019126258Smlaier		action = PF_DROP;
7020145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
7021126258Smlaier		log = 1;
7022126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
7023126258Smlaier		    ("pf: dropping packet with ip options\n"));
7024126258Smlaier	}
7025126258Smlaier
7026171168Smlaier	if ((s && s->tag) || r->rtableid)
7027171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7028145836Smlaier
7029126258Smlaier#ifdef ALTQ
7030126258Smlaier	if (action == PF_PASS && r->qid) {
7031171168Smlaier		if (pqid || (pd.tos & IPTOS_LOWDELAY))
7032171168Smlaier			pd.pf_mtag->qid = r->pqid;
7033171168Smlaier		else
7034171168Smlaier			pd.pf_mtag->qid = r->qid;
7035171168Smlaier		/* add hints for ecn */
7036171168Smlaier		pd.pf_mtag->af = AF_INET;
7037171168Smlaier		pd.pf_mtag->hdr = h;
7038126258Smlaier	}
7039145836Smlaier#endif /* ALTQ */
7040126258Smlaier
7041130613Smlaier	/*
7042130613Smlaier	 * connections redirected to loopback should not match sockets
7043130613Smlaier	 * bound specifically to loopback due to security implications,
7044130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
7045130613Smlaier	 */
7046130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7047130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7048130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7049130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7050171168Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
7051171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7052171168Smlaier
7053171168Smlaier	if (log) {
7054171168Smlaier		struct pf_rule *lr;
7055171168Smlaier
7056171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7057171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7058171168Smlaier			lr = s->nat_rule.ptr;
7059171168Smlaier		else
7060171168Smlaier			lr = r;
7061171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
7062171168Smlaier		    &pd);
7063130613Smlaier	}
7064130613Smlaier
7065130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7066130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
7067130613Smlaier
7068130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7069171168Smlaier		dirndx = (dir == PF_OUT);
7070171168Smlaier		r->packets[dirndx]++;
7071171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7072130613Smlaier		if (a != NULL) {
7073171168Smlaier			a->packets[dirndx]++;
7074171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7075130613Smlaier		}
7076130613Smlaier		if (s != NULL) {
7077130613Smlaier			if (s->nat_rule.ptr != NULL) {
7078171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7079171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7080130613Smlaier			}
7081130613Smlaier			if (s->src_node != NULL) {
7082171168Smlaier				s->src_node->packets[dirndx]++;
7083171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7084130613Smlaier			}
7085130613Smlaier			if (s->nat_src_node != NULL) {
7086171168Smlaier				s->nat_src_node->packets[dirndx]++;
7087171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7088130613Smlaier			}
7089171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7090171168Smlaier			s->packets[dirndx]++;
7091171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7092130613Smlaier		}
7093130613Smlaier		tr = r;
7094130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7095130613Smlaier		if (nr != NULL) {
7096130613Smlaier			struct pf_addr *x;
7097130613Smlaier			/*
7098130613Smlaier			 * XXX: we need to make sure that the addresses
7099130613Smlaier			 * passed to pfr_update_stats() are the same than
7100130613Smlaier			 * the addresses used during matching (pfr_match)
7101130613Smlaier			 */
7102130613Smlaier			if (r == &pf_default_rule) {
7103130613Smlaier				tr = nr;
7104130613Smlaier				x = (s == NULL || s->direction == dir) ?
7105130613Smlaier				    &pd.baddr : &pd.naddr;
7106130613Smlaier			} else
7107130613Smlaier				x = (s == NULL || s->direction == dir) ?
7108130613Smlaier				    &pd.naddr : &pd.baddr;
7109130613Smlaier			if (x == &pd.baddr || s == NULL) {
7110130613Smlaier				/* we need to change the address */
7111130613Smlaier				if (dir == PF_OUT)
7112130613Smlaier					pd.src = x;
7113130613Smlaier				else
7114130613Smlaier					pd.dst = x;
7115130613Smlaier			}
7116130613Smlaier		}
7117130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7118130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7119130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7120130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7121145836Smlaier			    tr->src.neg);
7122130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7123130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7124130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7125130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7126145836Smlaier			    tr->dst.neg);
7127130613Smlaier	}
7128130613Smlaier
7129130613Smlaier
7130126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7131126258Smlaier		m_freem(*m0);
7132126258Smlaier		*m0 = NULL;
7133126258Smlaier		action = PF_PASS;
7134126258Smlaier	} else if (r->rt)
7135126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
7136171168Smlaier		pf_route(m0, r, dir, ifp, s, &pd);
7137126258Smlaier
7138127145Smlaier#ifdef __FreeBSD__
7139126261Smlaier	PF_UNLOCK();
7140126261Smlaier#endif
7141126261Smlaier
7142126258Smlaier	return (action);
7143126258Smlaier}
7144126258Smlaier#endif /* INET */
7145126258Smlaier
7146126258Smlaier#ifdef INET6
7147126258Smlaierint
7148135920Smlaier#ifdef __FreeBSD__
7149145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7150145836Smlaier    struct ether_header *eh, struct inpcb *inp)
7151135920Smlaier#else
7152145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
7153145836Smlaier    struct ether_header *eh)
7154135920Smlaier#endif
7155126258Smlaier{
7156130613Smlaier	struct pfi_kif		*kif;
7157130613Smlaier	u_short			 action, reason = 0, log = 0;
7158171168Smlaier	struct mbuf		*m = *m0, *n = NULL;
7159171168Smlaier	struct ip6_hdr		*h;
7160130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
7161130613Smlaier	struct pf_state		*s = NULL;
7162130613Smlaier	struct pf_ruleset	*ruleset = NULL;
7163130613Smlaier	struct pf_pdesc		 pd;
7164169843Sdhartmei	int			 off, terminal = 0, dirndx, rh_cnt = 0;
7165126258Smlaier
7166127145Smlaier#ifdef __FreeBSD__
7167126261Smlaier	PF_LOCK();
7168126261Smlaier#endif
7169126261Smlaier
7170171168Smlaier	if (!pf_status.running)
7171127145Smlaier#ifdef __FreeBSD__
7172171168Smlaier	{
7173126261Smlaier		PF_UNLOCK();
7174126261Smlaier#endif
7175126258Smlaier		return (PF_PASS);
7176171168Smlaier#ifdef __FreeBSD__
7177126261Smlaier	}
7178171168Smlaier#endif
7179126258Smlaier
7180171168Smlaier	memset(&pd, 0, sizeof(pd));
7181171168Smlaier	if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) {
7182145836Smlaier#ifdef __FreeBSD__
7183171168Smlaier		PF_UNLOCK();
7184171168Smlaier#endif
7185171168Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7186171168Smlaier		    ("pf_test6: pf_get_mtag returned NULL\n"));
7187171168Smlaier		return (PF_DROP);
7188171168Smlaier	}
7189171168Smlaier	if (pd.pf_mtag->flags & PF_TAG_GENERATED)
7190171168Smlaier		return (PF_PASS);
7191171168Smlaier
7192171168Smlaier#ifdef __FreeBSD__
7193145836Smlaier	/* XXX_IMPORT: later */
7194145836Smlaier#else
7195145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
7196145836Smlaier		ifp = ifp->if_carpdev;
7197145836Smlaier#endif
7198145836Smlaier
7199171168Smlaier	kif = (struct pfi_kif *)ifp->if_pf_kif;
7200130613Smlaier	if (kif == NULL) {
7201130613Smlaier#ifdef __FreeBSD__
7202130613Smlaier		PF_UNLOCK();
7203130613Smlaier#endif
7204145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
7205145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
7206130613Smlaier		return (PF_DROP);
7207130613Smlaier	}
7208145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
7209145836Smlaier#ifdef __FreeBSD__
7210145836Smlaier		PF_UNLOCK();
7211145836Smlaier#endif
7212145836Smlaier		return (PF_PASS);
7213145836Smlaier	}
7214130613Smlaier
7215130613Smlaier#ifdef __FreeBSD__
7216126261Smlaier	M_ASSERTPKTHDR(m);
7217126261Smlaier#else
7218126258Smlaier#ifdef DIAGNOSTIC
7219126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
7220145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
7221145836Smlaier#endif /* DIAGNOSTIC */
7222126258Smlaier#endif
7223126258Smlaier
7224171168Smlaier#ifdef __FreeBSD__
7225171168Smlaier	h = NULL;	/* make the compiler happy */
7226171168Smlaier#endif
7227171168Smlaier
7228126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
7229126258Smlaier		action = PF_DROP;
7230126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
7231126258Smlaier		log = 1;
7232126258Smlaier		goto done;
7233126258Smlaier	}
7234126258Smlaier
7235126258Smlaier	/* We do IP header normalization and packet reassembly here */
7236145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
7237126258Smlaier		action = PF_DROP;
7238126258Smlaier		goto done;
7239126258Smlaier	}
7240126258Smlaier	m = *m0;
7241126258Smlaier	h = mtod(m, struct ip6_hdr *);
7242126258Smlaier
7243169843Sdhartmei#if 1
7244169843Sdhartmei	/*
7245169843Sdhartmei	 * we do not support jumbogram yet.  if we keep going, zero ip6_plen
7246169843Sdhartmei	 * will do something bad, so drop the packet for now.
7247169843Sdhartmei	 */
7248169843Sdhartmei	if (htons(h->ip6_plen) == 0) {
7249169843Sdhartmei		action = PF_DROP;
7250169843Sdhartmei		REASON_SET(&reason, PFRES_NORM);	/*XXX*/
7251169843Sdhartmei		goto done;
7252169843Sdhartmei	}
7253169843Sdhartmei#endif
7254169843Sdhartmei
7255126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
7256126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
7257130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
7258126258Smlaier	pd.ip_sum = NULL;
7259126258Smlaier	pd.af = AF_INET6;
7260126258Smlaier	pd.tos = 0;
7261126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
7262145836Smlaier	pd.eh = eh;
7263126258Smlaier
7264126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
7265126258Smlaier	pd.proto = h->ip6_nxt;
7266126258Smlaier	do {
7267126258Smlaier		switch (pd.proto) {
7268126258Smlaier		case IPPROTO_FRAGMENT:
7269130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
7270126258Smlaier			    &pd, &a, &ruleset);
7271126258Smlaier			if (action == PF_DROP)
7272126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
7273126258Smlaier			goto done;
7274169843Sdhartmei		case IPPROTO_ROUTING: {
7275169843Sdhartmei			struct ip6_rthdr rthdr;
7276169843Sdhartmei
7277169843Sdhartmei			if (rh_cnt++) {
7278169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7279169843Sdhartmei				    ("pf: IPv6 more than one rthdr\n"));
7280169843Sdhartmei				action = PF_DROP;
7281169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7282169843Sdhartmei				log = 1;
7283169843Sdhartmei				goto done;
7284169843Sdhartmei			}
7285169843Sdhartmei			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
7286169843Sdhartmei			    &reason, pd.af)) {
7287169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7288169843Sdhartmei				    ("pf: IPv6 short rthdr\n"));
7289169843Sdhartmei				action = PF_DROP;
7290169843Sdhartmei				REASON_SET(&reason, PFRES_SHORT);
7291169843Sdhartmei				log = 1;
7292169843Sdhartmei				goto done;
7293169843Sdhartmei			}
7294169843Sdhartmei			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
7295169843Sdhartmei				DPFPRINTF(PF_DEBUG_MISC,
7296169843Sdhartmei				    ("pf: IPv6 rthdr0\n"));
7297169843Sdhartmei				action = PF_DROP;
7298169843Sdhartmei				REASON_SET(&reason, PFRES_IPOPTIONS);
7299169843Sdhartmei				log = 1;
7300169843Sdhartmei				goto done;
7301169843Sdhartmei			}
7302169843Sdhartmei			/* fallthrough */
7303169843Sdhartmei		}
7304126258Smlaier		case IPPROTO_AH:
7305126258Smlaier		case IPPROTO_HOPOPTS:
7306126258Smlaier		case IPPROTO_DSTOPTS: {
7307126258Smlaier			/* get next header and header length */
7308126258Smlaier			struct ip6_ext	opt6;
7309126258Smlaier
7310126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
7311145836Smlaier			    NULL, &reason, pd.af)) {
7312126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
7313126258Smlaier				    ("pf: IPv6 short opt\n"));
7314126258Smlaier				action = PF_DROP;
7315126258Smlaier				log = 1;
7316126258Smlaier				goto done;
7317126258Smlaier			}
7318126258Smlaier			if (pd.proto == IPPROTO_AH)
7319126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
7320126258Smlaier			else
7321126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
7322126258Smlaier			pd.proto = opt6.ip6e_nxt;
7323126258Smlaier			/* goto the next header */
7324126258Smlaier			break;
7325126258Smlaier		}
7326126258Smlaier		default:
7327126258Smlaier			terminal++;
7328126258Smlaier			break;
7329126258Smlaier		}
7330126258Smlaier	} while (!terminal);
7331126258Smlaier
7332171168Smlaier	/* if there's no routing header, use unmodified mbuf for checksumming */
7333171168Smlaier	if (!n)
7334171168Smlaier		n = m;
7335171168Smlaier
7336126258Smlaier	switch (pd.proto) {
7337126258Smlaier
7338126258Smlaier	case IPPROTO_TCP: {
7339126258Smlaier		struct tcphdr	th;
7340126258Smlaier
7341126258Smlaier		pd.hdr.tcp = &th;
7342126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
7343126258Smlaier		    &action, &reason, AF_INET6)) {
7344126258Smlaier			log = action != PF_PASS;
7345126258Smlaier			goto done;
7346126258Smlaier		}
7347171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7348138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7349138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
7350126258Smlaier			action = PF_DROP;
7351145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7352126258Smlaier			goto done;
7353126258Smlaier		}
7354126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
7355130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
7356126258Smlaier		if (action == PF_DROP)
7357130613Smlaier			goto done;
7358130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
7359126258Smlaier		    &reason);
7360126258Smlaier		if (action == PF_PASS) {
7361130613Smlaier#if NPFSYNC
7362130613Smlaier			pfsync_update_state(s);
7363145836Smlaier#endif /* NPFSYNC */
7364126258Smlaier			r = s->rule.ptr;
7365130613Smlaier			a = s->anchor.ptr;
7366126258Smlaier			log = s->log;
7367126258Smlaier		} else if (s == NULL)
7368135920Smlaier#ifdef __FreeBSD__
7369130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7370145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7371135920Smlaier#else
7372135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
7373145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7374135920Smlaier#endif
7375126258Smlaier		break;
7376126258Smlaier	}
7377126258Smlaier
7378126258Smlaier	case IPPROTO_UDP: {
7379126258Smlaier		struct udphdr	uh;
7380126258Smlaier
7381126258Smlaier		pd.hdr.udp = &uh;
7382126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
7383126258Smlaier		    &action, &reason, AF_INET6)) {
7384126258Smlaier			log = action != PF_PASS;
7385126258Smlaier			goto done;
7386126258Smlaier		}
7387171168Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n,
7388138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7389138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
7390126258Smlaier			action = PF_DROP;
7391145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7392126258Smlaier			goto done;
7393126258Smlaier		}
7394130613Smlaier		if (uh.uh_dport == 0 ||
7395130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
7396130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
7397130613Smlaier			action = PF_DROP;
7398171168Smlaier			REASON_SET(&reason, PFRES_SHORT);
7399130613Smlaier			goto done;
7400130613Smlaier		}
7401130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
7402126258Smlaier		if (action == PF_PASS) {
7403130613Smlaier#if NPFSYNC
7404130613Smlaier			pfsync_update_state(s);
7405145836Smlaier#endif /* NPFSYNC */
7406126258Smlaier			r = s->rule.ptr;
7407130613Smlaier			a = s->anchor.ptr;
7408126258Smlaier			log = s->log;
7409126258Smlaier		} else if (s == NULL)
7410135920Smlaier#ifdef __FreeBSD__
7411130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7412145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
7413135920Smlaier#else
7414135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
7415145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7416135920Smlaier#endif
7417126258Smlaier		break;
7418126258Smlaier	}
7419126258Smlaier
7420126258Smlaier	case IPPROTO_ICMPV6: {
7421126258Smlaier		struct icmp6_hdr	ih;
7422126258Smlaier
7423126258Smlaier		pd.hdr.icmp6 = &ih;
7424126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
7425126258Smlaier		    &action, &reason, AF_INET6)) {
7426126258Smlaier			log = action != PF_PASS;
7427126258Smlaier			goto done;
7428126258Smlaier		}
7429171168Smlaier		if (dir == PF_IN && pf_check_proto_cksum(n, off,
7430145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
7431138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
7432126258Smlaier			action = PF_DROP;
7433145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
7434126258Smlaier			goto done;
7435126258Smlaier		}
7436130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
7437145836Smlaier		    m, off, h, &pd, &reason);
7438126258Smlaier		if (action == PF_PASS) {
7439130613Smlaier#if NPFSYNC
7440130613Smlaier			pfsync_update_state(s);
7441145836Smlaier#endif /* NPFSYNC */
7442126258Smlaier			r = s->rule.ptr;
7443130613Smlaier			a = s->anchor.ptr;
7444126258Smlaier			log = s->log;
7445126258Smlaier		} else if (s == NULL)
7446145836Smlaier#ifdef __FreeBSD__
7447130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7448145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
7449145836Smlaier#else
7450145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
7451145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
7452145836Smlaier#endif
7453126258Smlaier		break;
7454126258Smlaier	}
7455126258Smlaier
7456126258Smlaier	default:
7457130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
7458130613Smlaier		if (action == PF_PASS) {
7459145836Smlaier#if NPFSYNC
7460145836Smlaier			pfsync_update_state(s);
7461145836Smlaier#endif /* NPFSYNC */
7462130613Smlaier			r = s->rule.ptr;
7463130613Smlaier			a = s->anchor.ptr;
7464130613Smlaier			log = s->log;
7465130613Smlaier		} else if (s == NULL)
7466145836Smlaier#ifdef __FreeBSD__
7467130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7468145836Smlaier			    &pd, &a, &ruleset, NULL);
7469145836Smlaier#else
7470145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7471145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
7472145836Smlaier#endif
7473126258Smlaier		break;
7474126258Smlaier	}
7475126258Smlaier
7476126258Smlaierdone:
7477169843Sdhartmei	/* handle dangerous IPv6 extension headers. */
7478169843Sdhartmei	if (action == PF_PASS && rh_cnt &&
7479169843Sdhartmei	    !((s && s->allow_opts) || r->allow_opts)) {
7480169843Sdhartmei		action = PF_DROP;
7481169843Sdhartmei		REASON_SET(&reason, PFRES_IPOPTIONS);
7482169843Sdhartmei		log = 1;
7483169843Sdhartmei		DPFPRINTF(PF_DEBUG_MISC,
7484169843Sdhartmei		    ("pf: dropping packet with dangerous v6 headers\n"));
7485169843Sdhartmei	}
7486126258Smlaier
7487171168Smlaier	if ((s && s->tag) || r->rtableid)
7488171168Smlaier		pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid);
7489145836Smlaier
7490126258Smlaier#ifdef ALTQ
7491126258Smlaier	if (action == PF_PASS && r->qid) {
7492171168Smlaier		if (pd.tos & IPTOS_LOWDELAY)
7493171168Smlaier			pd.pf_mtag->qid = r->pqid;
7494171168Smlaier		else
7495171168Smlaier			pd.pf_mtag->qid = r->qid;
7496171168Smlaier		/* add hints for ecn */
7497171168Smlaier		pd.pf_mtag->af = AF_INET6;
7498171168Smlaier		pd.pf_mtag->hdr = h;
7499126258Smlaier	}
7500145836Smlaier#endif /* ALTQ */
7501126258Smlaier
7502130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7503130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7504130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7505130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7506171168Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
7507171168Smlaier		pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST;
7508171168Smlaier
7509171168Smlaier	if (log) {
7510171168Smlaier		struct pf_rule *lr;
7511171168Smlaier
7512171168Smlaier		if (s != NULL && s->nat_rule.ptr != NULL &&
7513171168Smlaier		    s->nat_rule.ptr->log & PF_LOG_ALL)
7514171168Smlaier			lr = s->nat_rule.ptr;
7515171168Smlaier		else
7516171168Smlaier			lr = r;
7517171168Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
7518171168Smlaier		    &pd);
7519130613Smlaier	}
7520130613Smlaier
7521130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7522130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7523130613Smlaier
7524130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7525171168Smlaier		dirndx = (dir == PF_OUT);
7526171168Smlaier		r->packets[dirndx]++;
7527171168Smlaier		r->bytes[dirndx] += pd.tot_len;
7528130613Smlaier		if (a != NULL) {
7529171168Smlaier			a->packets[dirndx]++;
7530171168Smlaier			a->bytes[dirndx] += pd.tot_len;
7531130613Smlaier		}
7532130613Smlaier		if (s != NULL) {
7533130613Smlaier			if (s->nat_rule.ptr != NULL) {
7534171168Smlaier				s->nat_rule.ptr->packets[dirndx]++;
7535171168Smlaier				s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
7536130613Smlaier			}
7537130613Smlaier			if (s->src_node != NULL) {
7538171168Smlaier				s->src_node->packets[dirndx]++;
7539171168Smlaier				s->src_node->bytes[dirndx] += pd.tot_len;
7540130613Smlaier			}
7541130613Smlaier			if (s->nat_src_node != NULL) {
7542171168Smlaier				s->nat_src_node->packets[dirndx]++;
7543171168Smlaier				s->nat_src_node->bytes[dirndx] += pd.tot_len;
7544130613Smlaier			}
7545171168Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7546171168Smlaier			s->packets[dirndx]++;
7547171168Smlaier			s->bytes[dirndx] += pd.tot_len;
7548130613Smlaier		}
7549130613Smlaier		tr = r;
7550130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7551130613Smlaier		if (nr != NULL) {
7552130613Smlaier			struct pf_addr *x;
7553130613Smlaier			/*
7554130613Smlaier			 * XXX: we need to make sure that the addresses
7555130613Smlaier			 * passed to pfr_update_stats() are the same than
7556130613Smlaier			 * the addresses used during matching (pfr_match)
7557130613Smlaier			 */
7558130613Smlaier			if (r == &pf_default_rule) {
7559130613Smlaier				tr = nr;
7560130613Smlaier				x = (s == NULL || s->direction == dir) ?
7561130613Smlaier				    &pd.baddr : &pd.naddr;
7562130613Smlaier			} else {
7563130613Smlaier				x = (s == NULL || s->direction == dir) ?
7564130613Smlaier				    &pd.naddr : &pd.baddr;
7565130613Smlaier			}
7566130613Smlaier			if (x == &pd.baddr || s == NULL) {
7567130613Smlaier				if (dir == PF_OUT)
7568130613Smlaier					pd.src = x;
7569130613Smlaier				else
7570130613Smlaier					pd.dst = x;
7571130613Smlaier			}
7572130613Smlaier		}
7573130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7574130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7575130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7576130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7577145836Smlaier			    tr->src.neg);
7578130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7579130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7580130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7581130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7582145836Smlaier			    tr->dst.neg);
7583130613Smlaier	}
7584130613Smlaier
7585130613Smlaier
7586126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7587126258Smlaier		m_freem(*m0);
7588126258Smlaier		*m0 = NULL;
7589126258Smlaier		action = PF_PASS;
7590126258Smlaier	} else if (r->rt)
7591126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7592171168Smlaier		pf_route6(m0, r, dir, ifp, s, &pd);
7593126258Smlaier
7594127145Smlaier#ifdef __FreeBSD__
7595126261Smlaier	PF_UNLOCK();
7596126261Smlaier#endif
7597126258Smlaier	return (action);
7598126258Smlaier}
7599126258Smlaier#endif /* INET6 */
7600145836Smlaier
7601145836Smlaierint
7602145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7603145836Smlaier{
7604145836Smlaier#ifdef __FreeBSD__
7605145836Smlaier	/* XXX_IMPORT: later */
7606145836Smlaier	return (0);
7607145836Smlaier#else
7608145836Smlaier	if (ifq->ifq_congestion)
7609145836Smlaier		return (1);
7610145836Smlaier	else
7611145836Smlaier		return (0);
7612145836Smlaier#endif
7613145836Smlaier}
7614