pf.c revision 135920
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf.c 135920 2004-09-29 04:54:33Z mlaier $	*/
2132303Smlaier/*	$OpenBSD: pf.c,v 1.433.2.2 2004/07/17 03:22:34 brad Exp $ */
3133574Smlaier/* add	$OpenBSD: pf.c,v 1.448 2004/05/11 07:34:11 dhartmei Exp $ */
4126258Smlaier
5126258Smlaier/*
6126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
7130613Smlaier * Copyright (c) 2002,2003 Henning Brauer
8126258Smlaier * All rights reserved.
9126258Smlaier *
10126258Smlaier * Redistribution and use in source and binary forms, with or without
11126258Smlaier * modification, are permitted provided that the following conditions
12126258Smlaier * are met:
13126258Smlaier *
14126258Smlaier *    - Redistributions of source code must retain the above copyright
15126258Smlaier *      notice, this list of conditions and the following disclaimer.
16126258Smlaier *    - Redistributions in binary form must reproduce the above
17126258Smlaier *      copyright notice, this list of conditions and the following
18126258Smlaier *      disclaimer in the documentation and/or other materials provided
19126258Smlaier *      with the distribution.
20126258Smlaier *
21126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
33126258Smlaier *
34126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
35126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
36126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
37126258Smlaier *
38126258Smlaier */
39126258Smlaier
40127145Smlaier#ifdef __FreeBSD__
41126261Smlaier#include "opt_inet.h"
42126261Smlaier#include "opt_inet6.h"
43126261Smlaier#endif
44126261Smlaier
45127145Smlaier#ifdef __FreeBSD__
46126261Smlaier#include "opt_bpf.h"
47126261Smlaier#include "opt_pf.h"
48127145Smlaier#define	NBPFILTER	DEV_BPF
49127145Smlaier#define	NPFLOG		DEV_PFLOG
50127145Smlaier#define	NPFSYNC		DEV_PFSYNC
51126261Smlaier#else
52126258Smlaier#include "bpfilter.h"
53126258Smlaier#include "pflog.h"
54126258Smlaier#include "pfsync.h"
55126261Smlaier#endif
56126258Smlaier
57126258Smlaier#include <sys/param.h>
58126258Smlaier#include <sys/systm.h>
59126258Smlaier#include <sys/mbuf.h>
60126258Smlaier#include <sys/filio.h>
61126258Smlaier#include <sys/socket.h>
62126258Smlaier#include <sys/socketvar.h>
63126258Smlaier#include <sys/kernel.h>
64126258Smlaier#include <sys/time.h>
65127145Smlaier#ifdef __FreeBSD__
66126261Smlaier#include <sys/sysctl.h>
67130613Smlaier#include <sys/endian.h>
68126261Smlaier#else
69126258Smlaier#include <sys/pool.h>
70126261Smlaier#endif
71126258Smlaier
72126258Smlaier#include <net/if.h>
73126258Smlaier#include <net/if_types.h>
74126258Smlaier#include <net/bpf.h>
75126258Smlaier#include <net/route.h>
76126258Smlaier
77126258Smlaier#include <netinet/in.h>
78126258Smlaier#include <netinet/in_var.h>
79126258Smlaier#include <netinet/in_systm.h>
80126258Smlaier#include <netinet/ip.h>
81126258Smlaier#include <netinet/ip_var.h>
82126258Smlaier#include <netinet/tcp.h>
83126258Smlaier#include <netinet/tcp_seq.h>
84126258Smlaier#include <netinet/udp.h>
85126258Smlaier#include <netinet/ip_icmp.h>
86126258Smlaier#include <netinet/in_pcb.h>
87126258Smlaier#include <netinet/tcp_timer.h>
88126258Smlaier#include <netinet/tcp_var.h>
89126258Smlaier#include <netinet/udp_var.h>
90126258Smlaier#include <netinet/icmp_var.h>
91126258Smlaier
92127145Smlaier#ifndef __FreeBSD__
93126258Smlaier#include <dev/rndvar.h>
94126261Smlaier#endif
95126258Smlaier#include <net/pfvar.h>
96126258Smlaier#include <net/if_pflog.h>
97130613Smlaier
98130613Smlaier#if NPFSYNC > 0
99126258Smlaier#include <net/if_pfsync.h>
100130613Smlaier#endif /* NPFSYNC > 0 */
101126258Smlaier
102126258Smlaier#ifdef INET6
103126258Smlaier#include <netinet/ip6.h>
104126258Smlaier#include <netinet/in_pcb.h>
105126258Smlaier#include <netinet/icmp6.h>
106126258Smlaier#include <netinet6/nd6.h>
107127145Smlaier#ifdef __FreeBSD__
108126261Smlaier#include <netinet6/ip6_var.h>
109126261Smlaier#include <netinet6/in6_pcb.h>
110126261Smlaier#endif
111126258Smlaier#endif /* INET6 */
112126258Smlaier
113127145Smlaier#ifdef __FreeBSD__
114126261Smlaier#include <machine/in_cksum.h>
115126261Smlaier#include <sys/limits.h>
116126261Smlaier#include <sys/ucred.h>
117126258Smlaier
118126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
119126261Smlaier#endif
120126261Smlaier
121126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
122126258Smlaier
123126258Smlaier/*
124126258Smlaier * Global variables
125126258Smlaier */
126126258Smlaier
127126258Smlaierstruct pf_anchorqueue	 pf_anchors;
128126258Smlaierstruct pf_ruleset	 pf_main_ruleset;
129126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
130126258Smlaierstruct pf_palist	 pf_pabuf;
131126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
132126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
133126258Smlaierstruct pf_status	 pf_status;
134126258Smlaier
135126258Smlaieru_int32_t		 ticket_altqs_active;
136126258Smlaieru_int32_t		 ticket_altqs_inactive;
137130613Smlaierint			 altqs_inactive_open;
138126258Smlaieru_int32_t		 ticket_pabuf;
139126258Smlaier
140127145Smlaier#ifdef __FreeBSD__
141126261Smlaierstruct callout	 	 pf_expire_to;			/* expire timeout */
142126261Smlaier#else
143126258Smlaierstruct timeout		 pf_expire_to;			/* expire timeout */
144126261Smlaier#endif
145126258Smlaier
146126261Smlaier
147127145Smlaier#ifdef __FreeBSD__
148130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
149126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
150126261Smlaier#else
151130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
152126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
153126261Smlaier#endif
154126258Smlaier
155126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
156126258Smlaiervoid			 pf_print_state(struct pf_state *);
157126258Smlaiervoid			 pf_print_flags(u_int8_t);
158126258Smlaier
159126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
160126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
161126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
162126258Smlaier#ifdef INET6
163126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
164126258Smlaier			    struct pf_addr *, u_int8_t);
165126258Smlaier#endif /* INET6 */
166126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
167126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
168126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
169126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
170126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
171126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
172126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
173126258Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t);
174126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
175126258Smlaier			    sa_family_t, struct pf_rule *);
176126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
177130613Smlaier			    int, int, struct pfi_kif *,
178126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
179126258Smlaier			    u_int16_t, int);
180126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
181130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
182126258Smlaier			    struct pf_addr *, u_int16_t,
183126258Smlaier			    struct pf_addr *, u_int16_t,
184126258Smlaier			    struct pf_addr *, u_int16_t *);
185126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
186130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
187126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
188135920Smlaier#ifdef __FreeBSD__
189135920Smlaier			    struct pf_ruleset **, struct inpcb *);
190135920Smlaier#else
191126258Smlaier			    struct pf_ruleset **);
192135920Smlaier#endif
193126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
194130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
195126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
196135920Smlaier#ifdef __FreeBSD__
197135920Smlaier			    struct pf_ruleset **, struct inpcb *);
198135920Smlaier#else
199126258Smlaier			    struct pf_ruleset **);
200135920Smlaier#endif
201126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
202130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
203126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
204126258Smlaier			    struct pf_ruleset **);
205126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
206130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
207126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
208126258Smlaier			    struct pf_ruleset **);
209126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
210130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
211126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
212126258Smlaier			    struct pf_ruleset **);
213126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
214130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
215126258Smlaier			    void *, struct pf_pdesc *, u_short *);
216126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
217130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
218126258Smlaier			    void *, struct pf_pdesc *);
219126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
220130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
221126258Smlaier			    void *, struct pf_pdesc *);
222126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
223130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
224126258Smlaierstruct pf_tag		*pf_get_tag(struct mbuf *);
225126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
226130613Smlaier			     struct pf_rule *, struct pf_tag *, int *);
227126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
228126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
229130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
230126258Smlaier			    struct pf_addr *, struct pf_addr *,
231130613Smlaier			    struct pf_addr *, struct pf_src_node **);
232130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
233126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
234130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
235130613Smlaier			    struct pf_src_node **);
236126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
237126258Smlaier			    struct ifnet *, struct pf_state *);
238126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
239126258Smlaier			    struct ifnet *, struct pf_state *);
240135920Smlaier#ifdef __FreeBSD__
241130613Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
242135920Smlaier			    int, struct pf_pdesc *, struct inpcb *);
243135920Smlaier#else
244135920Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
245126258Smlaier			    int, struct pf_pdesc *);
246135920Smlaier#endif
247126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
248126258Smlaier			    sa_family_t);
249126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
250126258Smlaier			    sa_family_t);
251126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
252126258Smlaier				u_int16_t);
253126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
254126258Smlaier			    struct pf_addr *);
255126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
256126258Smlaier			    u_int8_t, sa_family_t);
257126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
258126258Smlaier			    struct pf_addr_wrap *);
259130613Smlaierstatic int		 pf_add_mbuf_tag(struct mbuf *, u_int);
260130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
261130613Smlaier			    struct pf_state *, u_int8_t);
262126258Smlaier
263127145Smlaier#ifdef __FreeBSD__
264126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
265126258Smlaier
266126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
267126261Smlaier#else
268130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
269130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
270130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
271130613Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT }
272130613Smlaier};
273126261Smlaier#endif
274126258Smlaier
275126258Smlaier#define STATE_LOOKUP()							\
276126258Smlaier	do {								\
277126258Smlaier		if (direction == PF_IN)					\
278130613Smlaier			*state = pf_find_state_recurse(		\
279130613Smlaier			    kif, &key, PF_EXT_GWY);			\
280126258Smlaier		else							\
281130613Smlaier			*state = pf_find_state_recurse(		\
282130613Smlaier			    kif, &key, PF_LAN_EXT);			\
283126258Smlaier		if (*state == NULL)					\
284126258Smlaier			return (PF_DROP);				\
285126258Smlaier		if (direction == PF_OUT &&				\
286126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
287126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
288126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
289126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
290130613Smlaier		    (*state)->rt_kif != NULL &&				\
291130613Smlaier		    (*state)->rt_kif != kif)				\
292126258Smlaier			return (PF_PASS);				\
293126258Smlaier	} while (0)
294126258Smlaier
295126258Smlaier#define	STATE_TRANSLATE(s) \
296126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
297126258Smlaier	((s)->af == AF_INET6 && \
298126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
299126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
300126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
301126258Smlaier	(s)->lan.port != (s)->gwy.port
302126258Smlaier
303130613Smlaier#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) :   \
304130613Smlaier	((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent :	       \
305130613Smlaier	(k)->pfik_parent->pfik_parent)
306126258Smlaier
307132767Skan#ifndef __FreeBSD__
308130613Smlaierstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
309130613Smlaierstatic __inline int pf_state_compare_lan_ext(struct pf_state *,
310130613Smlaier	struct pf_state *);
311130613Smlaierstatic __inline int pf_state_compare_ext_gwy(struct pf_state *,
312130613Smlaier	struct pf_state *);
313130613Smlaierstatic __inline int pf_state_compare_id(struct pf_state *,
314130613Smlaier	struct pf_state *);
315132767Skan#else
316132767Skanstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
317132767Skanstatic int pf_state_compare_lan_ext(struct pf_state *,
318132767Skan	struct pf_state *);
319132767Skanstatic int pf_state_compare_ext_gwy(struct pf_state *,
320132767Skan	struct pf_state *);
321132767Skanstatic int pf_state_compare_id(struct pf_state *,
322132767Skan	struct pf_state *);
323132767Skan#endif
324126258Smlaier
325130613Smlaierstruct pf_src_tree tree_src_tracking;
326130613Smlaier
327130613Smlaierstruct pf_state_tree_id tree_id;
328130613Smlaierstruct pf_state_queue state_updates;
329130613Smlaier
330130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
331130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
332130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
333130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
334130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
335130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
336130613Smlaier    u.s.entry_id, pf_state_compare_id);
337130613Smlaier
338127145Smlaier#ifdef __FreeBSD__
339126409Smlaierstatic int
340126409Smlaier#else
341126258Smlaierstatic __inline int
342126409Smlaier#endif
343130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
344126258Smlaier{
345126258Smlaier	int	diff;
346126258Smlaier
347130613Smlaier	if (a->rule.ptr > b->rule.ptr)
348130613Smlaier		return (1);
349130613Smlaier	if (a->rule.ptr < b->rule.ptr)
350130613Smlaier		return (-1);
351130613Smlaier	if ((diff = a->af - b->af) != 0)
352130613Smlaier		return (diff);
353130613Smlaier	switch (a->af) {
354130613Smlaier#ifdef INET
355130613Smlaier	case AF_INET:
356130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
357130613Smlaier			return (1);
358130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
359130613Smlaier			return (-1);
360130613Smlaier		break;
361130613Smlaier#endif /* INET */
362130613Smlaier#ifdef INET6
363130613Smlaier	case AF_INET6:
364130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
365130613Smlaier			return (1);
366130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
367130613Smlaier			return (-1);
368130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
369130613Smlaier			return (1);
370130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
371130613Smlaier			return (-1);
372130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
373130613Smlaier			return (1);
374130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
375130613Smlaier			return (-1);
376130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
377130613Smlaier			return (1);
378130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
379130613Smlaier			return (-1);
380130613Smlaier		break;
381130613Smlaier#endif /* INET6 */
382130613Smlaier	}
383130613Smlaier	return (0);
384130613Smlaier}
385130613Smlaier
386130613Smlaier#ifdef __FreeBSD__
387130613Smlaierstatic int
388130613Smlaier#else
389130613Smlaierstatic __inline int
390130613Smlaier#endif
391130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
392130613Smlaier{
393130613Smlaier	int	diff;
394130613Smlaier
395126258Smlaier	if ((diff = a->proto - b->proto) != 0)
396126258Smlaier		return (diff);
397126258Smlaier	if ((diff = a->af - b->af) != 0)
398126258Smlaier		return (diff);
399126258Smlaier	switch (a->af) {
400126258Smlaier#ifdef INET
401126258Smlaier	case AF_INET:
402130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
403126258Smlaier			return (1);
404130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
405126258Smlaier			return (-1);
406130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
407126258Smlaier			return (1);
408130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
409126258Smlaier			return (-1);
410126258Smlaier		break;
411126258Smlaier#endif /* INET */
412126258Smlaier#ifdef INET6
413126258Smlaier	case AF_INET6:
414130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
415126258Smlaier			return (1);
416130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
417126258Smlaier			return (-1);
418130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
419126258Smlaier			return (1);
420130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
421126258Smlaier			return (-1);
422130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
423126258Smlaier			return (1);
424130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
425126258Smlaier			return (-1);
426130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
427126258Smlaier			return (1);
428130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
429126258Smlaier			return (-1);
430130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
431126258Smlaier			return (1);
432130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
433126258Smlaier			return (-1);
434130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
435126258Smlaier			return (1);
436130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
437126258Smlaier			return (-1);
438130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
439126258Smlaier			return (1);
440130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
441126258Smlaier			return (-1);
442130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
443126258Smlaier			return (1);
444130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
445126258Smlaier			return (-1);
446126258Smlaier		break;
447126258Smlaier#endif /* INET6 */
448126258Smlaier	}
449126258Smlaier
450130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
451126258Smlaier		return (diff);
452130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
453126258Smlaier		return (diff);
454126258Smlaier
455126258Smlaier	return (0);
456126258Smlaier}
457126258Smlaier
458130613Smlaier#ifdef __FreeBSD__
459130613Smlaierstatic int
460130613Smlaier#else
461130613Smlaierstatic __inline int
462130613Smlaier#endif
463130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
464130613Smlaier{
465130613Smlaier	int	diff;
466130613Smlaier
467130613Smlaier	if ((diff = a->proto - b->proto) != 0)
468130613Smlaier		return (diff);
469130613Smlaier	if ((diff = a->af - b->af) != 0)
470130613Smlaier		return (diff);
471130613Smlaier	switch (a->af) {
472130613Smlaier#ifdef INET
473130613Smlaier	case AF_INET:
474130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
475130613Smlaier			return (1);
476130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
477130613Smlaier			return (-1);
478130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
479130613Smlaier			return (1);
480130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
481130613Smlaier			return (-1);
482130613Smlaier		break;
483130613Smlaier#endif /* INET */
484126258Smlaier#ifdef INET6
485130613Smlaier	case AF_INET6:
486130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
487130613Smlaier			return (1);
488130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
489130613Smlaier			return (-1);
490130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
491130613Smlaier			return (1);
492130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
493130613Smlaier			return (-1);
494130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
495130613Smlaier			return (1);
496130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
497130613Smlaier			return (-1);
498130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
499130613Smlaier			return (1);
500130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
501130613Smlaier			return (-1);
502130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
503130613Smlaier			return (1);
504130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
505130613Smlaier			return (-1);
506130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
507130613Smlaier			return (1);
508130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
509130613Smlaier			return (-1);
510130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
511130613Smlaier			return (1);
512130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
513130613Smlaier			return (-1);
514130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
515130613Smlaier			return (1);
516130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
517130613Smlaier			return (-1);
518130613Smlaier		break;
519130613Smlaier#endif /* INET6 */
520130613Smlaier	}
521130613Smlaier
522130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
523130613Smlaier		return (diff);
524130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
525130613Smlaier		return (diff);
526130613Smlaier
527130613Smlaier	return (0);
528130613Smlaier}
529130613Smlaier
530130613Smlaier#ifdef __FreeBSD__
531130613Smlaierstatic int
532130613Smlaier#else
533130613Smlaierstatic __inline int
534130613Smlaier#endif
535130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
536130613Smlaier{
537130613Smlaier	if (a->id > b->id)
538130613Smlaier		return (1);
539130613Smlaier	if (a->id < b->id)
540130613Smlaier		return (-1);
541130613Smlaier	if (a->creatorid > b->creatorid)
542130613Smlaier		return (1);
543130613Smlaier	if (a->creatorid < b->creatorid)
544130613Smlaier		return (-1);
545130613Smlaier
546130613Smlaier	return (0);
547130613Smlaier}
548130613Smlaier
549130613Smlaier#ifdef INET6
550126258Smlaiervoid
551126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
552126258Smlaier{
553126258Smlaier	switch (af) {
554126258Smlaier#ifdef INET
555126258Smlaier	case AF_INET:
556126258Smlaier		dst->addr32[0] = src->addr32[0];
557126258Smlaier		break;
558126258Smlaier#endif /* INET */
559126258Smlaier	case AF_INET6:
560126258Smlaier		dst->addr32[0] = src->addr32[0];
561126258Smlaier		dst->addr32[1] = src->addr32[1];
562126258Smlaier		dst->addr32[2] = src->addr32[2];
563126258Smlaier		dst->addr32[3] = src->addr32[3];
564126258Smlaier		break;
565126258Smlaier	}
566126258Smlaier}
567126258Smlaier#endif
568126258Smlaier
569126258Smlaierstruct pf_state *
570130613Smlaierpf_find_state_byid(struct pf_state *key)
571126258Smlaier{
572130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
573130613Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, key));
574130613Smlaier}
575126258Smlaier
576130613Smlaierstruct pf_state *
577130613Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
578130613Smlaier{
579130613Smlaier	struct pf_state *s;
580130613Smlaier
581126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
582130613Smlaier
583130613Smlaier	switch (tree) {
584130613Smlaier	case PF_LAN_EXT:
585130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
586130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
587130613Smlaier			    &kif->pfik_lan_ext, key);
588130613Smlaier			if (s != NULL)
589130613Smlaier				return (s);
590130613Smlaier		}
591126258Smlaier		return (NULL);
592130613Smlaier	case PF_EXT_GWY:
593130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
594130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
595130613Smlaier			    &kif->pfik_ext_gwy, key);
596130613Smlaier			if (s != NULL)
597130613Smlaier				return (s);
598130613Smlaier		}
599130613Smlaier		return (NULL);
600130613Smlaier	default:
601130613Smlaier		panic("pf_find_state_recurse");
602130613Smlaier	}
603126258Smlaier}
604126258Smlaier
605130613Smlaierstruct pf_state *
606130613Smlaierpf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
607130613Smlaier{
608130613Smlaier	struct pf_state *s, *ss = NULL;
609130613Smlaier	struct pfi_kif	*kif;
610130613Smlaier
611130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
612130613Smlaier
613130613Smlaier	switch (tree) {
614130613Smlaier	case PF_LAN_EXT:
615130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
616130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
617130613Smlaier			    &kif->pfik_lan_ext, key);
618130613Smlaier			if (s == NULL)
619130613Smlaier				continue;
620130613Smlaier			if (more == NULL)
621130613Smlaier				return (s);
622130613Smlaier			ss = s;
623130613Smlaier			(*more)++;
624130613Smlaier		}
625130613Smlaier		return (ss);
626130613Smlaier	case PF_EXT_GWY:
627130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
628130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
629130613Smlaier			    &kif->pfik_ext_gwy, key);
630130613Smlaier			if (s == NULL)
631130613Smlaier				continue;
632130613Smlaier			if (more == NULL)
633130613Smlaier				return (s);
634130613Smlaier			ss = s;
635130613Smlaier			(*more)++;
636130613Smlaier		}
637130613Smlaier		return (ss);
638130613Smlaier	default:
639130613Smlaier		panic("pf_find_state_all");
640130613Smlaier	}
641130613Smlaier}
642130613Smlaier
643126258Smlaierint
644130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
645130613Smlaier    struct pf_addr *src, sa_family_t af)
646126258Smlaier{
647130613Smlaier	struct pf_src_node	k;
648126258Smlaier
649130613Smlaier	if (*sn == NULL) {
650130613Smlaier		k.af = af;
651130613Smlaier		PF_ACPY(&k.addr, src, af);
652130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
653130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
654130613Smlaier			k.rule.ptr = rule;
655130613Smlaier		else
656130613Smlaier			k.rule.ptr = NULL;
657130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
658130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
659130613Smlaier	}
660130613Smlaier	if (*sn == NULL) {
661130613Smlaier		if (!rule->max_src_nodes ||
662130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
663130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
664130613Smlaier		if ((*sn) == NULL)
665130613Smlaier			return (-1);
666130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
667130613Smlaier		(*sn)->af = af;
668130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
669130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
670130613Smlaier			(*sn)->rule.ptr = rule;
671130613Smlaier		else
672130613Smlaier			(*sn)->rule.ptr = NULL;
673130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
674130613Smlaier		if (RB_INSERT(pf_src_tree,
675130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
676130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
677130613Smlaier				printf("pf: src_tree insert failed: ");
678130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
679130613Smlaier				printf("\n");
680130613Smlaier			}
681130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
682130613Smlaier			return (-1);
683130613Smlaier		}
684130613Smlaier#ifdef __FreeBSD__
685130613Smlaier		(*sn)->creation = time_second;
686130613Smlaier#else
687130613Smlaier		(*sn)->creation = time.tv_sec;
688130613Smlaier#endif
689130613Smlaier		(*sn)->ruletype = rule->action;
690130613Smlaier		if ((*sn)->rule.ptr != NULL)
691130613Smlaier			(*sn)->rule.ptr->src_nodes++;
692130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
693130613Smlaier		pf_status.src_nodes++;
694130613Smlaier	} else {
695130613Smlaier		if (rule->max_src_states &&
696130613Smlaier		    (*sn)->states >= rule->max_src_states)
697130613Smlaier			return (-1);
698130613Smlaier	}
699130613Smlaier	return (0);
700130613Smlaier}
701126258Smlaier
702130613Smlaierint
703130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
704130613Smlaier{
705126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
706130613Smlaier	state->u.s.kif = kif;
707130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
708126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
709126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
710126258Smlaier			printf(" lan: ");
711126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
712126258Smlaier			    state->af);
713126258Smlaier			printf(" gwy: ");
714126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
715126258Smlaier			    state->af);
716126258Smlaier			printf(" ext: ");
717126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
718126258Smlaier			    state->af);
719130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
720130613Smlaier				printf(" (from sync)");
721126258Smlaier			printf("\n");
722126258Smlaier		}
723126258Smlaier		return (-1);
724126258Smlaier	}
725126258Smlaier
726130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
727126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
728126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
729126258Smlaier			printf(" lan: ");
730126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
731126258Smlaier			    state->af);
732126258Smlaier			printf(" gwy: ");
733126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
734126258Smlaier			    state->af);
735126258Smlaier			printf(" ext: ");
736126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
737126258Smlaier			    state->af);
738130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
739130613Smlaier				printf(" (from sync)");
740126258Smlaier			printf("\n");
741126258Smlaier		}
742130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
743126258Smlaier		return (-1);
744126258Smlaier	}
745126258Smlaier
746130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
747130613Smlaier		state->id = htobe64(pf_status.stateid++);
748130613Smlaier		state->creatorid = pf_status.hostid;
749130613Smlaier	}
750130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
751130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
752130613Smlaier#ifdef __FreeBSD__
753130613Smlaier			printf("pf: state insert failed: "
754130613Smlaier			    "id: %016llx creatorid: %08x",
755130613Smlaier			    (long long)be64toh(state->id),
756130613Smlaier			    ntohl(state->creatorid));
757130613Smlaier#else
758130613Smlaier			printf("pf: state insert failed: "
759130613Smlaier			    "id: %016llx creatorid: %08x",
760130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
761130613Smlaier#endif
762130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
763130613Smlaier				printf(" (from sync)");
764130613Smlaier			printf("\n");
765130613Smlaier		}
766130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
767130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
768130613Smlaier		return (-1);
769130613Smlaier	}
770130613Smlaier	TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
771130613Smlaier
772126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
773126258Smlaier	pf_status.states++;
774130613Smlaier	pfi_attach_state(kif);
775126258Smlaier#if NPFSYNC
776126258Smlaier	pfsync_insert_state(state);
777126258Smlaier#endif
778126258Smlaier	return (0);
779126258Smlaier}
780126258Smlaier
781126258Smlaiervoid
782126258Smlaierpf_purge_timeout(void *arg)
783126258Smlaier{
784127145Smlaier#ifdef __FreeBSD__
785126261Smlaier	struct callout  *to = arg;
786126261Smlaier#else
787126258Smlaier	struct timeout	*to = arg;
788126261Smlaier#endif
789126258Smlaier	int		 s;
790126258Smlaier
791127145Smlaier#ifdef __FreeBSD__
792126261Smlaier	PF_LOCK();
793126261Smlaier#endif
794126258Smlaier	s = splsoftnet();
795126258Smlaier	pf_purge_expired_states();
796126258Smlaier	pf_purge_expired_fragments();
797130613Smlaier	pf_purge_expired_src_nodes();
798126258Smlaier	splx(s);
799127145Smlaier#ifdef __FreeBSD__
800126261Smlaier	PF_UNLOCK();
801126261Smlaier#endif
802126258Smlaier
803127145Smlaier#ifdef __FreeBSD__
804126261Smlaier	callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
805126261Smlaier	    pf_purge_timeout, to);
806126261Smlaier#else
807126258Smlaier	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
808126261Smlaier#endif
809126258Smlaier}
810126258Smlaier
811126258Smlaieru_int32_t
812126258Smlaierpf_state_expires(const struct pf_state *state)
813126258Smlaier{
814126258Smlaier	u_int32_t	timeout;
815126258Smlaier	u_int32_t	start;
816126258Smlaier	u_int32_t	end;
817126258Smlaier	u_int32_t	states;
818126258Smlaier
819126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
820126258Smlaier	if (state->timeout == PFTM_PURGE)
821127145Smlaier#ifdef __FreeBSD__
822126261Smlaier		return (time_second);
823126261Smlaier#else
824126258Smlaier		return (time.tv_sec);
825126261Smlaier#endif
826126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
827126258Smlaier		return (0);
828127145Smlaier#ifdef __FreeBSD__
829126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
830126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
831126261Smlaier#else
832126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
833126261Smlaier#endif
834126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
835126258Smlaier	if (!timeout)
836126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
837126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
838126258Smlaier	if (start) {
839126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
840126258Smlaier		states = state->rule.ptr->states;
841126258Smlaier	} else {
842126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
843126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
844126258Smlaier		states = pf_status.states;
845126258Smlaier	}
846126258Smlaier	if (end && states > start && start < end) {
847126258Smlaier		if (states < end)
848126258Smlaier			return (state->expire + timeout * (end - states) /
849126258Smlaier			    (end - start));
850126258Smlaier		else
851127145Smlaier#ifdef __FreeBSD__
852126261Smlaier			return (time_second);
853126261Smlaier#else
854126258Smlaier			return (time.tv_sec);
855126261Smlaier#endif
856126258Smlaier	}
857126258Smlaier	return (state->expire + timeout);
858126258Smlaier}
859126258Smlaier
860126258Smlaiervoid
861130613Smlaierpf_purge_expired_src_nodes(void)
862126258Smlaier{
863130613Smlaier	 struct pf_src_node		*cur, *next;
864126258Smlaier
865130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
866130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
867126258Smlaier
868127145Smlaier#ifdef __FreeBSD__
869130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
870126261Smlaier#else
871130613Smlaier		 if (cur->states <= 0 && cur->expire <= time.tv_sec) {
872126261Smlaier#endif
873130613Smlaier			 if (cur->rule.ptr != NULL) {
874130613Smlaier				 cur->rule.ptr->src_nodes--;
875130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
876130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
877130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
878130613Smlaier			 }
879130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
880130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
881130613Smlaier			 pf_status.src_nodes--;
882130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
883130613Smlaier		 }
884130613Smlaier	 }
885130613Smlaier}
886126258Smlaier
887130613Smlaiervoid
888130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
889130613Smlaier{
890130613Smlaier	u_int32_t timeout;
891126258Smlaier
892130613Smlaier	if (s->src_node != NULL) {
893130613Smlaier		if (--s->src_node->states <= 0) {
894130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
895130613Smlaier			if (!timeout)
896130613Smlaier				timeout =
897130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
898127145Smlaier#ifdef __FreeBSD__
899130613Smlaier			s->src_node->expire = time_second + timeout;
900126261Smlaier#else
901130613Smlaier			s->src_node->expire = time.tv_sec + timeout;
902126261Smlaier#endif
903130613Smlaier		}
904130613Smlaier	}
905130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
906130613Smlaier		if (--s->nat_src_node->states <= 0) {
907130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
908130613Smlaier			if (!timeout)
909130613Smlaier				timeout =
910130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
911130613Smlaier#ifdef __FreeBSD__
912130613Smlaier			s->nat_src_node->expire = time_second + timeout;
913130613Smlaier#else
914130613Smlaier			s->nat_src_node->expire = time.tv_sec + timeout;
915130613Smlaier#endif
916130613Smlaier		}
917130613Smlaier	}
918130613Smlaier	s->src_node = s->nat_src_node = NULL;
919130613Smlaier}
920126258Smlaier
921130613Smlaiervoid
922130613Smlaierpf_purge_expired_states(void)
923130613Smlaier{
924130613Smlaier	struct pf_state		*cur, *next;
925130613Smlaier
926130613Smlaier	for (cur = RB_MIN(pf_state_tree_id, &tree_id);
927130613Smlaier	    cur; cur = next) {
928130613Smlaier		next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
929130613Smlaier
930130613Smlaier#ifdef __FreeBSD__
931130613Smlaier		if (pf_state_expires(cur) <= time_second) {
932130613Smlaier#else
933130613Smlaier		if (pf_state_expires(cur) <= time.tv_sec) {
934130613Smlaier#endif
935130613Smlaier			if (cur->src.state == PF_TCPS_PROXY_DST)
936130613Smlaier				pf_send_tcp(cur->rule.ptr, cur->af,
937130613Smlaier				    &cur->ext.addr, &cur->lan.addr,
938130613Smlaier				    cur->ext.port, cur->lan.port,
939130613Smlaier				    cur->src.seqhi, cur->src.seqlo + 1, 0,
940130613Smlaier				    TH_RST|TH_ACK, 0, 0);
941130613Smlaier			RB_REMOVE(pf_state_tree_ext_gwy,
942130613Smlaier			    &cur->u.s.kif->pfik_ext_gwy, cur);
943130613Smlaier			RB_REMOVE(pf_state_tree_lan_ext,
944130613Smlaier			    &cur->u.s.kif->pfik_lan_ext, cur);
945130613Smlaier			RB_REMOVE(pf_state_tree_id, &tree_id, cur);
946126258Smlaier#if NPFSYNC
947130613Smlaier			pfsync_delete_state(cur);
948126258Smlaier#endif
949130613Smlaier			pf_src_tree_remove_state(cur);
950130613Smlaier			if (--cur->rule.ptr->states <= 0 &&
951130613Smlaier			    cur->rule.ptr->src_nodes <= 0)
952130613Smlaier				pf_rm_rule(NULL, cur->rule.ptr);
953130613Smlaier			if (cur->nat_rule.ptr != NULL)
954130613Smlaier				if (--cur->nat_rule.ptr->states <= 0 &&
955130613Smlaier					cur->nat_rule.ptr->src_nodes <= 0)
956130613Smlaier					pf_rm_rule(NULL, cur->nat_rule.ptr);
957130613Smlaier			if (cur->anchor.ptr != NULL)
958130613Smlaier				if (--cur->anchor.ptr->states <= 0)
959130613Smlaier					pf_rm_rule(NULL, cur->anchor.ptr);
960130613Smlaier			pf_normalize_tcp_cleanup(cur);
961130613Smlaier			pfi_detach_state(cur->u.s.kif);
962130613Smlaier			TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
963130613Smlaier			pool_put(&pf_state_pl, cur);
964126258Smlaier			pf_status.fcounters[FCNT_STATE_REMOVALS]++;
965126258Smlaier			pf_status.states--;
966126258Smlaier		}
967126258Smlaier	}
968126258Smlaier}
969126258Smlaier
970126258Smlaierint
971126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
972126258Smlaier{
973126258Smlaier	if (aw->type != PF_ADDR_TABLE)
974126258Smlaier		return (0);
975126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
976126258Smlaier		return (1);
977126258Smlaier	return (0);
978126258Smlaier}
979126258Smlaier
980126258Smlaiervoid
981126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
982126258Smlaier{
983126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
984126258Smlaier		return;
985126258Smlaier	pfr_detach_table(aw->p.tbl);
986126258Smlaier	aw->p.tbl = NULL;
987126258Smlaier}
988126258Smlaier
989126258Smlaiervoid
990126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
991126258Smlaier{
992126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
993126258Smlaier
994126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
995126258Smlaier		return;
996126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
997126258Smlaier		kt = kt->pfrkt_root;
998126258Smlaier	aw->p.tbl = NULL;
999126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1000126258Smlaier		kt->pfrkt_cnt : -1;
1001126258Smlaier}
1002126258Smlaier
1003126258Smlaiervoid
1004126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1005126258Smlaier{
1006126258Smlaier	switch (af) {
1007126258Smlaier#ifdef INET
1008126258Smlaier	case AF_INET: {
1009126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1010126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1011126258Smlaier		    (a>>8)&255, a&255);
1012126258Smlaier		if (p) {
1013126258Smlaier			p = ntohs(p);
1014126258Smlaier			printf(":%u", p);
1015126258Smlaier		}
1016126258Smlaier		break;
1017126258Smlaier	}
1018126258Smlaier#endif /* INET */
1019126258Smlaier#ifdef INET6
1020126258Smlaier	case AF_INET6: {
1021126258Smlaier		u_int16_t b;
1022126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1023126258Smlaier		    maxstart = 0, maxend = 0;
1024126258Smlaier		for (i = 0; i < 8; i++) {
1025126258Smlaier			if (!addr->addr16[i]) {
1026126258Smlaier				if (curstart == 255)
1027126258Smlaier					curstart = i;
1028126258Smlaier				else
1029126258Smlaier					curend = i;
1030126258Smlaier			} else {
1031126258Smlaier				if (curstart) {
1032126258Smlaier					if ((curend - curstart) >
1033126258Smlaier					    (maxend - maxstart)) {
1034126258Smlaier						maxstart = curstart;
1035126258Smlaier						maxend = curend;
1036126258Smlaier						curstart = 255;
1037126258Smlaier					}
1038126258Smlaier				}
1039126258Smlaier			}
1040126258Smlaier		}
1041126258Smlaier		for (i = 0; i < 8; i++) {
1042126258Smlaier			if (i >= maxstart && i <= maxend) {
1043126258Smlaier				if (maxend != 7) {
1044126258Smlaier					if (i == maxstart)
1045126258Smlaier						printf(":");
1046126258Smlaier				} else {
1047126258Smlaier					if (i == maxend)
1048126258Smlaier						printf(":");
1049126258Smlaier				}
1050126258Smlaier			} else {
1051126258Smlaier				b = ntohs(addr->addr16[i]);
1052126258Smlaier				printf("%x", b);
1053126258Smlaier				if (i < 7)
1054126258Smlaier					printf(":");
1055126258Smlaier			}
1056126258Smlaier		}
1057126258Smlaier		if (p) {
1058126258Smlaier			p = ntohs(p);
1059126258Smlaier			printf("[%u]", p);
1060126258Smlaier		}
1061126258Smlaier		break;
1062126258Smlaier	}
1063126258Smlaier#endif /* INET6 */
1064126258Smlaier	}
1065126258Smlaier}
1066126258Smlaier
1067126258Smlaiervoid
1068126258Smlaierpf_print_state(struct pf_state *s)
1069126258Smlaier{
1070126258Smlaier	switch (s->proto) {
1071126258Smlaier	case IPPROTO_TCP:
1072126258Smlaier		printf("TCP ");
1073126258Smlaier		break;
1074126258Smlaier	case IPPROTO_UDP:
1075126258Smlaier		printf("UDP ");
1076126258Smlaier		break;
1077126258Smlaier	case IPPROTO_ICMP:
1078126258Smlaier		printf("ICMP ");
1079126258Smlaier		break;
1080126258Smlaier	case IPPROTO_ICMPV6:
1081126258Smlaier		printf("ICMPV6 ");
1082126258Smlaier		break;
1083126258Smlaier	default:
1084126258Smlaier		printf("%u ", s->proto);
1085126258Smlaier		break;
1086126258Smlaier	}
1087126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1088126258Smlaier	printf(" ");
1089126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1090126258Smlaier	printf(" ");
1091126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1092126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1093126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1094126258Smlaier	if (s->src.wscale && s->dst.wscale)
1095126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1096126258Smlaier	printf("]");
1097126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1098126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1099126258Smlaier	if (s->src.wscale && s->dst.wscale)
1100126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1101126258Smlaier	printf("]");
1102126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1103126258Smlaier}
1104126258Smlaier
1105126258Smlaiervoid
1106126258Smlaierpf_print_flags(u_int8_t f)
1107126258Smlaier{
1108126258Smlaier	if (f)
1109126258Smlaier		printf(" ");
1110126258Smlaier	if (f & TH_FIN)
1111126258Smlaier		printf("F");
1112126258Smlaier	if (f & TH_SYN)
1113126258Smlaier		printf("S");
1114126258Smlaier	if (f & TH_RST)
1115126258Smlaier		printf("R");
1116126258Smlaier	if (f & TH_PUSH)
1117126258Smlaier		printf("P");
1118126258Smlaier	if (f & TH_ACK)
1119126258Smlaier		printf("A");
1120126258Smlaier	if (f & TH_URG)
1121126258Smlaier		printf("U");
1122126258Smlaier	if (f & TH_ECE)
1123126258Smlaier		printf("E");
1124126258Smlaier	if (f & TH_CWR)
1125126258Smlaier		printf("W");
1126126258Smlaier}
1127126258Smlaier
1128126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1129126258Smlaier	do {							\
1130126258Smlaier		while (head[i] != cur) {			\
1131126258Smlaier			head[i]->skip[i].ptr = cur;		\
1132126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1133126258Smlaier		}						\
1134126258Smlaier	} while (0)
1135126258Smlaier
1136126258Smlaiervoid
1137126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1138126258Smlaier{
1139126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1140126258Smlaier	int i;
1141126258Smlaier
1142126258Smlaier	cur = TAILQ_FIRST(rules);
1143126258Smlaier	prev = cur;
1144126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1145126258Smlaier		head[i] = cur;
1146126258Smlaier	while (cur != NULL) {
1147126258Smlaier
1148130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1149126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1150126258Smlaier		if (cur->direction != prev->direction)
1151126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1152126258Smlaier		if (cur->af != prev->af)
1153126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1154126258Smlaier		if (cur->proto != prev->proto)
1155126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1156126258Smlaier		if (cur->src.not != prev->src.not ||
1157126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1158126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1159126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1160126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1161126258Smlaier		    cur->src.port_op != prev->src.port_op)
1162126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1163126258Smlaier		if (cur->dst.not != prev->dst.not ||
1164126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1165126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1166126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1167126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1168126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1169126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1170126258Smlaier
1171126258Smlaier		prev = cur;
1172126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1173126258Smlaier	}
1174126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1175126258Smlaier		PF_SET_SKIP_STEPS(i);
1176126258Smlaier}
1177126258Smlaier
1178126258Smlaierint
1179126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1180126258Smlaier{
1181126258Smlaier	if (aw1->type != aw2->type)
1182126258Smlaier		return (1);
1183126258Smlaier	switch (aw1->type) {
1184126258Smlaier	case PF_ADDR_ADDRMASK:
1185126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1186126258Smlaier			return (1);
1187126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1188126258Smlaier			return (1);
1189126258Smlaier		return (0);
1190126258Smlaier	case PF_ADDR_DYNIFTL:
1191130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1192126258Smlaier	case PF_ADDR_NOROUTE:
1193126258Smlaier		return (0);
1194126258Smlaier	case PF_ADDR_TABLE:
1195126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1196126258Smlaier	default:
1197126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1198126258Smlaier		return (1);
1199126258Smlaier	}
1200126258Smlaier}
1201126258Smlaier
1202126258Smlaiervoid
1203126258Smlaierpf_update_anchor_rules()
1204126258Smlaier{
1205126258Smlaier	struct pf_rule	*rule;
1206126258Smlaier	int		 i;
1207126258Smlaier
1208126258Smlaier	for (i = 0; i < PF_RULESET_MAX; ++i)
1209126258Smlaier		TAILQ_FOREACH(rule, pf_main_ruleset.rules[i].active.ptr,
1210126258Smlaier		    entries)
1211126258Smlaier			if (rule->anchorname[0])
1212126258Smlaier				rule->anchor = pf_find_anchor(rule->anchorname);
1213126258Smlaier			else
1214126258Smlaier				rule->anchor = NULL;
1215126258Smlaier}
1216126258Smlaier
1217126258Smlaieru_int16_t
1218126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1219126258Smlaier{
1220126258Smlaier	u_int32_t	l;
1221126258Smlaier
1222126258Smlaier	if (udp && !cksum)
1223126258Smlaier		return (0x0000);
1224126258Smlaier	l = cksum + old - new;
1225126258Smlaier	l = (l >> 16) + (l & 65535);
1226126258Smlaier	l = l & 65535;
1227126258Smlaier	if (udp && !l)
1228126258Smlaier		return (0xFFFF);
1229126258Smlaier	return (l);
1230126258Smlaier}
1231126258Smlaier
1232126258Smlaiervoid
1233126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1234126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1235126258Smlaier{
1236126258Smlaier	struct pf_addr	ao;
1237126258Smlaier	u_int16_t	po = *p;
1238126258Smlaier
1239126258Smlaier	PF_ACPY(&ao, a, af);
1240126258Smlaier	PF_ACPY(a, an, af);
1241126258Smlaier
1242126258Smlaier	*p = pn;
1243126258Smlaier
1244126258Smlaier	switch (af) {
1245126258Smlaier#ifdef INET
1246126258Smlaier	case AF_INET:
1247126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1248126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1249126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1250126258Smlaier		*p = pn;
1251126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1252126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1253126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1254126258Smlaier		    po, pn, u);
1255126258Smlaier		break;
1256126258Smlaier#endif /* INET */
1257126258Smlaier#ifdef INET6
1258126258Smlaier	case AF_INET6:
1259126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1260126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1261126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1262126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1263126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1264126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1265126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1266126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1267126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1268126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1269126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1270126258Smlaier		    po, pn, u);
1271126258Smlaier		break;
1272126258Smlaier#endif /* INET6 */
1273126258Smlaier	}
1274126258Smlaier}
1275126258Smlaier
1276126258Smlaier
1277126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1278126258Smlaiervoid
1279126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1280126258Smlaier{
1281126258Smlaier	u_int32_t	ao;
1282126258Smlaier
1283126258Smlaier	memcpy(&ao, a, sizeof(ao));
1284126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1285126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1286126258Smlaier	    ao % 65536, an % 65536, u);
1287126258Smlaier}
1288126258Smlaier
1289126258Smlaier#ifdef INET6
1290126258Smlaiervoid
1291126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1292126258Smlaier{
1293126258Smlaier	struct pf_addr	ao;
1294126258Smlaier
1295126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1296126258Smlaier	PF_ACPY(a, an, AF_INET6);
1297126258Smlaier
1298126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1299126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1300126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1301126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1302126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1303126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1304126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1305126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1306126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1307126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1308126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1309126258Smlaier}
1310126258Smlaier#endif /* INET6 */
1311126258Smlaier
1312126258Smlaiervoid
1313126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1314126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1315126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1316126258Smlaier{
1317126258Smlaier	struct pf_addr	oia, ooa;
1318126258Smlaier
1319126258Smlaier	PF_ACPY(&oia, ia, af);
1320126258Smlaier	PF_ACPY(&ooa, oa, af);
1321126258Smlaier
1322126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1323126258Smlaier	if (ip != NULL) {
1324126258Smlaier		u_int16_t	oip = *ip;
1325127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1326126258Smlaier
1327126258Smlaier		if (pc != NULL)
1328126258Smlaier			opc = *pc;
1329126258Smlaier		*ip = np;
1330126258Smlaier		if (pc != NULL)
1331126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1332126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1333126258Smlaier		if (pc != NULL)
1334126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1335126258Smlaier	}
1336126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1337126258Smlaier	PF_ACPY(ia, na, af);
1338126258Smlaier	switch (af) {
1339126258Smlaier#ifdef INET
1340126258Smlaier	case AF_INET: {
1341126258Smlaier		u_int32_t	 oh2c = *h2c;
1342126258Smlaier
1343126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1344126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1345126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1346126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1347126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1348126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1349126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1350126258Smlaier		break;
1351126258Smlaier	}
1352126258Smlaier#endif /* INET */
1353126258Smlaier#ifdef INET6
1354126258Smlaier	case AF_INET6:
1355126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1356126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1357126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1358126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1359126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1360126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1361126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1362126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1363126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1364126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1365126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1366126258Smlaier		break;
1367126258Smlaier#endif /* INET6 */
1368126258Smlaier	}
1369126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1370126258Smlaier	PF_ACPY(oa, na, af);
1371126258Smlaier	switch (af) {
1372126258Smlaier#ifdef INET
1373126258Smlaier	case AF_INET:
1374126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1375126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1376126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1377126258Smlaier		break;
1378126258Smlaier#endif /* INET */
1379126258Smlaier#ifdef INET6
1380126258Smlaier	case AF_INET6:
1381126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1382126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1383126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1384126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1385126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1386126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1387126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1388126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1389126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1390126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1391126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1392126258Smlaier		break;
1393126258Smlaier#endif /* INET6 */
1394126258Smlaier	}
1395126258Smlaier}
1396126258Smlaier
1397126258Smlaiervoid
1398126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1399126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1400126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1401126258Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl)
1402126258Smlaier{
1403126258Smlaier	struct mbuf	*m;
1404132280Smlaier#ifdef ALTQ
1405126258Smlaier	struct m_tag	*mtag;
1406132280Smlaier#endif
1407127629Smlaier	int		 len = 0, tlen;		/* make the compiler happy */
1408126258Smlaier#ifdef INET
1409127629Smlaier	struct ip	*h = NULL;		/* make the compiler happy */
1410126258Smlaier#endif /* INET */
1411126258Smlaier#ifdef INET6
1412127629Smlaier	struct ip6_hdr	*h6 = NULL;		/* make the compiler happy */
1413126258Smlaier#endif /* INET6 */
1414127629Smlaier	struct tcphdr	*th = NULL;		/* make the compiler happy */
1415127145Smlaier#ifdef __FreeBSD__
1416126261Smlaier	struct ip 	*ip;
1417126261Smlaier#endif
1418126258Smlaier	char *opt;
1419126258Smlaier
1420126258Smlaier	/* maximum segment size tcp option */
1421126258Smlaier	tlen = sizeof(struct tcphdr);
1422126258Smlaier	if (mss)
1423126258Smlaier		tlen += 4;
1424126258Smlaier
1425126258Smlaier	switch (af) {
1426126258Smlaier#ifdef INET
1427126258Smlaier	case AF_INET:
1428126258Smlaier		len = sizeof(struct ip) + tlen;
1429126258Smlaier		break;
1430126258Smlaier#endif /* INET */
1431126258Smlaier#ifdef INET6
1432126258Smlaier	case AF_INET6:
1433126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1434126258Smlaier		break;
1435126258Smlaier#endif /* INET6 */
1436126258Smlaier	}
1437126258Smlaier
1438126258Smlaier	/* create outgoing mbuf */
1439132280Smlaier#ifdef __FreeBSD__
1440132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1441132280Smlaier	if (m == NULL)
1442132280Smlaier		return;
1443132280Smlaier	m->m_flags |= M_SKIP_FIREWALL;
1444132280Smlaier#else
1445126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1446126258Smlaier	if (mtag == NULL)
1447126258Smlaier		return;
1448126258Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1449126258Smlaier	if (m == NULL) {
1450126258Smlaier		m_tag_free(mtag);
1451126258Smlaier		return;
1452126258Smlaier	}
1453126258Smlaier	m_tag_prepend(m, mtag);
1454132280Smlaier#endif
1455126258Smlaier#ifdef ALTQ
1456126258Smlaier	if (r != NULL && r->qid) {
1457126258Smlaier		struct altq_tag *atag;
1458126258Smlaier
1459126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1460126258Smlaier		if (mtag != NULL) {
1461126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1462126258Smlaier			atag->qid = r->qid;
1463126258Smlaier			/* add hints for ecn */
1464126258Smlaier			atag->af = af;
1465126258Smlaier			atag->hdr = mtod(m, struct ip *);
1466126258Smlaier			m_tag_prepend(m, mtag);
1467126258Smlaier		}
1468126258Smlaier	}
1469126258Smlaier#endif
1470126258Smlaier	m->m_data += max_linkhdr;
1471126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1472126258Smlaier	m->m_pkthdr.rcvif = NULL;
1473126258Smlaier	bzero(m->m_data, len);
1474126258Smlaier	switch (af) {
1475126258Smlaier#ifdef INET
1476126258Smlaier	case AF_INET:
1477126258Smlaier		h = mtod(m, struct ip *);
1478126258Smlaier
1479126258Smlaier		/* IP header fields included in the TCP checksum */
1480126258Smlaier		h->ip_p = IPPROTO_TCP;
1481126258Smlaier		h->ip_len = htons(tlen);
1482126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1483126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1484126258Smlaier
1485126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1486126258Smlaier		break;
1487126258Smlaier#endif /* INET */
1488126258Smlaier#ifdef INET6
1489126258Smlaier	case AF_INET6:
1490126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1491126258Smlaier
1492126258Smlaier		/* IP header fields included in the TCP checksum */
1493126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1494126258Smlaier		h6->ip6_plen = htons(tlen);
1495126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1496126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1497126258Smlaier
1498126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1499126258Smlaier		break;
1500126258Smlaier#endif /* INET6 */
1501126258Smlaier	}
1502126258Smlaier
1503126258Smlaier	/* TCP header */
1504126258Smlaier	th->th_sport = sport;
1505126258Smlaier	th->th_dport = dport;
1506126258Smlaier	th->th_seq = htonl(seq);
1507126258Smlaier	th->th_ack = htonl(ack);
1508126258Smlaier	th->th_off = tlen >> 2;
1509126258Smlaier	th->th_flags = flags;
1510126258Smlaier	th->th_win = htons(win);
1511126258Smlaier
1512126258Smlaier	if (mss) {
1513126258Smlaier		opt = (char *)(th + 1);
1514126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1515126258Smlaier		opt[1] = 4;
1516126258Smlaier		HTONS(mss);
1517126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1518126258Smlaier	}
1519126258Smlaier
1520126258Smlaier	switch (af) {
1521126258Smlaier#ifdef INET
1522126258Smlaier	case AF_INET:
1523126258Smlaier		/* TCP checksum */
1524126258Smlaier		th->th_sum = in_cksum(m, len);
1525126258Smlaier
1526126258Smlaier		/* Finish the IP header */
1527126258Smlaier		h->ip_v = 4;
1528126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1529126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1530127145Smlaier#ifdef __FreeBSD__
1531130613Smlaier		h->ip_off = path_mtu_discovery ? IP_DF : 0;
1532130613Smlaier		h->ip_len = len;
1533126261Smlaier#else
1534126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1535130613Smlaier		h->ip_len = htons(len);
1536126261Smlaier#endif
1537126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1538126258Smlaier		h->ip_sum = 0;
1539127145Smlaier#ifdef __FreeBSD__
1540126261Smlaier		ip = mtod(m, struct ip *);
1541126261Smlaier		PF_UNLOCK();
1542126258Smlaier		ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
1543126261Smlaier			(void *)NULL);
1544126261Smlaier		PF_LOCK();
1545126261Smlaier#else /* ! __FreeBSD__ */
1546126261Smlaier		ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
1547126258Smlaier		    (void *)NULL);
1548126261Smlaier#endif
1549126258Smlaier		break;
1550126258Smlaier#endif /* INET */
1551126258Smlaier#ifdef INET6
1552126258Smlaier	case AF_INET6:
1553126258Smlaier		/* TCP checksum */
1554126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1555126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1556126258Smlaier
1557126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1558126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1559126258Smlaier
1560127145Smlaier#ifdef __FreeBSD__
1561126261Smlaier		PF_UNLOCK();
1562126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1563126261Smlaier		PF_LOCK();
1564126261Smlaier#else
1565126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1566126261Smlaier#endif
1567126258Smlaier		break;
1568126258Smlaier#endif /* INET6 */
1569126258Smlaier	}
1570126258Smlaier}
1571126258Smlaier
1572126258Smlaiervoid
1573126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1574126258Smlaier    struct pf_rule *r)
1575126258Smlaier{
1576132280Smlaier#ifdef ALTQ
1577126258Smlaier	struct m_tag	*mtag;
1578132280Smlaier#endif
1579126258Smlaier	struct mbuf	*m0;
1580127145Smlaier#ifdef __FreeBSD__
1581126261Smlaier	struct ip *ip;
1582126261Smlaier#endif
1583126258Smlaier
1584132280Smlaier#ifdef __FreeBSD__
1585132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
1586132280Smlaier	if (m0 == NULL)
1587132280Smlaier		return;
1588132280Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
1589132280Smlaier#else
1590126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1591126258Smlaier	if (mtag == NULL)
1592126258Smlaier		return;
1593126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
1594126258Smlaier	if (m0 == NULL) {
1595126258Smlaier		m_tag_free(mtag);
1596126258Smlaier		return;
1597126258Smlaier	}
1598126258Smlaier	m_tag_prepend(m0, mtag);
1599132280Smlaier#endif
1600126258Smlaier
1601126258Smlaier#ifdef ALTQ
1602126258Smlaier	if (r->qid) {
1603126258Smlaier		struct altq_tag *atag;
1604126258Smlaier
1605126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1606126258Smlaier		if (mtag != NULL) {
1607126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1608126258Smlaier			atag->qid = r->qid;
1609126258Smlaier			/* add hints for ecn */
1610126258Smlaier			atag->af = af;
1611126258Smlaier			atag->hdr = mtod(m0, struct ip *);
1612126258Smlaier			m_tag_prepend(m0, mtag);
1613126258Smlaier		}
1614126258Smlaier	}
1615126258Smlaier#endif
1616126258Smlaier
1617126258Smlaier	switch (af) {
1618126258Smlaier#ifdef INET
1619126258Smlaier	case AF_INET:
1620127145Smlaier#ifdef __FreeBSD__
1621126261Smlaier		/* icmp_error() expects host byte ordering */
1622126261Smlaier		ip = mtod(m0, struct ip *);
1623126261Smlaier		NTOHS(ip->ip_len);
1624126261Smlaier		NTOHS(ip->ip_off);
1625126261Smlaier		PF_UNLOCK();
1626126261Smlaier#endif
1627130613Smlaier		icmp_error(m0, type, code, 0, (void *)NULL);
1628127145Smlaier#ifdef __FreeBSD__
1629126261Smlaier		PF_LOCK();
1630126261Smlaier#endif
1631126258Smlaier		break;
1632126258Smlaier#endif /* INET */
1633126258Smlaier#ifdef INET6
1634126258Smlaier	case AF_INET6:
1635127145Smlaier#ifdef __FreeBSD__
1636126261Smlaier		PF_UNLOCK();
1637126261Smlaier#endif
1638126258Smlaier		icmp6_error(m0, type, code, 0);
1639127145Smlaier#ifdef __FreeBSD__
1640126261Smlaier		PF_LOCK();
1641126261Smlaier#endif
1642126258Smlaier		break;
1643126258Smlaier#endif /* INET6 */
1644126258Smlaier	}
1645126258Smlaier}
1646126258Smlaier
1647126258Smlaier/*
1648126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
1649126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
1650126258Smlaier * are different.
1651126258Smlaier */
1652126258Smlaierint
1653126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
1654126258Smlaier    struct pf_addr *b, sa_family_t af)
1655126258Smlaier{
1656126258Smlaier	int	match = 0;
1657126258Smlaier
1658126258Smlaier	switch (af) {
1659126258Smlaier#ifdef INET
1660126258Smlaier	case AF_INET:
1661126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
1662126258Smlaier		    (b->addr32[0] & m->addr32[0]))
1663126258Smlaier			match++;
1664126258Smlaier		break;
1665126258Smlaier#endif /* INET */
1666126258Smlaier#ifdef INET6
1667126258Smlaier	case AF_INET6:
1668126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
1669126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
1670126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
1671126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
1672126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
1673126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
1674126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
1675126258Smlaier		     (b->addr32[3] & m->addr32[3])))
1676126258Smlaier			match++;
1677126258Smlaier		break;
1678126258Smlaier#endif /* INET6 */
1679126258Smlaier	}
1680126258Smlaier	if (match) {
1681126258Smlaier		if (n)
1682126258Smlaier			return (0);
1683126258Smlaier		else
1684126258Smlaier			return (1);
1685126258Smlaier	} else {
1686126258Smlaier		if (n)
1687126258Smlaier			return (1);
1688126258Smlaier		else
1689126258Smlaier			return (0);
1690126258Smlaier	}
1691126258Smlaier}
1692126258Smlaier
1693126258Smlaierint
1694126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
1695126258Smlaier{
1696126258Smlaier	switch (op) {
1697126258Smlaier	case PF_OP_IRG:
1698126258Smlaier		return ((p > a1) && (p < a2));
1699126258Smlaier	case PF_OP_XRG:
1700126258Smlaier		return ((p < a1) || (p > a2));
1701126258Smlaier	case PF_OP_RRG:
1702126258Smlaier		return ((p >= a1) && (p <= a2));
1703126258Smlaier	case PF_OP_EQ:
1704126258Smlaier		return (p == a1);
1705126258Smlaier	case PF_OP_NE:
1706126258Smlaier		return (p != a1);
1707126258Smlaier	case PF_OP_LT:
1708126258Smlaier		return (p < a1);
1709126258Smlaier	case PF_OP_LE:
1710126258Smlaier		return (p <= a1);
1711126258Smlaier	case PF_OP_GT:
1712126258Smlaier		return (p > a1);
1713126258Smlaier	case PF_OP_GE:
1714126258Smlaier		return (p >= a1);
1715126258Smlaier	}
1716126258Smlaier	return (0); /* never reached */
1717126258Smlaier}
1718126258Smlaier
1719126258Smlaierint
1720126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
1721126258Smlaier{
1722126258Smlaier	NTOHS(a1);
1723126258Smlaier	NTOHS(a2);
1724126258Smlaier	NTOHS(p);
1725126258Smlaier	return (pf_match(op, a1, a2, p));
1726126258Smlaier}
1727126258Smlaier
1728126258Smlaierint
1729126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
1730126258Smlaier{
1731126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1732126258Smlaier		return (0);
1733126258Smlaier	return (pf_match(op, a1, a2, u));
1734126258Smlaier}
1735126258Smlaier
1736126258Smlaierint
1737126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
1738126258Smlaier{
1739126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1740126258Smlaier		return (0);
1741126258Smlaier	return (pf_match(op, a1, a2, g));
1742126258Smlaier}
1743126258Smlaier
1744126258Smlaierstruct pf_tag *
1745126258Smlaierpf_get_tag(struct mbuf *m)
1746126258Smlaier{
1747126258Smlaier	struct m_tag	*mtag;
1748126258Smlaier
1749126258Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
1750126258Smlaier		return ((struct pf_tag *)(mtag + 1));
1751126258Smlaier	else
1752126258Smlaier		return (NULL);
1753126258Smlaier}
1754126258Smlaier
1755126258Smlaierint
1756130613Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat_rule,
1757130613Smlaier    struct pf_tag *pftag, int *tag)
1758126258Smlaier{
1759126258Smlaier	if (*tag == -1) {	/* find mbuf tag */
1760126258Smlaier		pftag = pf_get_tag(m);
1761126258Smlaier		if (pftag != NULL)
1762126258Smlaier			*tag = pftag->tag;
1763126258Smlaier		else
1764126258Smlaier			*tag = 0;
1765130613Smlaier		if (nat_rule != NULL && nat_rule->tag)
1766130613Smlaier			*tag = nat_rule->tag;
1767126258Smlaier	}
1768126258Smlaier
1769126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
1770126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
1771126258Smlaier}
1772126258Smlaier
1773126258Smlaierint
1774126258Smlaierpf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
1775126258Smlaier{
1776126258Smlaier	struct m_tag	*mtag;
1777126258Smlaier
1778126258Smlaier	if (tag <= 0)
1779126258Smlaier		return (0);
1780126258Smlaier
1781126258Smlaier	if (pftag == NULL) {
1782126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
1783126258Smlaier		if (mtag == NULL)
1784126258Smlaier			return (1);
1785126258Smlaier		((struct pf_tag *)(mtag + 1))->tag = tag;
1786126258Smlaier		m_tag_prepend(m, mtag);
1787126258Smlaier	} else
1788126258Smlaier		pftag->tag = tag;
1789126258Smlaier
1790126258Smlaier	return (0);
1791126258Smlaier}
1792126258Smlaier
1793126258Smlaier#define PF_STEP_INTO_ANCHOR(r, a, s, n)					\
1794126258Smlaier	do {								\
1795126258Smlaier		if ((r) == NULL || (r)->anchor == NULL ||		\
1796126258Smlaier		    (s) != NULL || (a) != NULL)				\
1797126258Smlaier			panic("PF_STEP_INTO_ANCHOR");			\
1798126258Smlaier		(a) = (r);						\
1799126258Smlaier		(s) = TAILQ_FIRST(&(r)->anchor->rulesets);		\
1800126258Smlaier		(r) = NULL;						\
1801126258Smlaier		while ((s) != NULL && ((r) =				\
1802126258Smlaier		    TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL)	\
1803126258Smlaier			(s) = TAILQ_NEXT((s), entries);			\
1804126258Smlaier		if ((r) == NULL) {					\
1805126258Smlaier			(r) = TAILQ_NEXT((a), entries);			\
1806126258Smlaier			(a) = NULL;					\
1807126258Smlaier		}							\
1808126258Smlaier	} while (0)
1809126258Smlaier
1810126258Smlaier#define PF_STEP_OUT_OF_ANCHOR(r, a, s, n)				\
1811126258Smlaier	do {								\
1812126258Smlaier		if ((r) != NULL || (a) == NULL || (s) == NULL)		\
1813126258Smlaier			panic("PF_STEP_OUT_OF_ANCHOR");			\
1814126258Smlaier		(s) = TAILQ_NEXT((s), entries);				\
1815126258Smlaier		while ((s) != NULL && ((r) =				\
1816126258Smlaier		    TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL)	\
1817126258Smlaier			(s) = TAILQ_NEXT((s), entries);			\
1818126258Smlaier		if ((r) == NULL) {					\
1819126258Smlaier			(r) = TAILQ_NEXT((a), entries);			\
1820126258Smlaier			(a) = NULL;					\
1821126258Smlaier		}							\
1822126258Smlaier	} while (0)
1823126258Smlaier
1824126258Smlaier#ifdef INET6
1825126258Smlaiervoid
1826126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
1827126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
1828126258Smlaier{
1829126258Smlaier	switch (af) {
1830126258Smlaier#ifdef INET
1831126258Smlaier	case AF_INET:
1832126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
1833126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
1834126258Smlaier		break;
1835126258Smlaier#endif /* INET */
1836126258Smlaier	case AF_INET6:
1837126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
1838126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
1839126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
1840126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
1841126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
1842126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
1843126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
1844126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
1845126258Smlaier		break;
1846126258Smlaier	}
1847126258Smlaier}
1848126258Smlaier
1849126258Smlaiervoid
1850130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
1851126258Smlaier{
1852126258Smlaier	switch (af) {
1853126258Smlaier#ifdef INET
1854126258Smlaier	case AF_INET:
1855126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
1856126258Smlaier		break;
1857126258Smlaier#endif /* INET */
1858126258Smlaier	case AF_INET6:
1859126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
1860126258Smlaier			addr->addr32[3] = 0;
1861126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
1862126258Smlaier				addr->addr32[2] = 0;
1863126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
1864126258Smlaier					addr->addr32[1] = 0;
1865126258Smlaier					addr->addr32[0] =
1866126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
1867126258Smlaier				} else
1868126258Smlaier					addr->addr32[1] =
1869126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
1870126258Smlaier			} else
1871126258Smlaier				addr->addr32[2] =
1872126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
1873126258Smlaier		} else
1874126258Smlaier			addr->addr32[3] =
1875126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
1876126258Smlaier		break;
1877126258Smlaier	}
1878126258Smlaier}
1879126258Smlaier#endif /* INET6 */
1880126258Smlaier
1881126258Smlaier#define mix(a,b,c) \
1882126258Smlaier	do {					\
1883126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
1884126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
1885126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
1886126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
1887126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
1888126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
1889126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
1890126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
1891126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
1892126258Smlaier	} while (0)
1893126258Smlaier
1894126258Smlaier/*
1895126258Smlaier * hash function based on bridge_hash in if_bridge.c
1896126258Smlaier */
1897126258Smlaiervoid
1898126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
1899126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
1900126258Smlaier{
1901126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
1902126258Smlaier
1903126258Smlaier	switch (af) {
1904126258Smlaier#ifdef INET
1905126258Smlaier	case AF_INET:
1906126258Smlaier		a += inaddr->addr32[0];
1907126258Smlaier		b += key->key32[1];
1908126258Smlaier		mix(a, b, c);
1909126258Smlaier		hash->addr32[0] = c + key->key32[2];
1910126258Smlaier		break;
1911126258Smlaier#endif /* INET */
1912126258Smlaier#ifdef INET6
1913126258Smlaier	case AF_INET6:
1914126258Smlaier		a += inaddr->addr32[0];
1915126258Smlaier		b += inaddr->addr32[2];
1916126258Smlaier		mix(a, b, c);
1917126258Smlaier		hash->addr32[0] = c;
1918126258Smlaier		a += inaddr->addr32[1];
1919126258Smlaier		b += inaddr->addr32[3];
1920126258Smlaier		c += key->key32[1];
1921126258Smlaier		mix(a, b, c);
1922126258Smlaier		hash->addr32[1] = c;
1923126258Smlaier		a += inaddr->addr32[2];
1924126258Smlaier		b += inaddr->addr32[1];
1925126258Smlaier		c += key->key32[2];
1926126258Smlaier		mix(a, b, c);
1927126258Smlaier		hash->addr32[2] = c;
1928126258Smlaier		a += inaddr->addr32[3];
1929126258Smlaier		b += inaddr->addr32[0];
1930126258Smlaier		c += key->key32[3];
1931126258Smlaier		mix(a, b, c);
1932126258Smlaier		hash->addr32[3] = c;
1933126258Smlaier		break;
1934126258Smlaier#endif /* INET6 */
1935126258Smlaier	}
1936126258Smlaier}
1937126258Smlaier
1938126258Smlaierint
1939130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
1940130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
1941126258Smlaier{
1942126258Smlaier	unsigned char		 hash[16];
1943130613Smlaier	struct pf_pool		*rpool = &r->rpool;
1944130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
1945130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
1946126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
1947130613Smlaier	struct pf_src_node	 k;
1948126258Smlaier
1949130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
1950130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
1951130613Smlaier		k.af = af;
1952130613Smlaier		PF_ACPY(&k.addr, saddr, af);
1953130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
1954130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
1955130613Smlaier			k.rule.ptr = r;
1956130613Smlaier		else
1957130613Smlaier			k.rule.ptr = NULL;
1958130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
1959130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
1960130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
1961130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
1962130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
1963130613Smlaier				printf("pf_map_addr: src tracking maps ");
1964130613Smlaier				pf_print_host(&k.addr, 0, af);
1965130613Smlaier				printf(" to ");
1966130613Smlaier				pf_print_host(naddr, 0, af);
1967130613Smlaier				printf("\n");
1968130613Smlaier			}
1969130613Smlaier			return (0);
1970130613Smlaier		}
1971130613Smlaier	}
1972130613Smlaier
1973126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
1974126258Smlaier		return (1);
1975130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
1976130613Smlaier		if (af == AF_INET) {
1977130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
1978130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
1979130613Smlaier			    PF_POOL_ROUNDROBIN)
1980130613Smlaier				return (1);
1981130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
1982130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
1983130613Smlaier		} else {
1984130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
1985130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
1986130613Smlaier			    PF_POOL_ROUNDROBIN)
1987130613Smlaier				return (1);
1988130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
1989130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
1990130613Smlaier		}
1991130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
1992126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
1993126258Smlaier			return (1); /* unsupported */
1994126258Smlaier	} else {
1995126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
1996126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
1997126258Smlaier	}
1998126258Smlaier
1999126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2000126258Smlaier	case PF_POOL_NONE:
2001126258Smlaier		PF_ACPY(naddr, raddr, af);
2002126258Smlaier		break;
2003126258Smlaier	case PF_POOL_BITMASK:
2004126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2005126258Smlaier		break;
2006126258Smlaier	case PF_POOL_RANDOM:
2007126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2008126258Smlaier			switch (af) {
2009126258Smlaier#ifdef INET
2010126258Smlaier			case AF_INET:
2011126258Smlaier				rpool->counter.addr32[0] = arc4random();
2012126258Smlaier				break;
2013126258Smlaier#endif /* INET */
2014126258Smlaier#ifdef INET6
2015126258Smlaier			case AF_INET6:
2016126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2017126258Smlaier					rpool->counter.addr32[3] = arc4random();
2018126258Smlaier				else
2019126258Smlaier					break;
2020126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2021126258Smlaier					rpool->counter.addr32[2] = arc4random();
2022126258Smlaier				else
2023126258Smlaier					break;
2024126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2025126258Smlaier					rpool->counter.addr32[1] = arc4random();
2026126258Smlaier				else
2027126258Smlaier					break;
2028126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2029126258Smlaier					rpool->counter.addr32[0] = arc4random();
2030126258Smlaier				break;
2031126258Smlaier#endif /* INET6 */
2032126258Smlaier			}
2033126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2034126258Smlaier			PF_ACPY(init_addr, naddr, af);
2035126258Smlaier
2036126258Smlaier		} else {
2037126258Smlaier			PF_AINC(&rpool->counter, af);
2038126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2039126258Smlaier		}
2040126258Smlaier		break;
2041126258Smlaier	case PF_POOL_SRCHASH:
2042126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2043126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2044126258Smlaier		break;
2045126258Smlaier	case PF_POOL_ROUNDROBIN:
2046126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2047126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2048126258Smlaier			    &rpool->tblidx, &rpool->counter,
2049126258Smlaier			    &raddr, &rmask, af))
2050126258Smlaier				goto get_addr;
2051130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2052130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2053130613Smlaier			    &rpool->tblidx, &rpool->counter,
2054130613Smlaier			    &raddr, &rmask, af))
2055130613Smlaier				goto get_addr;
2056126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2057126258Smlaier			goto get_addr;
2058126258Smlaier
2059126258Smlaier	try_next:
2060126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2061126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2062126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2063126258Smlaier			rpool->tblidx = -1;
2064126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2065126258Smlaier			    &rpool->tblidx, &rpool->counter,
2066126258Smlaier			    &raddr, &rmask, af)) {
2067130613Smlaier				/* table contains no address of type 'af' */
2068126258Smlaier				if (rpool->cur != acur)
2069126258Smlaier					goto try_next;
2070126258Smlaier				return (1);
2071126258Smlaier			}
2072130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2073130613Smlaier			rpool->tblidx = -1;
2074130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2075130613Smlaier			    &rpool->tblidx, &rpool->counter,
2076130613Smlaier			    &raddr, &rmask, af)) {
2077130613Smlaier				/* table contains no address of type 'af' */
2078130613Smlaier				if (rpool->cur != acur)
2079130613Smlaier					goto try_next;
2080130613Smlaier				return (1);
2081130613Smlaier			}
2082126258Smlaier		} else {
2083126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2084126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2085126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2086126258Smlaier		}
2087126258Smlaier
2088126258Smlaier	get_addr:
2089126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2090126258Smlaier		PF_AINC(&rpool->counter, af);
2091126258Smlaier		break;
2092126258Smlaier	}
2093130613Smlaier	if (*sn != NULL)
2094130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2095126258Smlaier
2096126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2097126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2098130613Smlaier		printf("pf_map_addr: selected address ");
2099126258Smlaier		pf_print_host(naddr, 0, af);
2100126258Smlaier		printf("\n");
2101126258Smlaier	}
2102126258Smlaier
2103126258Smlaier	return (0);
2104126258Smlaier}
2105126258Smlaier
2106126258Smlaierint
2107130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2108126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2109130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2110130613Smlaier    struct pf_src_node **sn)
2111126258Smlaier{
2112130613Smlaier	struct pf_state		key;
2113126258Smlaier	struct pf_addr		init_addr;
2114126258Smlaier	u_int16_t		cut;
2115126258Smlaier
2116126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2117130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2118126258Smlaier		return (1);
2119126258Smlaier
2120126258Smlaier	do {
2121126258Smlaier		key.af = af;
2122126258Smlaier		key.proto = proto;
2123130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2124130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2125130613Smlaier		key.ext.port = dport;
2126126258Smlaier
2127126258Smlaier		/*
2128126258Smlaier		 * port search; start random, step;
2129126258Smlaier		 * similar 2 portloop in in_pcbbind
2130126258Smlaier		 */
2131126258Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
2132130613Smlaier			key.gwy.port = 0;
2133130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2134126258Smlaier				return (0);
2135126258Smlaier		} else if (low == 0 && high == 0) {
2136130613Smlaier			key.gwy.port = *nport;
2137130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2138126258Smlaier				return (0);
2139126258Smlaier		} else if (low == high) {
2140130613Smlaier			key.gwy.port = htons(low);
2141130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2142126258Smlaier				*nport = htons(low);
2143126258Smlaier				return (0);
2144126258Smlaier			}
2145126258Smlaier		} else {
2146126258Smlaier			u_int16_t tmp;
2147126258Smlaier
2148126258Smlaier			if (low > high) {
2149126258Smlaier				tmp = low;
2150126258Smlaier				low = high;
2151126258Smlaier				high = tmp;
2152126258Smlaier			}
2153126258Smlaier			/* low < high */
2154126258Smlaier			cut = arc4random() % (1 + high - low) + low;
2155126258Smlaier			/* low <= cut <= high */
2156126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2157130613Smlaier				key.gwy.port = htons(tmp);
2158130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2159126258Smlaier				    NULL) {
2160126258Smlaier					*nport = htons(tmp);
2161126258Smlaier					return (0);
2162126258Smlaier				}
2163126258Smlaier			}
2164126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2165130613Smlaier				key.gwy.port = htons(tmp);
2166130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2167126258Smlaier				    NULL) {
2168126258Smlaier					*nport = htons(tmp);
2169126258Smlaier					return (0);
2170126258Smlaier				}
2171126258Smlaier			}
2172126258Smlaier		}
2173126258Smlaier
2174130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2175126258Smlaier		case PF_POOL_RANDOM:
2176126258Smlaier		case PF_POOL_ROUNDROBIN:
2177130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2178126258Smlaier				return (1);
2179126258Smlaier			break;
2180126258Smlaier		case PF_POOL_NONE:
2181126258Smlaier		case PF_POOL_SRCHASH:
2182126258Smlaier		case PF_POOL_BITMASK:
2183126258Smlaier		default:
2184126258Smlaier			return (1);
2185126258Smlaier		}
2186126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2187126258Smlaier
2188126258Smlaier	return (1);					/* none available */
2189126258Smlaier}
2190126258Smlaier
2191126258Smlaierstruct pf_rule *
2192126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2193130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2194126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2195126258Smlaier{
2196126258Smlaier	struct pf_rule		*r, *rm = NULL, *anchorrule = NULL;
2197126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2198126258Smlaier
2199126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2200126258Smlaier	while (r && rm == NULL) {
2201126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2202126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2203126258Smlaier
2204126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2205126258Smlaier			src = &r->dst;
2206126258Smlaier			if (r->rpool.cur != NULL)
2207126258Smlaier				xdst = &r->rpool.cur->addr;
2208126258Smlaier		} else {
2209126258Smlaier			src = &r->src;
2210126258Smlaier			dst = &r->dst;
2211126258Smlaier		}
2212126258Smlaier
2213126258Smlaier		r->evaluations++;
2214130613Smlaier		if (r->kif != NULL &&
2215130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
2216126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2217126258Smlaier		else if (r->direction && r->direction != direction)
2218126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2219126258Smlaier		else if (r->af && r->af != pd->af)
2220126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2221126258Smlaier		else if (r->proto && r->proto != pd->proto)
2222126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2223126258Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->not))
2224126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2225126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2226126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2227126258Smlaier		    src->port[0], src->port[1], sport))
2228126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2229126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2230126258Smlaier		else if (dst != NULL &&
2231126258Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->not))
2232126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2233126258Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
2234126258Smlaier			r = TAILQ_NEXT(r, entries);
2235126258Smlaier		else if (dst != NULL && dst->port_op &&
2236126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2237126258Smlaier		    dst->port[1], dport))
2238126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2239126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2240126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2241126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2242126258Smlaier			r = TAILQ_NEXT(r, entries);
2243126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
2244126258Smlaier			r = TAILQ_NEXT(r, entries);
2245126258Smlaier		else if (r->anchor == NULL)
2246126258Smlaier				rm = r;
2247126258Smlaier		else
2248126258Smlaier			PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, rs_num);
2249126258Smlaier		if (r == NULL && anchorrule != NULL)
2250126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset,
2251126258Smlaier			    rs_num);
2252126258Smlaier	}
2253126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2254126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2255126258Smlaier		return (NULL);
2256126258Smlaier	return (rm);
2257126258Smlaier}
2258126258Smlaier
2259126258Smlaierstruct pf_rule *
2260126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2261130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2262126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2263126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2264126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2265126258Smlaier{
2266126258Smlaier	struct pf_rule	*r = NULL;
2267126258Smlaier
2268126258Smlaier	if (direction == PF_OUT) {
2269130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2270126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2271126258Smlaier		if (r == NULL)
2272130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2273126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2274126258Smlaier	} else {
2275130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2276126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2277126258Smlaier		if (r == NULL)
2278130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2279126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2280126258Smlaier	}
2281126258Smlaier
2282126258Smlaier	if (r != NULL) {
2283126258Smlaier		switch (r->action) {
2284126258Smlaier		case PF_NONAT:
2285126258Smlaier		case PF_NOBINAT:
2286126258Smlaier		case PF_NORDR:
2287126258Smlaier			return (NULL);
2288126258Smlaier		case PF_NAT:
2289130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2290126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2291130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2292126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2293126258Smlaier				    ("pf: NAT proxy port allocation "
2294126258Smlaier				    "(%u-%u) failed\n",
2295126258Smlaier				    r->rpool.proxy_port[0],
2296126258Smlaier				    r->rpool.proxy_port[1]));
2297126258Smlaier				return (NULL);
2298126258Smlaier			}
2299126258Smlaier			break;
2300126258Smlaier		case PF_BINAT:
2301126258Smlaier			switch (direction) {
2302126258Smlaier			case PF_OUT:
2303130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2304130613Smlaier					if (pd->af == AF_INET) {
2305130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2306130613Smlaier						    pfid_acnt4 < 1)
2307130613Smlaier							return (NULL);
2308130613Smlaier						PF_POOLMASK(naddr,
2309130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2310130613Smlaier						    pfid_addr4,
2311130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2312130613Smlaier						    pfid_mask4,
2313130613Smlaier						    saddr, AF_INET);
2314130613Smlaier					} else {
2315130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2316130613Smlaier						    pfid_acnt6 < 1)
2317130613Smlaier							return (NULL);
2318130613Smlaier						PF_POOLMASK(naddr,
2319130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2320130613Smlaier						    pfid_addr6,
2321130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2322130613Smlaier						    pfid_mask6,
2323130613Smlaier						    saddr, AF_INET6);
2324130613Smlaier					}
2325130613Smlaier				} else
2326126258Smlaier					PF_POOLMASK(naddr,
2327126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2328126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2329126258Smlaier					    saddr, pd->af);
2330126258Smlaier				break;
2331126258Smlaier			case PF_IN:
2332130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2333130613Smlaier					if (pd->af == AF_INET) {
2334130613Smlaier						if (r->src.addr.p.dyn->
2335130613Smlaier						    pfid_acnt4 < 1)
2336130613Smlaier							return (NULL);
2337130613Smlaier						PF_POOLMASK(naddr,
2338130613Smlaier						    &r->src.addr.p.dyn->
2339130613Smlaier						    pfid_addr4,
2340130613Smlaier						    &r->src.addr.p.dyn->
2341130613Smlaier						    pfid_mask4,
2342130613Smlaier						    daddr, AF_INET);
2343130613Smlaier					} else {
2344130613Smlaier						if (r->src.addr.p.dyn->
2345130613Smlaier						    pfid_acnt6 < 1)
2346130613Smlaier							return (NULL);
2347130613Smlaier						PF_POOLMASK(naddr,
2348130613Smlaier						    &r->src.addr.p.dyn->
2349130613Smlaier						    pfid_addr6,
2350130613Smlaier						    &r->src.addr.p.dyn->
2351130613Smlaier						    pfid_mask6,
2352130613Smlaier						    daddr, AF_INET6);
2353130613Smlaier					}
2354130613Smlaier				} else
2355126258Smlaier					PF_POOLMASK(naddr,
2356126258Smlaier					    &r->src.addr.v.a.addr,
2357126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2358126258Smlaier					    pd->af);
2359126258Smlaier				break;
2360126258Smlaier			}
2361126258Smlaier			break;
2362126258Smlaier		case PF_RDR: {
2363130613Smlaier			if (pf_map_addr(r->af, r, saddr, naddr, NULL, sn))
2364126258Smlaier				return (NULL);
2365126258Smlaier
2366126258Smlaier			if (r->rpool.proxy_port[1]) {
2367126258Smlaier				u_int32_t	tmp_nport;
2368126258Smlaier
2369126258Smlaier				tmp_nport = ((ntohs(dport) -
2370126258Smlaier				    ntohs(r->dst.port[0])) %
2371126258Smlaier				    (r->rpool.proxy_port[1] -
2372126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2373126258Smlaier				    r->rpool.proxy_port[0];
2374126258Smlaier
2375126258Smlaier				/* wrap around if necessary */
2376126258Smlaier				if (tmp_nport > 65535)
2377126258Smlaier					tmp_nport -= 65535;
2378126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2379126258Smlaier			} else if (r->rpool.proxy_port[0])
2380126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2381126258Smlaier			break;
2382126258Smlaier		}
2383126258Smlaier		default:
2384126258Smlaier			return (NULL);
2385126258Smlaier		}
2386126258Smlaier	}
2387126258Smlaier
2388126258Smlaier	return (r);
2389126258Smlaier}
2390126258Smlaier
2391126258Smlaierint
2392135920Smlaier#ifdef __FreeBSD__
2393135920Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
2394135920Smlaier    struct inpcb *inp_arg)
2395135920Smlaier#else
2396130613Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
2397135920Smlaier#endif
2398126258Smlaier{
2399126258Smlaier	struct pf_addr		*saddr, *daddr;
2400126258Smlaier	u_int16_t		 sport, dport;
2401127145Smlaier#ifdef __FreeBSD__
2402126261Smlaier	struct inpcbinfo	*pi;
2403126261Smlaier#else
2404126258Smlaier	struct inpcbtable	*tb;
2405126261Smlaier#endif
2406126258Smlaier	struct inpcb		*inp;
2407126258Smlaier
2408126258Smlaier	*uid = UID_MAX;
2409126258Smlaier	*gid = GID_MAX;
2410135920Smlaier#ifdef __FreeBSD__
2411135920Smlaier	if (inp_arg != NULL) {
2412135920Smlaier		INP_LOCK_ASSERT(inp_arg);
2413135920Smlaier		if (inp_arg->inp_socket) {
2414135920Smlaier			*uid = inp_arg->inp_socket->so_cred->cr_uid;
2415135920Smlaier			*gid = inp_arg->inp_socket->so_cred->cr_groups[0];
2416135920Smlaier			return (1);
2417135920Smlaier		} else
2418135920Smlaier			return (0);
2419135920Smlaier	}
2420135920Smlaier#endif
2421130613Smlaier	switch (pd->proto) {
2422126258Smlaier	case IPPROTO_TCP:
2423126258Smlaier		sport = pd->hdr.tcp->th_sport;
2424126258Smlaier		dport = pd->hdr.tcp->th_dport;
2425127145Smlaier#ifdef __FreeBSD__
2426126261Smlaier		pi = &tcbinfo;
2427126261Smlaier#else
2428126258Smlaier		tb = &tcbtable;
2429126261Smlaier#endif
2430126258Smlaier		break;
2431126258Smlaier	case IPPROTO_UDP:
2432126258Smlaier		sport = pd->hdr.udp->uh_sport;
2433126258Smlaier		dport = pd->hdr.udp->uh_dport;
2434127145Smlaier#ifdef __FreeBSD__
2435126261Smlaier		pi = &udbinfo;
2436126261Smlaier#else
2437126258Smlaier		tb = &udbtable;
2438126261Smlaier#endif
2439126258Smlaier		break;
2440126258Smlaier	default:
2441126258Smlaier		return (0);
2442126258Smlaier	}
2443126258Smlaier	if (direction == PF_IN) {
2444126258Smlaier		saddr = pd->src;
2445126258Smlaier		daddr = pd->dst;
2446126258Smlaier	} else {
2447126258Smlaier		u_int16_t	p;
2448126258Smlaier
2449126258Smlaier		p = sport;
2450126258Smlaier		sport = dport;
2451126258Smlaier		dport = p;
2452126258Smlaier		saddr = pd->dst;
2453126258Smlaier		daddr = pd->src;
2454126258Smlaier	}
2455130613Smlaier	switch (pd->af) {
2456126258Smlaier	case AF_INET:
2457127145Smlaier#ifdef __FreeBSD__
2458126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2459126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2460126261Smlaier			dport, 0, NULL);
2461126261Smlaier		if (inp == NULL) {
2462126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2463126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2464126261Smlaier			if(inp == NULL) {
2465126261Smlaier				INP_INFO_RUNLOCK(pi);
2466126261Smlaier				return (0);
2467126261Smlaier			}
2468126261Smlaier		}
2469126261Smlaier#else
2470126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
2471126258Smlaier		if (inp == NULL) {
2472130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
2473126258Smlaier			if (inp == NULL)
2474126258Smlaier				return (0);
2475126258Smlaier		}
2476126261Smlaier#endif
2477126258Smlaier		break;
2478126258Smlaier#ifdef INET6
2479126258Smlaier	case AF_INET6:
2480127145Smlaier#ifdef __FreeBSD__
2481126261Smlaier		INP_INFO_RLOCK(pi);
2482126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2483126261Smlaier			&daddr->v6, dport, 0, NULL);
2484126261Smlaier		if (inp == NULL) {
2485126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2486126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
2487126261Smlaier			if (inp == NULL) {
2488126261Smlaier				INP_INFO_RUNLOCK(pi);
2489126261Smlaier				return (0);
2490126261Smlaier			}
2491126261Smlaier		}
2492126261Smlaier#else
2493126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
2494126258Smlaier		    dport);
2495126258Smlaier		if (inp == NULL) {
2496130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
2497126258Smlaier			if (inp == NULL)
2498126258Smlaier				return (0);
2499126258Smlaier		}
2500126261Smlaier#endif
2501126258Smlaier		break;
2502126258Smlaier#endif /* INET6 */
2503126258Smlaier
2504126258Smlaier	default:
2505126258Smlaier		return (0);
2506126258Smlaier	}
2507127145Smlaier#ifdef __FreeBSD__
2508126261Smlaier	INP_LOCK(inp);
2509126261Smlaier	*uid = inp->inp_socket->so_cred->cr_uid;
2510126261Smlaier	*gid = inp->inp_socket->so_cred->cr_groups[0];
2511126261Smlaier	INP_UNLOCK(inp);
2512126261Smlaier	INP_INFO_RUNLOCK(pi);
2513126261Smlaier#else
2514126258Smlaier	*uid = inp->inp_socket->so_euid;
2515126258Smlaier	*gid = inp->inp_socket->so_egid;
2516126261Smlaier#endif
2517126258Smlaier	return (1);
2518126258Smlaier}
2519126258Smlaier
2520126258Smlaieru_int8_t
2521126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2522126258Smlaier{
2523126258Smlaier	int		 hlen;
2524126258Smlaier	u_int8_t	 hdr[60];
2525126258Smlaier	u_int8_t	*opt, optlen;
2526126258Smlaier	u_int8_t	 wscale = 0;
2527126258Smlaier
2528126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
2529126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2530126258Smlaier		return (0);
2531126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2532126258Smlaier		return (0);
2533126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2534126258Smlaier	hlen -= sizeof(struct tcphdr);
2535126258Smlaier	while (hlen >= 3) {
2536126258Smlaier		switch (*opt) {
2537126258Smlaier		case TCPOPT_EOL:
2538126258Smlaier		case TCPOPT_NOP:
2539126258Smlaier			++opt;
2540126258Smlaier			--hlen;
2541126258Smlaier			break;
2542126258Smlaier		case TCPOPT_WINDOW:
2543126258Smlaier			wscale = opt[2];
2544126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
2545126258Smlaier				wscale = TCP_MAX_WINSHIFT;
2546126258Smlaier			wscale |= PF_WSCALE_FLAG;
2547130613Smlaier			/* FALLTHROUGH */
2548126258Smlaier		default:
2549126258Smlaier			optlen = opt[1];
2550126258Smlaier			if (optlen < 2)
2551126258Smlaier				optlen = 2;
2552126258Smlaier			hlen -= optlen;
2553126258Smlaier			opt += optlen;
2554130613Smlaier			break;
2555126258Smlaier		}
2556126258Smlaier	}
2557126258Smlaier	return (wscale);
2558126258Smlaier}
2559126258Smlaier
2560126258Smlaieru_int16_t
2561126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2562126258Smlaier{
2563126258Smlaier	int		 hlen;
2564126258Smlaier	u_int8_t	 hdr[60];
2565126258Smlaier	u_int8_t	*opt, optlen;
2566126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
2567126258Smlaier
2568126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
2569126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2570126258Smlaier		return (0);
2571126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2572126258Smlaier		return (0);
2573126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2574126258Smlaier	hlen -= sizeof(struct tcphdr);
2575126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
2576126258Smlaier		switch (*opt) {
2577126258Smlaier		case TCPOPT_EOL:
2578126258Smlaier		case TCPOPT_NOP:
2579126258Smlaier			++opt;
2580126258Smlaier			--hlen;
2581126258Smlaier			break;
2582126258Smlaier		case TCPOPT_MAXSEG:
2583126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
2584130613Smlaier			/* FALLTHROUGH */
2585126258Smlaier		default:
2586126258Smlaier			optlen = opt[1];
2587126258Smlaier			if (optlen < 2)
2588126258Smlaier				optlen = 2;
2589126258Smlaier			hlen -= optlen;
2590126258Smlaier			opt += optlen;
2591130613Smlaier			break;
2592126258Smlaier		}
2593126258Smlaier	}
2594126258Smlaier	return (mss);
2595126258Smlaier}
2596126258Smlaier
2597126258Smlaieru_int16_t
2598126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
2599126258Smlaier{
2600126258Smlaier#ifdef INET
2601126258Smlaier	struct sockaddr_in	*dst;
2602126258Smlaier	struct route		 ro;
2603126258Smlaier#endif /* INET */
2604126258Smlaier#ifdef INET6
2605126258Smlaier	struct sockaddr_in6	*dst6;
2606126258Smlaier	struct route_in6	 ro6;
2607126258Smlaier#endif /* INET6 */
2608126258Smlaier	struct rtentry		*rt = NULL;
2609127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
2610126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2611126258Smlaier
2612126258Smlaier	switch (af) {
2613126258Smlaier#ifdef INET
2614126258Smlaier	case AF_INET:
2615126258Smlaier		hlen = sizeof(struct ip);
2616126258Smlaier		bzero(&ro, sizeof(ro));
2617126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
2618126258Smlaier		dst->sin_family = AF_INET;
2619126258Smlaier		dst->sin_len = sizeof(*dst);
2620126258Smlaier		dst->sin_addr = addr->v4;
2621127145Smlaier#ifdef __FreeBSD__
2622126261Smlaier#ifdef RTF_PRCLONING
2623126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
2624126261Smlaier#else /* !RTF_PRCLONING */
2625126261Smlaier		rtalloc_ign(&ro, RTF_CLONING);
2626126261Smlaier#endif
2627126261Smlaier#else /* ! __FreeBSD__ */
2628126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
2629126261Smlaier#endif
2630126258Smlaier		rt = ro.ro_rt;
2631126258Smlaier		break;
2632126258Smlaier#endif /* INET */
2633126258Smlaier#ifdef INET6
2634126258Smlaier	case AF_INET6:
2635126258Smlaier		hlen = sizeof(struct ip6_hdr);
2636126258Smlaier		bzero(&ro6, sizeof(ro6));
2637126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
2638126258Smlaier		dst6->sin6_family = AF_INET6;
2639126258Smlaier		dst6->sin6_len = sizeof(*dst6);
2640126258Smlaier		dst6->sin6_addr = addr->v6;
2641127145Smlaier#ifdef __FreeBSD__
2642126261Smlaier#ifdef RTF_PRCLONING
2643126261Smlaier		rtalloc_ign((struct route *)&ro6,
2644126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
2645126261Smlaier#else /* !RTF_PRCLONING */
2646126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
2647126261Smlaier#endif
2648126261Smlaier#else /* ! __FreeBSD__ */
2649126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
2650126261Smlaier#endif
2651126258Smlaier		rt = ro6.ro_rt;
2652126258Smlaier		break;
2653126258Smlaier#endif /* INET6 */
2654126258Smlaier	}
2655126258Smlaier
2656126258Smlaier	if (rt && rt->rt_ifp) {
2657126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
2658126258Smlaier		mss = max(tcp_mssdflt, mss);
2659126258Smlaier		RTFREE(rt);
2660126258Smlaier	}
2661126258Smlaier	mss = min(mss, offer);
2662126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
2663126258Smlaier	return (mss);
2664126258Smlaier}
2665126258Smlaier
2666126258Smlaiervoid
2667126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
2668126258Smlaier{
2669126258Smlaier	struct pf_rule *r = s->rule.ptr;
2670126258Smlaier
2671130613Smlaier	s->rt_kif = NULL;
2672126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
2673126258Smlaier		return;
2674126258Smlaier	switch (s->af) {
2675126258Smlaier#ifdef INET
2676126258Smlaier	case AF_INET:
2677130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
2678130613Smlaier		    &s->nat_src_node);
2679130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2680126258Smlaier		break;
2681126258Smlaier#endif /* INET */
2682126258Smlaier#ifdef INET6
2683126258Smlaier	case AF_INET6:
2684130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
2685130613Smlaier		    &s->nat_src_node);
2686130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2687126258Smlaier		break;
2688126258Smlaier#endif /* INET6 */
2689126258Smlaier	}
2690126258Smlaier}
2691126258Smlaier
2692126258Smlaierint
2693126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
2694130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
2695135920Smlaier#ifdef __FreeBSD__
2696135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
2697135920Smlaier    struct inpcb *inp)
2698135920Smlaier#else
2699126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
2700135920Smlaier#endif
2701126258Smlaier{
2702130613Smlaier	struct pf_rule		*nr = NULL;
2703126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2704126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
2705126258Smlaier	u_int16_t		 bport, nport = 0;
2706126258Smlaier	sa_family_t		 af = pd->af;
2707126258Smlaier	int			 lookup = -1;
2708126258Smlaier	uid_t			 uid;
2709126258Smlaier	gid_t			 gid;
2710126258Smlaier	struct pf_rule		*r, *a = NULL;
2711126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2712130613Smlaier	struct pf_src_node	*nsn = NULL;
2713126258Smlaier	u_short			 reason;
2714126258Smlaier	int			 rewrite = 0;
2715126258Smlaier	struct pf_tag		*pftag = NULL;
2716126258Smlaier	int			 tag = -1;
2717126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2718126258Smlaier
2719126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2720126258Smlaier
2721126258Smlaier	if (direction == PF_OUT) {
2722126258Smlaier		bport = nport = th->th_sport;
2723126258Smlaier		/* check outgoing packet for BINAT/NAT */
2724130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
2725126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
2726130613Smlaier		    &pd->naddr, &nport)) != NULL) {
2727130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
2728126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
2729130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
2730126258Smlaier			rewrite++;
2731130613Smlaier			if (nr->natpass)
2732126258Smlaier				r = NULL;
2733130613Smlaier			pd->nat_rule = nr;
2734126258Smlaier		}
2735126258Smlaier	} else {
2736126258Smlaier		bport = nport = th->th_dport;
2737126258Smlaier		/* check incoming packet for BINAT/RDR */
2738130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
2739130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
2740130613Smlaier		    &pd->naddr, &nport)) != NULL) {
2741130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
2742126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
2743130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
2744126258Smlaier			rewrite++;
2745130613Smlaier			if (nr->natpass)
2746126258Smlaier				r = NULL;
2747130613Smlaier			pd->nat_rule = nr;
2748126258Smlaier		}
2749126258Smlaier	}
2750126258Smlaier
2751126258Smlaier	while (r != NULL) {
2752126258Smlaier		r->evaluations++;
2753130613Smlaier		if (r->kif != NULL &&
2754130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
2755126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2756126258Smlaier		else if (r->direction && r->direction != direction)
2757126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2758126258Smlaier		else if (r->af && r->af != af)
2759126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2760126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
2761126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2762126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
2763126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
2764126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
2765126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
2766126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
2767126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
2768126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2769126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
2770126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
2771126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2772126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
2773126258Smlaier			r = TAILQ_NEXT(r, entries);
2774126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
2775126258Smlaier			r = TAILQ_NEXT(r, entries);
2776126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
2777126258Smlaier			r = TAILQ_NEXT(r, entries);
2778126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
2779135920Smlaier#ifdef __FreeBSD__
2780135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
2781135920Smlaier#else
2782130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
2783135920Smlaier#endif
2784126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
2785126258Smlaier		    uid))
2786126258Smlaier			r = TAILQ_NEXT(r, entries);
2787126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
2788135920Smlaier#ifdef __FreeBSD__
2789135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
2790135920Smlaier#else
2791130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
2792135920Smlaier#endif
2793126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
2794126258Smlaier		    gid))
2795126258Smlaier			r = TAILQ_NEXT(r, entries);
2796130613Smlaier		else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
2797126258Smlaier			r = TAILQ_NEXT(r, entries);
2798126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
2799126258Smlaier			r = TAILQ_NEXT(r, entries);
2800126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
2801126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
2802126258Smlaier			r = TAILQ_NEXT(r, entries);
2803126258Smlaier		else {
2804126258Smlaier			if (r->tag)
2805126258Smlaier				tag = r->tag;
2806126258Smlaier			if (r->anchor == NULL) {
2807126258Smlaier				*rm = r;
2808126258Smlaier				*am = a;
2809126258Smlaier				*rsm = ruleset;
2810126258Smlaier				if ((*rm)->quick)
2811126258Smlaier					break;
2812126258Smlaier				r = TAILQ_NEXT(r, entries);
2813126258Smlaier			} else
2814126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
2815126258Smlaier				    PF_RULESET_FILTER);
2816126258Smlaier		}
2817126258Smlaier		if (r == NULL && a != NULL)
2818126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
2819126258Smlaier			    PF_RULESET_FILTER);
2820126258Smlaier	}
2821126258Smlaier	r = *rm;
2822126258Smlaier	a = *am;
2823126258Smlaier	ruleset = *rsm;
2824126258Smlaier
2825126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
2826126258Smlaier
2827126258Smlaier	if (r->log) {
2828126258Smlaier		if (rewrite)
2829126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
2830130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
2831126258Smlaier	}
2832126258Smlaier
2833126258Smlaier	if ((r->action == PF_DROP) &&
2834126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
2835126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
2836126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
2837126258Smlaier		/* undo NAT changes, if they have taken place */
2838130613Smlaier		if (nr != NULL) {
2839130613Smlaier			if (direction == PF_OUT) {
2840130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
2841130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
2842130613Smlaier				rewrite++;
2843130613Smlaier			} else {
2844130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
2845130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
2846130613Smlaier				rewrite++;
2847130613Smlaier			}
2848126258Smlaier		}
2849126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
2850126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
2851126258Smlaier		    !(th->th_flags & TH_RST)) {
2852126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
2853126258Smlaier
2854126258Smlaier			if (th->th_flags & TH_SYN)
2855126258Smlaier				ack++;
2856126258Smlaier			if (th->th_flags & TH_FIN)
2857126258Smlaier				ack++;
2858126258Smlaier			pf_send_tcp(r, af, pd->dst,
2859126258Smlaier			    pd->src, th->th_dport, th->th_sport,
2860126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
2861126258Smlaier			    r->return_ttl);
2862126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
2863126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
2864126258Smlaier			    r->return_icmp & 255, af, r);
2865126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
2866126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
2867126258Smlaier			    r->return_icmp6 & 255, af, r);
2868126258Smlaier	}
2869126258Smlaier
2870126258Smlaier	if (r->action == PF_DROP)
2871126258Smlaier		return (PF_DROP);
2872126258Smlaier
2873126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
2874126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
2875126258Smlaier		return (PF_DROP);
2876126258Smlaier	}
2877126258Smlaier
2878130613Smlaier	if (r->keep_state || nr != NULL ||
2879126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
2880126258Smlaier		/* create new state */
2881126258Smlaier		u_int16_t	 len;
2882126258Smlaier		struct pf_state	*s = NULL;
2883130613Smlaier		struct pf_src_node *sn = NULL;
2884126258Smlaier
2885126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
2886130613Smlaier
2887130613Smlaier		/* check maximums */
2888130613Smlaier		if (r->max_states && (r->states >= r->max_states))
2889130613Smlaier			goto cleanup;
2890130613Smlaier		/* src node for flter rule */
2891130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
2892130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
2893130613Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0)
2894130613Smlaier			goto cleanup;
2895130613Smlaier		/* src node for translation rule */
2896130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
2897130613Smlaier		    ((direction == PF_OUT &&
2898130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
2899130613Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
2900130613Smlaier			goto cleanup;
2901130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
2902126258Smlaier		if (s == NULL) {
2903130613Smlaiercleanup:
2904130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
2905130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
2906130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
2907130613Smlaier				pf_status.src_nodes--;
2908130613Smlaier				pool_put(&pf_src_tree_pl, sn);
2909130613Smlaier			}
2910130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
2911130613Smlaier			    nsn->expire == 0) {
2912130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
2913130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
2914130613Smlaier				pf_status.src_nodes--;
2915130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
2916130613Smlaier			}
2917126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2918126258Smlaier			return (PF_DROP);
2919126258Smlaier		}
2920126258Smlaier		bzero(s, sizeof(*s));
2921126258Smlaier		r->states++;
2922126258Smlaier		if (a != NULL)
2923126258Smlaier			a->states++;
2924126258Smlaier		s->rule.ptr = r;
2925130613Smlaier		s->nat_rule.ptr = nr;
2926126258Smlaier		if (s->nat_rule.ptr != NULL)
2927126258Smlaier			s->nat_rule.ptr->states++;
2928126258Smlaier		s->anchor.ptr = a;
2929126258Smlaier		s->allow_opts = r->allow_opts;
2930126258Smlaier		s->log = r->log & 2;
2931126258Smlaier		s->proto = IPPROTO_TCP;
2932126258Smlaier		s->direction = direction;
2933126258Smlaier		s->af = af;
2934126258Smlaier		if (direction == PF_OUT) {
2935126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
2936126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
2937126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
2938126258Smlaier			s->ext.port = th->th_dport;
2939130613Smlaier			if (nr != NULL) {
2940130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
2941126258Smlaier				s->lan.port = bport;
2942126258Smlaier			} else {
2943126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
2944126258Smlaier				s->lan.port = s->gwy.port;
2945126258Smlaier			}
2946126258Smlaier		} else {
2947126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
2948126258Smlaier			s->lan.port = th->th_dport;
2949126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
2950126258Smlaier			s->ext.port = th->th_sport;
2951130613Smlaier			if (nr != NULL) {
2952130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
2953126258Smlaier				s->gwy.port = bport;
2954126258Smlaier			} else {
2955126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
2956126258Smlaier				s->gwy.port = s->lan.port;
2957126258Smlaier			}
2958126258Smlaier		}
2959126258Smlaier
2960126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
2961126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
2962126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
2963126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
2964126258Smlaier			/* Generate sequence number modulator */
2965126258Smlaier			while ((s->src.seqdiff = arc4random()) == 0)
2966126258Smlaier				;
2967126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
2968126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
2969126258Smlaier			rewrite = 1;
2970126258Smlaier		} else
2971126258Smlaier			s->src.seqdiff = 0;
2972126258Smlaier		if (th->th_flags & TH_SYN) {
2973126258Smlaier			s->src.seqhi++;
2974126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
2975126258Smlaier		}
2976126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
2977126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
2978126258Smlaier			/* Remove scale factor from initial window */
2979126258Smlaier			int win = s->src.max_win;
2980126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
2981126258Smlaier			s->src.max_win = (win - 1) >>
2982126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
2983126258Smlaier		}
2984126258Smlaier		if (th->th_flags & TH_FIN)
2985126258Smlaier			s->src.seqhi++;
2986126258Smlaier		s->dst.seqhi = 1;
2987126258Smlaier		s->dst.max_win = 1;
2988126258Smlaier		s->src.state = TCPS_SYN_SENT;
2989126258Smlaier		s->dst.state = TCPS_CLOSED;
2990127145Smlaier#ifdef __FreeBSD__
2991126261Smlaier		s->creation = time_second;
2992126261Smlaier		s->expire = time_second;
2993126261Smlaier#else
2994126258Smlaier		s->creation = time.tv_sec;
2995126258Smlaier		s->expire = time.tv_sec;
2996126261Smlaier#endif
2997126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
2998126258Smlaier		pf_set_rt_ifp(s, saddr);
2999130613Smlaier		if (sn != NULL) {
3000130613Smlaier			s->src_node = sn;
3001130613Smlaier			s->src_node->states++;
3002130613Smlaier		}
3003130613Smlaier		if (nsn != NULL) {
3004130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3005130613Smlaier			s->nat_src_node = nsn;
3006130613Smlaier			s->nat_src_node->states++;
3007130613Smlaier		}
3008126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3009126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3010126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3011130613Smlaier			pf_src_tree_remove_state(s);
3012126258Smlaier			pool_put(&pf_state_pl, s);
3013126258Smlaier			return (PF_DROP);
3014126258Smlaier		}
3015126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3016126258Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, &s->src,
3017126258Smlaier		    &s->dst, &rewrite)) {
3018126258Smlaier			pf_normalize_tcp_cleanup(s);
3019130613Smlaier			pf_src_tree_remove_state(s);
3020126258Smlaier			pool_put(&pf_state_pl, s);
3021126258Smlaier			return (PF_DROP);
3022126258Smlaier		}
3023130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3024126258Smlaier			pf_normalize_tcp_cleanup(s);
3025126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3026130613Smlaier			pf_src_tree_remove_state(s);
3027126258Smlaier			pool_put(&pf_state_pl, s);
3028126258Smlaier			return (PF_DROP);
3029126258Smlaier		} else
3030126258Smlaier			*sm = s;
3031126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3032126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3033126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3034130613Smlaier			if (nr != NULL) {
3035130613Smlaier				if (direction == PF_OUT) {
3036130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3037130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3038130613Smlaier					    bport, 0, af);
3039130613Smlaier				} else {
3040130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3041130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3042130613Smlaier					    bport, 0, af);
3043130613Smlaier				}
3044130613Smlaier			}
3045126258Smlaier			s->src.seqhi = arc4random();
3046126258Smlaier			/* Find mss option */
3047126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3048126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3049126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3050126258Smlaier			s->src.mss = mss;
3051126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3052130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3053130613Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0);
3054126258Smlaier			return (PF_SYNPROXY_DROP);
3055126258Smlaier		}
3056126258Smlaier	}
3057126258Smlaier
3058126258Smlaier	/* copy back packet headers if we performed NAT operations */
3059126258Smlaier	if (rewrite)
3060126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3061126258Smlaier
3062126258Smlaier	return (PF_PASS);
3063126258Smlaier}
3064126258Smlaier
3065126258Smlaierint
3066126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3067130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3068135920Smlaier#ifdef __FreeBSD__
3069135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3070135920Smlaier    struct inpcb *inp)
3071135920Smlaier#else
3072126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
3073135920Smlaier#endif
3074126258Smlaier{
3075130613Smlaier	struct pf_rule		*nr = NULL;
3076126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3077126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3078126258Smlaier	u_int16_t		 bport, nport = 0;
3079126258Smlaier	sa_family_t		 af = pd->af;
3080126258Smlaier	int			 lookup = -1;
3081126258Smlaier	uid_t			 uid;
3082126258Smlaier	gid_t			 gid;
3083126258Smlaier	struct pf_rule		*r, *a = NULL;
3084126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3085130613Smlaier	struct pf_src_node	*nsn = NULL;
3086126258Smlaier	u_short			 reason;
3087126258Smlaier	int			 rewrite = 0;
3088126258Smlaier	struct pf_tag		*pftag = NULL;
3089126258Smlaier	int			 tag = -1;
3090126258Smlaier
3091126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3092126258Smlaier
3093126258Smlaier	if (direction == PF_OUT) {
3094126258Smlaier		bport = nport = uh->uh_sport;
3095126258Smlaier		/* check outgoing packet for BINAT/NAT */
3096130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3097126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3098130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3099130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3100126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3101130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3102126258Smlaier			rewrite++;
3103130613Smlaier			if (nr->natpass)
3104126258Smlaier				r = NULL;
3105130613Smlaier			pd->nat_rule = nr;
3106126258Smlaier		}
3107126258Smlaier	} else {
3108126258Smlaier		bport = nport = uh->uh_dport;
3109126258Smlaier		/* check incoming packet for BINAT/RDR */
3110130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3111130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3112130613Smlaier		    &nport)) != NULL) {
3113130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3114126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3115130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3116126258Smlaier			rewrite++;
3117130613Smlaier			if (nr->natpass)
3118126258Smlaier				r = NULL;
3119130613Smlaier			pd->nat_rule = nr;
3120126258Smlaier		}
3121126258Smlaier	}
3122126258Smlaier
3123126258Smlaier	while (r != NULL) {
3124126258Smlaier		r->evaluations++;
3125130613Smlaier		if (r->kif != NULL &&
3126130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3127126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3128126258Smlaier		else if (r->direction && r->direction != direction)
3129126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3130126258Smlaier		else if (r->af && r->af != af)
3131126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3132126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3133126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3134126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
3135126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3136126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3137126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3138126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3139126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
3140126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3141126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3142126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3143126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3144126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3145126258Smlaier			r = TAILQ_NEXT(r, entries);
3146126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3147126258Smlaier			r = TAILQ_NEXT(r, entries);
3148126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3149135920Smlaier#ifdef __FreeBSD__
3150135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3151135920Smlaier#else
3152130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3153135920Smlaier#endif
3154126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3155126258Smlaier		    uid))
3156126258Smlaier			r = TAILQ_NEXT(r, entries);
3157126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3158135920Smlaier#ifdef __FreeBSD__
3159135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3160135920Smlaier#else
3161130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3162135920Smlaier#endif
3163126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3164126258Smlaier		    gid))
3165126258Smlaier			r = TAILQ_NEXT(r, entries);
3166130613Smlaier		else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
3167126258Smlaier			r = TAILQ_NEXT(r, entries);
3168126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3169126258Smlaier			r = TAILQ_NEXT(r, entries);
3170126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3171126258Smlaier			r = TAILQ_NEXT(r, entries);
3172126258Smlaier		else {
3173126258Smlaier			if (r->tag)
3174126258Smlaier				tag = r->tag;
3175126258Smlaier			if (r->anchor == NULL) {
3176126258Smlaier				*rm = r;
3177126258Smlaier				*am = a;
3178126258Smlaier				*rsm = ruleset;
3179126258Smlaier				if ((*rm)->quick)
3180126258Smlaier					break;
3181126258Smlaier				r = TAILQ_NEXT(r, entries);
3182126258Smlaier			} else
3183126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3184126258Smlaier				    PF_RULESET_FILTER);
3185126258Smlaier		}
3186126258Smlaier		if (r == NULL && a != NULL)
3187126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3188126258Smlaier			    PF_RULESET_FILTER);
3189126258Smlaier	}
3190126258Smlaier	r = *rm;
3191126258Smlaier	a = *am;
3192126258Smlaier	ruleset = *rsm;
3193126258Smlaier
3194126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3195126258Smlaier
3196126258Smlaier	if (r->log) {
3197126258Smlaier		if (rewrite)
3198126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3199130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3200126258Smlaier	}
3201126258Smlaier
3202126258Smlaier	if ((r->action == PF_DROP) &&
3203126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3204126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3205126258Smlaier		/* undo NAT changes, if they have taken place */
3206130613Smlaier		if (nr != NULL) {
3207130613Smlaier			if (direction == PF_OUT) {
3208130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3209130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3210130613Smlaier				rewrite++;
3211130613Smlaier			} else {
3212130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3213130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3214130613Smlaier				rewrite++;
3215130613Smlaier			}
3216126258Smlaier		}
3217126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3218126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3219126258Smlaier			    r->return_icmp & 255, af, r);
3220126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3221126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3222126258Smlaier			    r->return_icmp6 & 255, af, r);
3223126258Smlaier	}
3224126258Smlaier
3225126258Smlaier	if (r->action == PF_DROP)
3226126258Smlaier		return (PF_DROP);
3227126258Smlaier
3228126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3229126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3230126258Smlaier		return (PF_DROP);
3231126258Smlaier	}
3232126258Smlaier
3233130613Smlaier	if (r->keep_state || nr != NULL) {
3234126258Smlaier		/* create new state */
3235126258Smlaier		struct pf_state	*s = NULL;
3236130613Smlaier		struct pf_src_node *sn = NULL;
3237126258Smlaier
3238130613Smlaier		/* check maximums */
3239130613Smlaier		if (r->max_states && (r->states >= r->max_states))
3240130613Smlaier			goto cleanup;
3241130613Smlaier		/* src node for flter rule */
3242130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3243130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3244130613Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0)
3245130613Smlaier			goto cleanup;
3246130613Smlaier		/* src node for translation rule */
3247130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3248130613Smlaier		    ((direction == PF_OUT &&
3249130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3250130613Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
3251130613Smlaier			goto cleanup;
3252130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3253126258Smlaier		if (s == NULL) {
3254130613Smlaiercleanup:
3255130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3256130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3257130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3258130613Smlaier				pf_status.src_nodes--;
3259130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3260130613Smlaier			}
3261130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3262130613Smlaier			    nsn->expire == 0) {
3263130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3264130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3265130613Smlaier				pf_status.src_nodes--;
3266130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3267130613Smlaier			}
3268126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3269126258Smlaier			return (PF_DROP);
3270126258Smlaier		}
3271126258Smlaier		bzero(s, sizeof(*s));
3272126258Smlaier		r->states++;
3273126258Smlaier		if (a != NULL)
3274126258Smlaier			a->states++;
3275126258Smlaier		s->rule.ptr = r;
3276130613Smlaier		s->nat_rule.ptr = nr;
3277126258Smlaier		if (s->nat_rule.ptr != NULL)
3278126258Smlaier			s->nat_rule.ptr->states++;
3279126258Smlaier		s->anchor.ptr = a;
3280126258Smlaier		s->allow_opts = r->allow_opts;
3281126258Smlaier		s->log = r->log & 2;
3282126258Smlaier		s->proto = IPPROTO_UDP;
3283126258Smlaier		s->direction = direction;
3284126258Smlaier		s->af = af;
3285126258Smlaier		if (direction == PF_OUT) {
3286126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3287126258Smlaier			s->gwy.port = uh->uh_sport;
3288126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3289126258Smlaier			s->ext.port = uh->uh_dport;
3290130613Smlaier			if (nr != NULL) {
3291130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3292126258Smlaier				s->lan.port = bport;
3293126258Smlaier			} else {
3294126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3295126258Smlaier				s->lan.port = s->gwy.port;
3296126258Smlaier			}
3297126258Smlaier		} else {
3298126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3299126258Smlaier			s->lan.port = uh->uh_dport;
3300126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3301126258Smlaier			s->ext.port = uh->uh_sport;
3302130613Smlaier			if (nr != NULL) {
3303130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3304126258Smlaier				s->gwy.port = bport;
3305126258Smlaier			} else {
3306126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3307126258Smlaier				s->gwy.port = s->lan.port;
3308126258Smlaier			}
3309126258Smlaier		}
3310126258Smlaier		s->src.state = PFUDPS_SINGLE;
3311126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3312127145Smlaier#ifdef __FreeBSD__
3313126261Smlaier		s->creation = time_second;
3314126261Smlaier		s->expire = time_second;
3315126261Smlaier#else
3316126258Smlaier		s->creation = time.tv_sec;
3317126258Smlaier		s->expire = time.tv_sec;
3318126261Smlaier#endif
3319126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3320126258Smlaier		pf_set_rt_ifp(s, saddr);
3321130613Smlaier		if (sn != NULL) {
3322130613Smlaier			s->src_node = sn;
3323130613Smlaier			s->src_node->states++;
3324130613Smlaier		}
3325130613Smlaier		if (nsn != NULL) {
3326130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3327130613Smlaier			s->nat_src_node = nsn;
3328130613Smlaier			s->nat_src_node->states++;
3329130613Smlaier		}
3330130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3331126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3332130613Smlaier			pf_src_tree_remove_state(s);
3333126258Smlaier			pool_put(&pf_state_pl, s);
3334126258Smlaier			return (PF_DROP);
3335126258Smlaier		} else
3336126258Smlaier			*sm = s;
3337126258Smlaier	}
3338126258Smlaier
3339126258Smlaier	/* copy back packet headers if we performed NAT operations */
3340126258Smlaier	if (rewrite)
3341126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3342126258Smlaier
3343126258Smlaier	return (PF_PASS);
3344126258Smlaier}
3345126258Smlaier
3346126258Smlaierint
3347126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3348130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3349126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
3350126258Smlaier{
3351130613Smlaier	struct pf_rule		*nr = NULL;
3352126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3353126258Smlaier	struct pf_rule		*r, *a = NULL;
3354126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3355130613Smlaier	struct pf_src_node	*nsn = NULL;
3356126258Smlaier	u_short			 reason;
3357127629Smlaier	u_int16_t		 icmpid = 0;	/* make the compiler happy */
3358126258Smlaier	sa_family_t		 af = pd->af;
3359127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3360127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3361126258Smlaier	int			 state_icmp = 0;
3362126258Smlaier	struct pf_tag		*pftag = NULL;
3363126258Smlaier	int			 tag = -1;
3364126258Smlaier#ifdef INET6
3365126258Smlaier	int			 rewrite = 0;
3366126258Smlaier#endif /* INET6 */
3367126258Smlaier
3368126258Smlaier	switch (pd->proto) {
3369126258Smlaier#ifdef INET
3370126258Smlaier	case IPPROTO_ICMP:
3371126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3372126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
3373126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
3374126258Smlaier
3375126258Smlaier		if (icmptype == ICMP_UNREACH ||
3376126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
3377126258Smlaier		    icmptype == ICMP_REDIRECT ||
3378126258Smlaier		    icmptype == ICMP_TIMXCEED ||
3379126258Smlaier		    icmptype == ICMP_PARAMPROB)
3380126258Smlaier			state_icmp++;
3381126258Smlaier		break;
3382126258Smlaier#endif /* INET */
3383126258Smlaier#ifdef INET6
3384126258Smlaier	case IPPROTO_ICMPV6:
3385126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
3386126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
3387126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
3388126258Smlaier
3389126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
3390126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
3391126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
3392126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
3393126258Smlaier			state_icmp++;
3394126258Smlaier		break;
3395126258Smlaier#endif /* INET6 */
3396126258Smlaier	}
3397126258Smlaier
3398126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3399126258Smlaier
3400126258Smlaier	if (direction == PF_OUT) {
3401126258Smlaier		/* check outgoing packet for BINAT/NAT */
3402130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3403130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3404130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3405126258Smlaier			switch (af) {
3406126258Smlaier#ifdef INET
3407126258Smlaier			case AF_INET:
3408126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3409130613Smlaier				    pd->naddr.v4.s_addr, 0);
3410126258Smlaier				break;
3411126258Smlaier#endif /* INET */
3412126258Smlaier#ifdef INET6
3413126258Smlaier			case AF_INET6:
3414126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
3415130613Smlaier				    &pd->naddr, 0);
3416126258Smlaier				rewrite++;
3417126258Smlaier				break;
3418126258Smlaier#endif /* INET6 */
3419126258Smlaier			}
3420130613Smlaier			if (nr->natpass)
3421126258Smlaier				r = NULL;
3422130613Smlaier			pd->nat_rule = nr;
3423126258Smlaier		}
3424126258Smlaier	} else {
3425126258Smlaier		/* check incoming packet for BINAT/RDR */
3426130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3427130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3428130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3429126258Smlaier			switch (af) {
3430126258Smlaier#ifdef INET
3431126258Smlaier			case AF_INET:
3432126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3433130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3434126258Smlaier				break;
3435126258Smlaier#endif /* INET */
3436126258Smlaier#ifdef INET6
3437126258Smlaier			case AF_INET6:
3438126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
3439130613Smlaier				    &pd->naddr, 0);
3440126258Smlaier				rewrite++;
3441126258Smlaier				break;
3442126258Smlaier#endif /* INET6 */
3443126258Smlaier			}
3444130613Smlaier			if (nr->natpass)
3445126258Smlaier				r = NULL;
3446130613Smlaier			pd->nat_rule = nr;
3447126258Smlaier		}
3448126258Smlaier	}
3449126258Smlaier
3450126258Smlaier	while (r != NULL) {
3451126258Smlaier		r->evaluations++;
3452130613Smlaier		if (r->kif != NULL &&
3453130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3454126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3455126258Smlaier		else if (r->direction && r->direction != direction)
3456126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3457126258Smlaier		else if (r->af && r->af != af)
3458126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3459126258Smlaier		else if (r->proto && r->proto != pd->proto)
3460126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3461126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
3462126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3463126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
3464126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3465126258Smlaier		else if (r->type && r->type != icmptype + 1)
3466126258Smlaier			r = TAILQ_NEXT(r, entries);
3467126258Smlaier		else if (r->code && r->code != icmpcode + 1)
3468126258Smlaier			r = TAILQ_NEXT(r, entries);
3469126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3470126258Smlaier			r = TAILQ_NEXT(r, entries);
3471126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3472126258Smlaier			r = TAILQ_NEXT(r, entries);
3473130613Smlaier		else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
3474126258Smlaier			r = TAILQ_NEXT(r, entries);
3475126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3476126258Smlaier			r = TAILQ_NEXT(r, entries);
3477126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3478126258Smlaier			r = TAILQ_NEXT(r, entries);
3479126258Smlaier		else {
3480126258Smlaier			if (r->tag)
3481126258Smlaier				tag = r->tag;
3482126258Smlaier			if (r->anchor == NULL) {
3483126258Smlaier				*rm = r;
3484126258Smlaier				*am = a;
3485126258Smlaier				*rsm = ruleset;
3486126258Smlaier				if ((*rm)->quick)
3487126258Smlaier					break;
3488126258Smlaier				r = TAILQ_NEXT(r, entries);
3489126258Smlaier			} else
3490126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3491126258Smlaier				    PF_RULESET_FILTER);
3492126258Smlaier		}
3493126258Smlaier		if (r == NULL && a != NULL)
3494126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3495126258Smlaier			    PF_RULESET_FILTER);
3496126258Smlaier	}
3497126258Smlaier	r = *rm;
3498126258Smlaier	a = *am;
3499126258Smlaier	ruleset = *rsm;
3500126258Smlaier
3501126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3502126258Smlaier
3503126258Smlaier	if (r->log) {
3504126258Smlaier#ifdef INET6
3505126258Smlaier		if (rewrite)
3506126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
3507126261Smlaier			    (caddr_t)pd->hdr.icmp6);
3508126258Smlaier#endif /* INET6 */
3509130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3510126258Smlaier	}
3511126258Smlaier
3512126258Smlaier	if (r->action != PF_PASS)
3513126258Smlaier		return (PF_DROP);
3514126258Smlaier
3515126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3516126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3517126258Smlaier		return (PF_DROP);
3518126258Smlaier	}
3519126258Smlaier
3520130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
3521126258Smlaier		/* create new state */
3522126258Smlaier		struct pf_state	*s = NULL;
3523130613Smlaier		struct pf_src_node *sn = NULL;
3524126258Smlaier
3525130613Smlaier		/* check maximums */
3526130613Smlaier		if (r->max_states && (r->states >= r->max_states))
3527130613Smlaier			goto cleanup;
3528130613Smlaier		/* src node for flter rule */
3529130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3530130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3531130613Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0)
3532130613Smlaier			goto cleanup;
3533130613Smlaier		/* src node for translation rule */
3534130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3535130613Smlaier		    ((direction == PF_OUT &&
3536130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3537130613Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
3538130613Smlaier			goto cleanup;
3539130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3540126258Smlaier		if (s == NULL) {
3541130613Smlaiercleanup:
3542130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3543130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3544130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3545130613Smlaier				pf_status.src_nodes--;
3546130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3547130613Smlaier			}
3548130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3549130613Smlaier			    nsn->expire == 0) {
3550130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3551130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3552130613Smlaier				pf_status.src_nodes--;
3553130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3554130613Smlaier			}
3555126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3556126258Smlaier			return (PF_DROP);
3557126258Smlaier		}
3558126258Smlaier		bzero(s, sizeof(*s));
3559126258Smlaier		r->states++;
3560126258Smlaier		if (a != NULL)
3561126258Smlaier			a->states++;
3562126258Smlaier		s->rule.ptr = r;
3563130613Smlaier		s->nat_rule.ptr = nr;
3564126258Smlaier		if (s->nat_rule.ptr != NULL)
3565126258Smlaier			s->nat_rule.ptr->states++;
3566126258Smlaier		s->anchor.ptr = a;
3567126258Smlaier		s->allow_opts = r->allow_opts;
3568126258Smlaier		s->log = r->log & 2;
3569126258Smlaier		s->proto = pd->proto;
3570126258Smlaier		s->direction = direction;
3571126258Smlaier		s->af = af;
3572126258Smlaier		if (direction == PF_OUT) {
3573126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3574126258Smlaier			s->gwy.port = icmpid;
3575126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3576126258Smlaier			s->ext.port = icmpid;
3577130613Smlaier			if (nr != NULL)
3578130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3579126258Smlaier			else
3580126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3581126258Smlaier			s->lan.port = icmpid;
3582126258Smlaier		} else {
3583126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3584126258Smlaier			s->lan.port = icmpid;
3585126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3586126258Smlaier			s->ext.port = icmpid;
3587130613Smlaier			if (nr != NULL)
3588130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3589126258Smlaier			else
3590126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3591126258Smlaier			s->gwy.port = icmpid;
3592126258Smlaier		}
3593127145Smlaier#ifdef __FreeBSD__
3594126261Smlaier		s->creation = time_second;
3595126261Smlaier		s->expire = time_second;
3596126261Smlaier#else
3597126258Smlaier		s->creation = time.tv_sec;
3598126258Smlaier		s->expire = time.tv_sec;
3599126261Smlaier#endif
3600126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
3601126258Smlaier		pf_set_rt_ifp(s, saddr);
3602130613Smlaier		if (sn != NULL) {
3603130613Smlaier			s->src_node = sn;
3604130613Smlaier			s->src_node->states++;
3605130613Smlaier		}
3606130613Smlaier		if (nsn != NULL) {
3607130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3608130613Smlaier			s->nat_src_node = nsn;
3609130613Smlaier			s->nat_src_node->states++;
3610130613Smlaier		}
3611130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3612126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3613130613Smlaier			pf_src_tree_remove_state(s);
3614126258Smlaier			pool_put(&pf_state_pl, s);
3615126258Smlaier			return (PF_DROP);
3616126258Smlaier		} else
3617126258Smlaier			*sm = s;
3618126258Smlaier	}
3619126258Smlaier
3620126258Smlaier#ifdef INET6
3621126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
3622126258Smlaier	if (rewrite)
3623126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
3624126261Smlaier		    (caddr_t)pd->hdr.icmp6);
3625126258Smlaier#endif /* INET6 */
3626126258Smlaier
3627126258Smlaier	return (PF_PASS);
3628126258Smlaier}
3629126258Smlaier
3630126258Smlaierint
3631126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
3632130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
3633126258Smlaier    struct pf_rule **am, struct pf_ruleset **rsm)
3634126258Smlaier{
3635130613Smlaier	struct pf_rule		*nr = NULL;
3636126258Smlaier	struct pf_rule		*r, *a = NULL;
3637126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3638130613Smlaier	struct pf_src_node	*nsn = NULL;
3639126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3640126258Smlaier	sa_family_t		 af = pd->af;
3641126258Smlaier	u_short			 reason;
3642126258Smlaier	struct pf_tag		*pftag = NULL;
3643126258Smlaier	int			 tag = -1;
3644126258Smlaier
3645126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3646126258Smlaier
3647126258Smlaier	if (direction == PF_OUT) {
3648126258Smlaier		/* check outgoing packet for BINAT/NAT */
3649130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3650130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3651130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3652126258Smlaier			switch (af) {
3653126258Smlaier#ifdef INET
3654126258Smlaier			case AF_INET:
3655126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3656130613Smlaier				    pd->naddr.v4.s_addr, 0);
3657126258Smlaier				break;
3658126258Smlaier#endif /* INET */
3659126258Smlaier#ifdef INET6
3660126258Smlaier			case AF_INET6:
3661130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
3662126258Smlaier				break;
3663126258Smlaier#endif /* INET6 */
3664126258Smlaier			}
3665130613Smlaier			if (nr->natpass)
3666126258Smlaier				r = NULL;
3667130613Smlaier			pd->nat_rule = nr;
3668126258Smlaier		}
3669126258Smlaier	} else {
3670126258Smlaier		/* check incoming packet for BINAT/RDR */
3671130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3672130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3673130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3674126258Smlaier			switch (af) {
3675126258Smlaier#ifdef INET
3676126258Smlaier			case AF_INET:
3677126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3678130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3679126258Smlaier				break;
3680126258Smlaier#endif /* INET */
3681126258Smlaier#ifdef INET6
3682126258Smlaier			case AF_INET6:
3683130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
3684126258Smlaier				break;
3685126258Smlaier#endif /* INET6 */
3686126258Smlaier			}
3687130613Smlaier			if (nr->natpass)
3688126258Smlaier				r = NULL;
3689130613Smlaier			pd->nat_rule = nr;
3690126258Smlaier		}
3691126258Smlaier	}
3692126258Smlaier
3693126258Smlaier	while (r != NULL) {
3694126258Smlaier		r->evaluations++;
3695130613Smlaier		if (r->kif != NULL &&
3696130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3697126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3698126258Smlaier		else if (r->direction && r->direction != direction)
3699126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3700126258Smlaier		else if (r->af && r->af != af)
3701126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3702126258Smlaier		else if (r->proto && r->proto != pd->proto)
3703126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3704126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
3705126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3706126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
3707126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3708126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3709126258Smlaier			r = TAILQ_NEXT(r, entries);
3710126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3711126258Smlaier			r = TAILQ_NEXT(r, entries);
3712130613Smlaier		else if (r->match_tag && !pf_match_tag(m, r, nr, pftag, &tag))
3713126258Smlaier			r = TAILQ_NEXT(r, entries);
3714126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3715126258Smlaier			r = TAILQ_NEXT(r, entries);
3716126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3717126258Smlaier			r = TAILQ_NEXT(r, entries);
3718126258Smlaier		else {
3719126258Smlaier			if (r->tag)
3720126258Smlaier				tag = r->tag;
3721126258Smlaier			if (r->anchor == NULL) {
3722126258Smlaier				*rm = r;
3723126258Smlaier				*am = a;
3724126258Smlaier				*rsm = ruleset;
3725126258Smlaier				if ((*rm)->quick)
3726126258Smlaier					break;
3727126258Smlaier				r = TAILQ_NEXT(r, entries);
3728126258Smlaier			} else
3729126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3730126258Smlaier				    PF_RULESET_FILTER);
3731126258Smlaier		}
3732126258Smlaier		if (r == NULL && a != NULL)
3733126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3734126258Smlaier			    PF_RULESET_FILTER);
3735126258Smlaier	}
3736126258Smlaier	r = *rm;
3737126258Smlaier	a = *am;
3738126258Smlaier	ruleset = *rsm;
3739126258Smlaier
3740126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3741130613Smlaier
3742126258Smlaier	if (r->log)
3743130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3744126258Smlaier
3745126258Smlaier	if ((r->action == PF_DROP) &&
3746126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3747126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3748126258Smlaier		struct pf_addr *a = NULL;
3749126258Smlaier
3750130613Smlaier		if (nr != NULL) {
3751130613Smlaier			if (direction == PF_OUT)
3752130613Smlaier				a = saddr;
3753130613Smlaier			else
3754130613Smlaier				a = daddr;
3755130613Smlaier		}
3756126258Smlaier		if (a != NULL) {
3757126258Smlaier			switch (af) {
3758126258Smlaier#ifdef INET
3759126258Smlaier			case AF_INET:
3760126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
3761130613Smlaier				    pd->baddr.v4.s_addr, 0);
3762126258Smlaier				break;
3763126258Smlaier#endif /* INET */
3764126258Smlaier#ifdef INET6
3765126258Smlaier			case AF_INET6:
3766130613Smlaier				PF_ACPY(a, &pd->baddr, af);
3767126258Smlaier				break;
3768126258Smlaier#endif /* INET6 */
3769126258Smlaier			}
3770126258Smlaier		}
3771126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3772126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3773126258Smlaier			    r->return_icmp & 255, af, r);
3774126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3775126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3776126258Smlaier			    r->return_icmp6 & 255, af, r);
3777126258Smlaier	}
3778126258Smlaier
3779126258Smlaier	if (r->action != PF_PASS)
3780126258Smlaier		return (PF_DROP);
3781126258Smlaier
3782126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3783126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3784126258Smlaier		return (PF_DROP);
3785126258Smlaier	}
3786126258Smlaier
3787130613Smlaier	if (r->keep_state || nr != NULL) {
3788126258Smlaier		/* create new state */
3789126258Smlaier		struct pf_state	*s = NULL;
3790130613Smlaier		struct pf_src_node *sn = NULL;
3791126258Smlaier
3792130613Smlaier		/* check maximums */
3793130613Smlaier		if (r->max_states && (r->states >= r->max_states))
3794130613Smlaier			goto cleanup;
3795130613Smlaier		/* src node for flter rule */
3796130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3797130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3798130613Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0)
3799130613Smlaier			goto cleanup;
3800130613Smlaier		/* src node for translation rule */
3801130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3802130613Smlaier		    ((direction == PF_OUT &&
3803130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3804130613Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0)))
3805130613Smlaier			goto cleanup;
3806130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3807126258Smlaier		if (s == NULL) {
3808130613Smlaiercleanup:
3809130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3810130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3811130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3812130613Smlaier				pf_status.src_nodes--;
3813130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3814130613Smlaier			}
3815130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3816130613Smlaier			    nsn->expire == 0) {
3817130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3818130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3819130613Smlaier				pf_status.src_nodes--;
3820130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3821130613Smlaier			}
3822126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3823126258Smlaier			return (PF_DROP);
3824126258Smlaier		}
3825126258Smlaier		bzero(s, sizeof(*s));
3826126258Smlaier		r->states++;
3827126258Smlaier		if (a != NULL)
3828126258Smlaier			a->states++;
3829126258Smlaier		s->rule.ptr = r;
3830130613Smlaier		s->nat_rule.ptr = nr;
3831126258Smlaier		if (s->nat_rule.ptr != NULL)
3832126258Smlaier			s->nat_rule.ptr->states++;
3833126258Smlaier		s->anchor.ptr = a;
3834126258Smlaier		s->allow_opts = r->allow_opts;
3835126258Smlaier		s->log = r->log & 2;
3836126258Smlaier		s->proto = pd->proto;
3837126258Smlaier		s->direction = direction;
3838126258Smlaier		s->af = af;
3839126258Smlaier		if (direction == PF_OUT) {
3840126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3841126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3842130613Smlaier			if (nr != NULL)
3843130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3844126258Smlaier			else
3845126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3846126258Smlaier		} else {
3847126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3848126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3849130613Smlaier			if (nr != NULL)
3850130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3851126258Smlaier			else
3852126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3853126258Smlaier		}
3854126258Smlaier		s->src.state = PFOTHERS_SINGLE;
3855126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
3856127145Smlaier#ifdef __FreeBSD__
3857126261Smlaier		s->creation = time_second;
3858126261Smlaier		s->expire = time_second;
3859126261Smlaier#else
3860126258Smlaier		s->creation = time.tv_sec;
3861126258Smlaier		s->expire = time.tv_sec;
3862126261Smlaier#endif
3863126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
3864126258Smlaier		pf_set_rt_ifp(s, saddr);
3865130613Smlaier		if (sn != NULL) {
3866130613Smlaier			s->src_node = sn;
3867130613Smlaier			s->src_node->states++;
3868130613Smlaier		}
3869130613Smlaier		if (nsn != NULL) {
3870130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3871130613Smlaier			s->nat_src_node = nsn;
3872130613Smlaier			s->nat_src_node->states++;
3873130613Smlaier		}
3874130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3875126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3876130613Smlaier			pf_src_tree_remove_state(s);
3877126258Smlaier			pool_put(&pf_state_pl, s);
3878126258Smlaier			return (PF_DROP);
3879126258Smlaier		} else
3880126258Smlaier			*sm = s;
3881126258Smlaier	}
3882126258Smlaier
3883126258Smlaier	return (PF_PASS);
3884126258Smlaier}
3885126258Smlaier
3886126258Smlaierint
3887130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
3888126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
3889126258Smlaier    struct pf_ruleset **rsm)
3890126258Smlaier{
3891126258Smlaier	struct pf_rule		*r, *a = NULL;
3892126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3893126258Smlaier	sa_family_t		 af = pd->af;
3894126258Smlaier	u_short			 reason;
3895126258Smlaier	struct pf_tag		*pftag = NULL;
3896126258Smlaier	int			 tag = -1;
3897126258Smlaier
3898126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3899126258Smlaier	while (r != NULL) {
3900126258Smlaier		r->evaluations++;
3901130613Smlaier		if (r->kif != NULL &&
3902130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3903126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3904126258Smlaier		else if (r->direction && r->direction != direction)
3905126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3906126258Smlaier		else if (r->af && r->af != af)
3907126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3908126258Smlaier		else if (r->proto && r->proto != pd->proto)
3909126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3910126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
3911126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3912126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
3913126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3914126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3915126258Smlaier			r = TAILQ_NEXT(r, entries);
3916126258Smlaier		else if (r->src.port_op || r->dst.port_op ||
3917126258Smlaier		    r->flagset || r->type || r->code ||
3918126258Smlaier		    r->os_fingerprint != PF_OSFP_ANY)
3919126258Smlaier			r = TAILQ_NEXT(r, entries);
3920130613Smlaier		else if (r->match_tag && !pf_match_tag(m, r, NULL, pftag, &tag))
3921126258Smlaier			r = TAILQ_NEXT(r, entries);
3922126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3923126258Smlaier			r = TAILQ_NEXT(r, entries);
3924126258Smlaier		else {
3925126258Smlaier			if (r->anchor == NULL) {
3926126258Smlaier				*rm = r;
3927126258Smlaier				*am = a;
3928126258Smlaier				*rsm = ruleset;
3929126258Smlaier				if ((*rm)->quick)
3930126258Smlaier					break;
3931126258Smlaier				r = TAILQ_NEXT(r, entries);
3932126258Smlaier			} else
3933126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3934126258Smlaier				    PF_RULESET_FILTER);
3935126258Smlaier		}
3936126258Smlaier		if (r == NULL && a != NULL)
3937126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3938126258Smlaier			    PF_RULESET_FILTER);
3939126258Smlaier	}
3940126258Smlaier	r = *rm;
3941126258Smlaier	a = *am;
3942126258Smlaier	ruleset = *rsm;
3943126258Smlaier
3944126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3945130613Smlaier
3946126258Smlaier	if (r->log)
3947130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3948126258Smlaier
3949126258Smlaier	if (r->action != PF_PASS)
3950126258Smlaier		return (PF_DROP);
3951126258Smlaier
3952126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3953126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3954126258Smlaier		return (PF_DROP);
3955126258Smlaier	}
3956126258Smlaier
3957126258Smlaier	return (PF_PASS);
3958126258Smlaier}
3959126258Smlaier
3960126258Smlaierint
3961130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
3962130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
3963126258Smlaier    u_short *reason)
3964126258Smlaier{
3965130613Smlaier	struct pf_state		 key;
3966126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3967126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
3968126258Smlaier	u_int32_t		 ack, end, seq;
3969126258Smlaier	u_int8_t		 sws, dws;
3970130613Smlaier	int			 ackskew;
3971126258Smlaier	int			 copyback = 0;
3972126258Smlaier	struct pf_state_peer	*src, *dst;
3973126258Smlaier
3974126258Smlaier	key.af = pd->af;
3975126258Smlaier	key.proto = IPPROTO_TCP;
3976130613Smlaier	if (direction == PF_IN)	{
3977130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
3978130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
3979130613Smlaier		key.ext.port = th->th_sport;
3980130613Smlaier		key.gwy.port = th->th_dport;
3981130613Smlaier	} else {
3982130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
3983130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
3984130613Smlaier		key.lan.port = th->th_sport;
3985130613Smlaier		key.ext.port = th->th_dport;
3986130613Smlaier	}
3987126258Smlaier
3988126258Smlaier	STATE_LOOKUP();
3989126258Smlaier
3990126258Smlaier	if (direction == (*state)->direction) {
3991126258Smlaier		src = &(*state)->src;
3992126258Smlaier		dst = &(*state)->dst;
3993126258Smlaier	} else {
3994126258Smlaier		src = &(*state)->dst;
3995126258Smlaier		dst = &(*state)->src;
3996126258Smlaier	}
3997126258Smlaier
3998126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
3999126258Smlaier		if (direction != (*state)->direction)
4000126258Smlaier			return (PF_SYNPROXY_DROP);
4001126258Smlaier		if (th->th_flags & TH_SYN) {
4002126258Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo)
4003126258Smlaier				return (PF_DROP);
4004126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4005126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4006126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4007126258Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0);
4008126258Smlaier			return (PF_SYNPROXY_DROP);
4009126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4010126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4011126258Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
4012126258Smlaier			return (PF_DROP);
4013126258Smlaier		else
4014126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4015126258Smlaier	}
4016126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4017126258Smlaier		struct pf_state_host *src, *dst;
4018126258Smlaier
4019126258Smlaier		if (direction == PF_OUT) {
4020126258Smlaier			src = &(*state)->gwy;
4021126258Smlaier			dst = &(*state)->ext;
4022126258Smlaier		} else {
4023126258Smlaier			src = &(*state)->ext;
4024126258Smlaier			dst = &(*state)->lan;
4025126258Smlaier		}
4026126258Smlaier		if (direction == (*state)->direction) {
4027126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4028126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4029126258Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
4030126258Smlaier				return (PF_DROP);
4031126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4032126258Smlaier			if ((*state)->dst.seqhi == 1)
4033126258Smlaier				(*state)->dst.seqhi = arc4random();
4034126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4035126258Smlaier			    &dst->addr, src->port, dst->port,
4036130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4037130613Smlaier			    (*state)->src.mss, 0);
4038126258Smlaier			return (PF_SYNPROXY_DROP);
4039126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4040126258Smlaier		    (TH_SYN|TH_ACK)) ||
4041126258Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1))
4042126258Smlaier			return (PF_DROP);
4043126258Smlaier		else {
4044126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4045126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4046126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4047126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4048126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4049126258Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0);
4050126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4051126258Smlaier			    &dst->addr, src->port, dst->port,
4052126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4053126258Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0);
4054126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4055126258Smlaier			    (*state)->src.seqlo;
4056126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4057126258Smlaier			    (*state)->dst.seqlo;
4058126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4059126258Smlaier			    (*state)->src.max_win;
4060126258Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4061126258Smlaier			    (*state)->dst.max_win;
4062126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4063126258Smlaier			(*state)->src.state = (*state)->dst.state =
4064126258Smlaier			    TCPS_ESTABLISHED;
4065126258Smlaier			return (PF_SYNPROXY_DROP);
4066126258Smlaier		}
4067126258Smlaier	}
4068126258Smlaier
4069126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4070126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4071126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4072126258Smlaier	} else
4073126258Smlaier		sws = dws = 0;
4074126258Smlaier
4075126258Smlaier	/*
4076126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4077126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4078126258Smlaier	 *	tcp_filtering.ps
4079126258Smlaier	 */
4080126258Smlaier
4081126258Smlaier	seq = ntohl(th->th_seq);
4082126258Smlaier	if (src->seqlo == 0) {
4083126258Smlaier		/* First packet from this end. Set its state */
4084126258Smlaier
4085126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4086126258Smlaier		    src->scrub == NULL) {
4087126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4088126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4089126258Smlaier				return (PF_DROP);
4090126258Smlaier			}
4091126258Smlaier		}
4092126258Smlaier
4093126258Smlaier		/* Deferred generation of sequence number modulator */
4094126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4095126258Smlaier			while ((src->seqdiff = arc4random()) == 0)
4096126258Smlaier				;
4097126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4098126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4099126258Smlaier			    src->seqdiff), 0);
4100126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4101126258Smlaier			copyback = 1;
4102126258Smlaier		} else {
4103126258Smlaier			ack = ntohl(th->th_ack);
4104126258Smlaier		}
4105126258Smlaier
4106126258Smlaier		end = seq + pd->p_len;
4107126258Smlaier		if (th->th_flags & TH_SYN) {
4108126258Smlaier			end++;
4109126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4110126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4111126258Smlaier				    pd->af);
4112126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4113126258Smlaier					/* Remove scale factor from initial
4114126258Smlaier					 * window */
4115126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4116126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4117126258Smlaier					    >> sws;
4118126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4119126258Smlaier				} else {
4120126258Smlaier					/* fixup other window */
4121126258Smlaier					dst->max_win <<= dst->wscale &
4122126258Smlaier					    PF_WSCALE_MASK;
4123126258Smlaier					/* in case of a retrans SYN|ACK */
4124126258Smlaier					dst->wscale = 0;
4125126258Smlaier				}
4126126258Smlaier			}
4127126258Smlaier		}
4128126258Smlaier		if (th->th_flags & TH_FIN)
4129126258Smlaier			end++;
4130126258Smlaier
4131126258Smlaier		src->seqlo = seq;
4132126258Smlaier		if (src->state < TCPS_SYN_SENT)
4133126258Smlaier			src->state = TCPS_SYN_SENT;
4134126258Smlaier
4135126258Smlaier		/*
4136126258Smlaier		 * May need to slide the window (seqhi may have been set by
4137126258Smlaier		 * the crappy stack check or if we picked up the connection
4138126258Smlaier		 * after establishment)
4139126258Smlaier		 */
4140126258Smlaier		if (src->seqhi == 1 ||
4141126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4142126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4143126258Smlaier		if (win > src->max_win)
4144126258Smlaier			src->max_win = win;
4145126258Smlaier
4146126258Smlaier	} else {
4147126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4148126258Smlaier		if (src->seqdiff) {
4149126258Smlaier			/* Modulate sequence numbers */
4150126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4151126258Smlaier			    src->seqdiff), 0);
4152126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4153126258Smlaier			copyback = 1;
4154126258Smlaier		}
4155126258Smlaier		end = seq + pd->p_len;
4156126258Smlaier		if (th->th_flags & TH_SYN)
4157126258Smlaier			end++;
4158126258Smlaier		if (th->th_flags & TH_FIN)
4159126258Smlaier			end++;
4160126258Smlaier	}
4161126258Smlaier
4162126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4163126258Smlaier		/* Let it pass through the ack skew check */
4164126258Smlaier		ack = dst->seqlo;
4165126258Smlaier	} else if ((ack == 0 &&
4166126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4167126258Smlaier	    /* broken tcp stacks do not set ack */
4168126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4169126258Smlaier		/*
4170126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4171126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4172126258Smlaier		 */
4173126258Smlaier		ack = dst->seqlo;
4174126258Smlaier	}
4175126258Smlaier
4176126258Smlaier	if (seq == end) {
4177126258Smlaier		/* Ease sequencing restrictions on no data packets */
4178126258Smlaier		seq = src->seqlo;
4179126258Smlaier		end = seq;
4180126258Smlaier	}
4181126258Smlaier
4182126258Smlaier	ackskew = dst->seqlo - ack;
4183126258Smlaier
4184126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4185126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4186126258Smlaier	    /* Last octet inside other's window space */
4187126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4188126258Smlaier	    /* Retrans: not more than one window back */
4189126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4190126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4191126258Smlaier	    (ackskew <= (MAXACKWINDOW << sws))) {
4192126258Smlaier	    /* Acking not more than one window forward */
4193126258Smlaier
4194126258Smlaier		/* update max window */
4195126258Smlaier		if (src->max_win < win)
4196126258Smlaier			src->max_win = win;
4197126258Smlaier		/* synchronize sequencing */
4198126258Smlaier		if (SEQ_GT(end, src->seqlo))
4199126258Smlaier			src->seqlo = end;
4200126258Smlaier		/* slide the window of what the other end can send */
4201126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4202126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4203126258Smlaier
4204126258Smlaier
4205126258Smlaier		/* update states */
4206126258Smlaier		if (th->th_flags & TH_SYN)
4207126258Smlaier			if (src->state < TCPS_SYN_SENT)
4208126258Smlaier				src->state = TCPS_SYN_SENT;
4209126258Smlaier		if (th->th_flags & TH_FIN)
4210126258Smlaier			if (src->state < TCPS_CLOSING)
4211126258Smlaier				src->state = TCPS_CLOSING;
4212126258Smlaier		if (th->th_flags & TH_ACK) {
4213126258Smlaier			if (dst->state == TCPS_SYN_SENT)
4214126258Smlaier				dst->state = TCPS_ESTABLISHED;
4215126258Smlaier			else if (dst->state == TCPS_CLOSING)
4216126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4217126258Smlaier		}
4218126258Smlaier		if (th->th_flags & TH_RST)
4219126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4220126258Smlaier
4221126258Smlaier		/* update expire time */
4222127145Smlaier#ifdef __FreeBSD__
4223126261Smlaier		(*state)->expire = time_second;
4224126261Smlaier#else
4225126258Smlaier		(*state)->expire = time.tv_sec;
4226126261Smlaier#endif
4227126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4228126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4229126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4230126258Smlaier		else if (src->state >= TCPS_FIN_WAIT_2 ||
4231126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4232126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4233126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4234126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4235126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4236126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4237126258Smlaier		    dst->state >= TCPS_CLOSING)
4238126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4239126258Smlaier		else
4240126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4241126258Smlaier
4242126258Smlaier		/* Fall through to PASS packet */
4243126258Smlaier
4244126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4245126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4246126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4247126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4248126258Smlaier	    /* Within a window forward of the originating packet */
4249126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4250126258Smlaier	    /* Within a window backward of the originating packet */
4251126258Smlaier
4252126258Smlaier		/*
4253126258Smlaier		 * This currently handles three situations:
4254126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
4255126258Smlaier		 *     replies.
4256126258Smlaier		 *  2) When PF catches an already established stream (the
4257126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
4258126258Smlaier		 *     changed...)
4259126258Smlaier		 *  3) Packets get funky immediately after the connection
4260126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
4261126258Smlaier		 *     that web servers like to spew after a close)
4262126258Smlaier		 *
4263126258Smlaier		 * This must be a little more careful than the above code
4264126258Smlaier		 * since packet floods will also be caught here. We don't
4265126258Smlaier		 * update the TTL here to mitigate the damage of a packet
4266126258Smlaier		 * flood and so the same code can handle awkward establishment
4267126258Smlaier		 * and a loosened connection close.
4268126258Smlaier		 * In the establishment case, a correct peer response will
4269126258Smlaier		 * validate the connection, go through the normal state code
4270126258Smlaier		 * and keep updating the state TTL.
4271126258Smlaier		 */
4272126258Smlaier
4273126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4274126258Smlaier			printf("pf: loose state match: ");
4275126258Smlaier			pf_print_state(*state);
4276126258Smlaier			pf_print_flags(th->th_flags);
4277126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
4278126258Smlaier			    seq, ack, pd->p_len, ackskew,
4279126258Smlaier			    (*state)->packets[0], (*state)->packets[1]);
4280126258Smlaier		}
4281126258Smlaier
4282126258Smlaier		/* update max window */
4283126258Smlaier		if (src->max_win < win)
4284126258Smlaier			src->max_win = win;
4285126258Smlaier		/* synchronize sequencing */
4286126258Smlaier		if (SEQ_GT(end, src->seqlo))
4287126258Smlaier			src->seqlo = end;
4288126258Smlaier		/* slide the window of what the other end can send */
4289126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4290126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4291126258Smlaier
4292126258Smlaier		/*
4293126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
4294126258Smlaier		 * SYN and not an already established connection.
4295126258Smlaier		 */
4296126258Smlaier
4297126258Smlaier		if (th->th_flags & TH_FIN)
4298126258Smlaier			if (src->state < TCPS_CLOSING)
4299126258Smlaier				src->state = TCPS_CLOSING;
4300126258Smlaier		if (th->th_flags & TH_RST)
4301126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4302126258Smlaier
4303126258Smlaier		/* Fall through to PASS packet */
4304126258Smlaier
4305126258Smlaier	} else {
4306126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
4307126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
4308126258Smlaier			/* Send RST for state mismatches during handshake */
4309126258Smlaier			if (!(th->th_flags & TH_RST)) {
4310126258Smlaier				u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
4311126258Smlaier
4312126258Smlaier				if (th->th_flags & TH_SYN)
4313126258Smlaier					ack++;
4314126258Smlaier				if (th->th_flags & TH_FIN)
4315126258Smlaier					ack++;
4316126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
4317126258Smlaier				    pd->dst, pd->src, th->th_dport,
4318126258Smlaier				    th->th_sport, ntohl(th->th_ack), ack,
4319126258Smlaier				    TH_RST|TH_ACK, 0, 0,
4320126258Smlaier				    (*state)->rule.ptr->return_ttl);
4321126258Smlaier			}
4322126258Smlaier			src->seqlo = 0;
4323126258Smlaier			src->seqhi = 1;
4324126258Smlaier			src->max_win = 1;
4325126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
4326126258Smlaier			printf("pf: BAD state: ");
4327126258Smlaier			pf_print_state(*state);
4328126258Smlaier			pf_print_flags(th->th_flags);
4329126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
4330126258Smlaier			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
4331126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
4332126258Smlaier			    direction == PF_IN ? "in" : "out",
4333126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
4334126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
4335126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
4336126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
4337126258Smlaier			    ' ': '2',
4338126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
4339126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
4340126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
4341126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
4342126258Smlaier		}
4343126258Smlaier		return (PF_DROP);
4344126258Smlaier	}
4345126258Smlaier
4346126258Smlaier	if (dst->scrub || src->scrub) {
4347130613Smlaier		if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4348130613Smlaier		    src, dst, &copyback))
4349126258Smlaier			return (PF_DROP);
4350126258Smlaier	}
4351126258Smlaier
4352126258Smlaier	/* Any packets which have gotten here are to be passed */
4353126258Smlaier
4354126258Smlaier	/* translate source/destination address, if necessary */
4355126258Smlaier	if (STATE_TRANSLATE(*state)) {
4356126258Smlaier		if (direction == PF_OUT)
4357126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
4358126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
4359126258Smlaier			    (*state)->gwy.port, 0, pd->af);
4360126258Smlaier		else
4361126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
4362126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
4363126258Smlaier			    (*state)->lan.port, 0, pd->af);
4364126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4365126258Smlaier	} else if (copyback) {
4366126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
4367126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4368126258Smlaier	}
4369126258Smlaier
4370126258Smlaier	return (PF_PASS);
4371126258Smlaier}
4372126258Smlaier
4373126258Smlaierint
4374130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
4375130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4376126258Smlaier{
4377126258Smlaier	struct pf_state_peer	*src, *dst;
4378130613Smlaier	struct pf_state		 key;
4379126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
4380126258Smlaier
4381126258Smlaier	key.af = pd->af;
4382126258Smlaier	key.proto = IPPROTO_UDP;
4383130613Smlaier	if (direction == PF_IN)	{
4384130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4385130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4386130613Smlaier		key.ext.port = uh->uh_sport;
4387130613Smlaier		key.gwy.port = uh->uh_dport;
4388130613Smlaier	} else {
4389130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4390130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4391130613Smlaier		key.lan.port = uh->uh_sport;
4392130613Smlaier		key.ext.port = uh->uh_dport;
4393130613Smlaier	}
4394126258Smlaier
4395126258Smlaier	STATE_LOOKUP();
4396126258Smlaier
4397126258Smlaier	if (direction == (*state)->direction) {
4398126258Smlaier		src = &(*state)->src;
4399126258Smlaier		dst = &(*state)->dst;
4400126258Smlaier	} else {
4401126258Smlaier		src = &(*state)->dst;
4402126258Smlaier		dst = &(*state)->src;
4403126258Smlaier	}
4404126258Smlaier
4405126258Smlaier	/* update states */
4406126258Smlaier	if (src->state < PFUDPS_SINGLE)
4407126258Smlaier		src->state = PFUDPS_SINGLE;
4408126258Smlaier	if (dst->state == PFUDPS_SINGLE)
4409126258Smlaier		dst->state = PFUDPS_MULTIPLE;
4410126258Smlaier
4411126258Smlaier	/* update expire time */
4412127145Smlaier#ifdef __FreeBSD__
4413126261Smlaier	(*state)->expire = time_second;
4414126261Smlaier#else
4415126258Smlaier	(*state)->expire = time.tv_sec;
4416126261Smlaier#endif
4417126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
4418126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
4419126258Smlaier	else
4420126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
4421126258Smlaier
4422126258Smlaier	/* translate source/destination address, if necessary */
4423126258Smlaier	if (STATE_TRANSLATE(*state)) {
4424126258Smlaier		if (direction == PF_OUT)
4425126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
4426126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
4427126258Smlaier			    (*state)->gwy.port, 1, pd->af);
4428126258Smlaier		else
4429126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
4430126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
4431126258Smlaier			    (*state)->lan.port, 1, pd->af);
4432126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
4433126258Smlaier	}
4434126258Smlaier
4435126258Smlaier	return (PF_PASS);
4436126258Smlaier}
4437126258Smlaier
4438126258Smlaierint
4439130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
4440130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4441126258Smlaier{
4442126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
4443127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
4444127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
4445127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
4446130613Smlaier	int		 state_icmp = 0;
4447126258Smlaier
4448126258Smlaier	switch (pd->proto) {
4449126258Smlaier#ifdef INET
4450126258Smlaier	case IPPROTO_ICMP:
4451126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4452126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4453126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
4454126258Smlaier
4455126258Smlaier		if (icmptype == ICMP_UNREACH ||
4456126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4457126258Smlaier		    icmptype == ICMP_REDIRECT ||
4458126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4459126258Smlaier		    icmptype == ICMP_PARAMPROB)
4460126258Smlaier			state_icmp++;
4461126258Smlaier		break;
4462126258Smlaier#endif /* INET */
4463126258Smlaier#ifdef INET6
4464126258Smlaier	case IPPROTO_ICMPV6:
4465126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4466126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4467126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
4468126258Smlaier
4469126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4470126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4471126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4472126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4473126258Smlaier			state_icmp++;
4474126258Smlaier		break;
4475126258Smlaier#endif /* INET6 */
4476126258Smlaier	}
4477126258Smlaier
4478126258Smlaier	if (!state_icmp) {
4479126258Smlaier
4480126258Smlaier		/*
4481126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
4482126258Smlaier		 * Search for an ICMP state.
4483126258Smlaier		 */
4484130613Smlaier		struct pf_state		key;
4485126258Smlaier
4486126258Smlaier		key.af = pd->af;
4487126258Smlaier		key.proto = pd->proto;
4488130613Smlaier		if (direction == PF_IN)	{
4489130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
4490130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4491130613Smlaier			key.ext.port = icmpid;
4492130613Smlaier			key.gwy.port = icmpid;
4493130613Smlaier		} else {
4494130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
4495130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
4496130613Smlaier			key.lan.port = icmpid;
4497130613Smlaier			key.ext.port = icmpid;
4498130613Smlaier		}
4499126258Smlaier
4500126258Smlaier		STATE_LOOKUP();
4501126258Smlaier
4502127145Smlaier#ifdef __FreeBSD__
4503126261Smlaier		(*state)->expire = time_second;
4504126261Smlaier#else
4505126258Smlaier		(*state)->expire = time.tv_sec;
4506126261Smlaier#endif
4507126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
4508126258Smlaier
4509126258Smlaier		/* translate source/destination address, if necessary */
4510126258Smlaier		if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) {
4511126258Smlaier			if (direction == PF_OUT) {
4512126258Smlaier				switch (pd->af) {
4513126258Smlaier#ifdef INET
4514126258Smlaier				case AF_INET:
4515126258Smlaier					pf_change_a(&saddr->v4.s_addr,
4516126258Smlaier					    pd->ip_sum,
4517126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
4518126258Smlaier					break;
4519126258Smlaier#endif /* INET */
4520126258Smlaier#ifdef INET6
4521126258Smlaier				case AF_INET6:
4522126258Smlaier					pf_change_a6(saddr,
4523126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4524126258Smlaier					    &(*state)->gwy.addr, 0);
4525126258Smlaier					m_copyback(m, off,
4526126258Smlaier					    sizeof(struct icmp6_hdr),
4527126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4528126258Smlaier					break;
4529126258Smlaier#endif /* INET6 */
4530126258Smlaier				}
4531126258Smlaier			} else {
4532126258Smlaier				switch (pd->af) {
4533126258Smlaier#ifdef INET
4534126258Smlaier				case AF_INET:
4535126258Smlaier					pf_change_a(&daddr->v4.s_addr,
4536126258Smlaier					    pd->ip_sum,
4537126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
4538126258Smlaier					break;
4539126258Smlaier#endif /* INET */
4540126258Smlaier#ifdef INET6
4541126258Smlaier				case AF_INET6:
4542126258Smlaier					pf_change_a6(daddr,
4543126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4544126258Smlaier					    &(*state)->lan.addr, 0);
4545126258Smlaier					m_copyback(m, off,
4546126258Smlaier					    sizeof(struct icmp6_hdr),
4547126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4548126258Smlaier					break;
4549126258Smlaier#endif /* INET6 */
4550126258Smlaier				}
4551126258Smlaier			}
4552126258Smlaier		}
4553126258Smlaier
4554126258Smlaier		return (PF_PASS);
4555126258Smlaier
4556126258Smlaier	} else {
4557126258Smlaier		/*
4558126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
4559126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
4560126258Smlaier		 */
4561126258Smlaier
4562126258Smlaier		struct pf_pdesc	pd2;
4563126258Smlaier#ifdef INET
4564126258Smlaier		struct ip	h2;
4565126258Smlaier#endif /* INET */
4566126258Smlaier#ifdef INET6
4567126258Smlaier		struct ip6_hdr	h2_6;
4568126258Smlaier		int		terminal = 0;
4569126258Smlaier#endif /* INET6 */
4570127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
4571127629Smlaier		int		off2 = 0;	/* make the compiler happy */
4572126258Smlaier
4573126258Smlaier		pd2.af = pd->af;
4574126258Smlaier		switch (pd->af) {
4575126258Smlaier#ifdef INET
4576126258Smlaier		case AF_INET:
4577126258Smlaier			/* offset of h2 in mbuf chain */
4578126258Smlaier			ipoff2 = off + ICMP_MINLEN;
4579126258Smlaier
4580126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
4581126258Smlaier			    NULL, NULL, pd2.af)) {
4582126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4583126258Smlaier				    ("pf: ICMP error message too short "
4584126258Smlaier				    "(ip)\n"));
4585126258Smlaier				return (PF_DROP);
4586126258Smlaier			}
4587126258Smlaier			/*
4588126258Smlaier			 * ICMP error messages don't refer to non-first
4589126258Smlaier			 * fragments
4590126258Smlaier			 */
4591126258Smlaier			if (h2.ip_off & htons(IP_OFFMASK))
4592126258Smlaier				return (PF_DROP);
4593126258Smlaier
4594126258Smlaier			/* offset of protocol header that follows h2 */
4595126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
4596126258Smlaier
4597126258Smlaier			pd2.proto = h2.ip_p;
4598126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
4599126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
4600126258Smlaier			pd2.ip_sum = &h2.ip_sum;
4601126258Smlaier			break;
4602126258Smlaier#endif /* INET */
4603126258Smlaier#ifdef INET6
4604126258Smlaier		case AF_INET6:
4605126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
4606126258Smlaier
4607126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
4608126258Smlaier			    NULL, NULL, pd2.af)) {
4609126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4610126258Smlaier				    ("pf: ICMP error message too short "
4611126258Smlaier				    "(ip6)\n"));
4612126258Smlaier				return (PF_DROP);
4613126258Smlaier			}
4614126258Smlaier			pd2.proto = h2_6.ip6_nxt;
4615126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
4616126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
4617126258Smlaier			pd2.ip_sum = NULL;
4618126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
4619126258Smlaier			do {
4620126258Smlaier				switch (pd2.proto) {
4621126258Smlaier				case IPPROTO_FRAGMENT:
4622126258Smlaier					/*
4623126258Smlaier					 * ICMPv6 error messages for
4624126258Smlaier					 * non-first fragments
4625126258Smlaier					 */
4626126258Smlaier					return (PF_DROP);
4627126258Smlaier				case IPPROTO_AH:
4628126258Smlaier				case IPPROTO_HOPOPTS:
4629126258Smlaier				case IPPROTO_ROUTING:
4630126258Smlaier				case IPPROTO_DSTOPTS: {
4631126258Smlaier					/* get next header and header length */
4632126258Smlaier					struct ip6_ext opt6;
4633126258Smlaier
4634126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
4635126258Smlaier					    sizeof(opt6), NULL, NULL, pd2.af)) {
4636126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
4637126258Smlaier						    ("pf: ICMPv6 short opt\n"));
4638126258Smlaier						return (PF_DROP);
4639126258Smlaier					}
4640126258Smlaier					if (pd2.proto == IPPROTO_AH)
4641126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
4642126258Smlaier					else
4643126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
4644126258Smlaier					pd2.proto = opt6.ip6e_nxt;
4645126258Smlaier					/* goto the next header */
4646126258Smlaier					break;
4647126258Smlaier				}
4648126258Smlaier				default:
4649126258Smlaier					terminal++;
4650126258Smlaier					break;
4651126258Smlaier				}
4652126258Smlaier			} while (!terminal);
4653126258Smlaier			break;
4654126258Smlaier#endif /* INET6 */
4655126258Smlaier		}
4656126258Smlaier
4657126258Smlaier		switch (pd2.proto) {
4658126258Smlaier		case IPPROTO_TCP: {
4659126258Smlaier			struct tcphdr		 th;
4660126258Smlaier			u_int32_t		 seq;
4661130613Smlaier			struct pf_state		 key;
4662126258Smlaier			struct pf_state_peer	*src, *dst;
4663126258Smlaier			u_int8_t		 dws;
4664128129Smlaier			int			 copyback = 0;
4665126258Smlaier
4666126258Smlaier			/*
4667126258Smlaier			 * Only the first 8 bytes of the TCP header can be
4668126258Smlaier			 * expected. Don't access any TCP header fields after
4669126258Smlaier			 * th_seq, an ackskew test is not possible.
4670126258Smlaier			 */
4671126258Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) {
4672126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4673126258Smlaier				    ("pf: ICMP error message too short "
4674126258Smlaier				    "(tcp)\n"));
4675126258Smlaier				return (PF_DROP);
4676126258Smlaier			}
4677126258Smlaier
4678126258Smlaier			key.af = pd2.af;
4679126258Smlaier			key.proto = IPPROTO_TCP;
4680130613Smlaier			if (direction == PF_IN)	{
4681130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4682130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4683130613Smlaier				key.ext.port = th.th_dport;
4684130613Smlaier				key.gwy.port = th.th_sport;
4685130613Smlaier			} else {
4686130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4687130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
4688130613Smlaier				key.lan.port = th.th_dport;
4689130613Smlaier				key.ext.port = th.th_sport;
4690130613Smlaier			}
4691126258Smlaier
4692126258Smlaier			STATE_LOOKUP();
4693126258Smlaier
4694126258Smlaier			if (direction == (*state)->direction) {
4695126258Smlaier				src = &(*state)->dst;
4696126258Smlaier				dst = &(*state)->src;
4697126258Smlaier			} else {
4698126258Smlaier				src = &(*state)->src;
4699126258Smlaier				dst = &(*state)->dst;
4700126258Smlaier			}
4701126258Smlaier
4702130613Smlaier			if (src->wscale && dst->wscale &&
4703130613Smlaier			    !(th.th_flags & TH_SYN))
4704126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
4705126258Smlaier			else
4706126258Smlaier				dws = 0;
4707126258Smlaier
4708126258Smlaier			/* Demodulate sequence number */
4709126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
4710128129Smlaier			if (src->seqdiff) {
4711128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
4712126258Smlaier				    htonl(seq), 0);
4713128129Smlaier				copyback = 1;
4714128129Smlaier			}
4715126258Smlaier
4716126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
4717126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
4718126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
4719126258Smlaier					printf("pf: BAD ICMP %d:%d ",
4720126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
4721126258Smlaier					pf_print_host(pd->src, 0, pd->af);
4722126258Smlaier					printf(" -> ");
4723126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
4724126258Smlaier					printf(" state: ");
4725126258Smlaier					pf_print_state(*state);
4726126258Smlaier					printf(" seq=%u\n", seq);
4727126258Smlaier				}
4728126258Smlaier				return (PF_DROP);
4729126258Smlaier			}
4730126258Smlaier
4731126258Smlaier			if (STATE_TRANSLATE(*state)) {
4732126258Smlaier				if (direction == PF_IN) {
4733126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
4734128129Smlaier					    daddr, &(*state)->lan.addr,
4735126258Smlaier					    (*state)->lan.port, NULL,
4736126258Smlaier					    pd2.ip_sum, icmpsum,
4737126258Smlaier					    pd->ip_sum, 0, pd2.af);
4738126258Smlaier				} else {
4739126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
4740126258Smlaier					    saddr, &(*state)->gwy.addr,
4741126258Smlaier					    (*state)->gwy.port, NULL,
4742126258Smlaier					    pd2.ip_sum, icmpsum,
4743126258Smlaier					    pd->ip_sum, 0, pd2.af);
4744126258Smlaier				}
4745128129Smlaier				copyback = 1;
4746128129Smlaier			}
4747128129Smlaier
4748128129Smlaier			if (copyback) {
4749126258Smlaier				switch (pd2.af) {
4750126258Smlaier#ifdef INET
4751126258Smlaier				case AF_INET:
4752126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4753126261Smlaier					    (caddr_t)pd->hdr.icmp);
4754126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
4755126261Smlaier					    (caddr_t)&h2);
4756126258Smlaier					break;
4757126258Smlaier#endif /* INET */
4758126258Smlaier#ifdef INET6
4759126258Smlaier				case AF_INET6:
4760126258Smlaier					m_copyback(m, off,
4761126258Smlaier					    sizeof(struct icmp6_hdr),
4762126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4763126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
4764126261Smlaier					    (caddr_t)&h2_6);
4765126258Smlaier					break;
4766126258Smlaier#endif /* INET6 */
4767126258Smlaier				}
4768126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
4769126258Smlaier			}
4770126258Smlaier
4771126258Smlaier			return (PF_PASS);
4772126258Smlaier			break;
4773126258Smlaier		}
4774126258Smlaier		case IPPROTO_UDP: {
4775126258Smlaier			struct udphdr		uh;
4776130613Smlaier			struct pf_state		key;
4777126258Smlaier
4778126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
4779126258Smlaier			    NULL, NULL, pd2.af)) {
4780126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4781126258Smlaier				    ("pf: ICMP error message too short "
4782126258Smlaier				    "(udp)\n"));
4783126258Smlaier				return (PF_DROP);
4784126258Smlaier			}
4785126258Smlaier
4786126258Smlaier			key.af = pd2.af;
4787126258Smlaier			key.proto = IPPROTO_UDP;
4788130613Smlaier			if (direction == PF_IN)	{
4789130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4790130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4791130613Smlaier				key.ext.port = uh.uh_dport;
4792130613Smlaier				key.gwy.port = uh.uh_sport;
4793130613Smlaier			} else {
4794130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4795130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
4796130613Smlaier				key.lan.port = uh.uh_dport;
4797130613Smlaier				key.ext.port = uh.uh_sport;
4798130613Smlaier			}
4799126258Smlaier
4800126258Smlaier			STATE_LOOKUP();
4801126258Smlaier
4802126258Smlaier			if (STATE_TRANSLATE(*state)) {
4803126258Smlaier				if (direction == PF_IN) {
4804126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
4805126258Smlaier					    daddr, &(*state)->lan.addr,
4806126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
4807126258Smlaier					    pd2.ip_sum, icmpsum,
4808126258Smlaier					    pd->ip_sum, 1, pd2.af);
4809126258Smlaier				} else {
4810126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
4811126258Smlaier					    saddr, &(*state)->gwy.addr,
4812126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
4813126258Smlaier					    pd2.ip_sum, icmpsum,
4814126258Smlaier					    pd->ip_sum, 1, pd2.af);
4815126258Smlaier				}
4816126258Smlaier				switch (pd2.af) {
4817126258Smlaier#ifdef INET
4818126258Smlaier				case AF_INET:
4819126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4820126261Smlaier					    (caddr_t)pd->hdr.icmp);
4821126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
4822126261Smlaier					    (caddr_t)&h2);
4823126258Smlaier					break;
4824126258Smlaier#endif /* INET */
4825126258Smlaier#ifdef INET6
4826126258Smlaier				case AF_INET6:
4827126258Smlaier					m_copyback(m, off,
4828126258Smlaier					    sizeof(struct icmp6_hdr),
4829126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4830126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
4831126261Smlaier					    (caddr_t)&h2_6);
4832126258Smlaier					break;
4833126258Smlaier#endif /* INET6 */
4834126258Smlaier				}
4835126261Smlaier				m_copyback(m, off2, sizeof(uh),
4836126261Smlaier				    (caddr_t)&uh);
4837126258Smlaier			}
4838126258Smlaier
4839126258Smlaier			return (PF_PASS);
4840126258Smlaier			break;
4841126258Smlaier		}
4842126258Smlaier#ifdef INET
4843126258Smlaier		case IPPROTO_ICMP: {
4844126258Smlaier			struct icmp		iih;
4845130613Smlaier			struct pf_state		key;
4846126258Smlaier
4847126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
4848126258Smlaier			    NULL, NULL, pd2.af)) {
4849126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4850126258Smlaier				    ("pf: ICMP error message too short i"
4851126258Smlaier				    "(icmp)\n"));
4852126258Smlaier				return (PF_DROP);
4853126258Smlaier			}
4854126258Smlaier
4855126258Smlaier			key.af = pd2.af;
4856126258Smlaier			key.proto = IPPROTO_ICMP;
4857130613Smlaier			if (direction == PF_IN)	{
4858130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4859130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4860130613Smlaier				key.ext.port = iih.icmp_id;
4861130613Smlaier				key.gwy.port = iih.icmp_id;
4862130613Smlaier			} else {
4863130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4864130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
4865130613Smlaier				key.lan.port = iih.icmp_id;
4866130613Smlaier				key.ext.port = iih.icmp_id;
4867130613Smlaier			}
4868126258Smlaier
4869126258Smlaier			STATE_LOOKUP();
4870126258Smlaier
4871126258Smlaier			if (STATE_TRANSLATE(*state)) {
4872126258Smlaier				if (direction == PF_IN) {
4873126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
4874126258Smlaier					    daddr, &(*state)->lan.addr,
4875126258Smlaier					    (*state)->lan.port, NULL,
4876126258Smlaier					    pd2.ip_sum, icmpsum,
4877126258Smlaier					    pd->ip_sum, 0, AF_INET);
4878126258Smlaier				} else {
4879126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
4880126258Smlaier					    saddr, &(*state)->gwy.addr,
4881126258Smlaier					    (*state)->gwy.port, NULL,
4882126258Smlaier					    pd2.ip_sum, icmpsum,
4883126258Smlaier					    pd->ip_sum, 0, AF_INET);
4884126258Smlaier				}
4885126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
4886126261Smlaier				    (caddr_t)pd->hdr.icmp);
4887126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
4888126261Smlaier				    (caddr_t)&h2);
4889126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
4890126261Smlaier				    (caddr_t)&iih);
4891126258Smlaier			}
4892126258Smlaier
4893126258Smlaier			return (PF_PASS);
4894126258Smlaier			break;
4895126258Smlaier		}
4896126258Smlaier#endif /* INET */
4897126258Smlaier#ifdef INET6
4898126258Smlaier		case IPPROTO_ICMPV6: {
4899126258Smlaier			struct icmp6_hdr	iih;
4900130613Smlaier			struct pf_state		key;
4901126258Smlaier
4902126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
4903126258Smlaier			    sizeof(struct icmp6_hdr), NULL, NULL, pd2.af)) {
4904126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4905126258Smlaier				    ("pf: ICMP error message too short "
4906126258Smlaier				    "(icmp6)\n"));
4907126258Smlaier				return (PF_DROP);
4908126258Smlaier			}
4909126258Smlaier
4910126258Smlaier			key.af = pd2.af;
4911126258Smlaier			key.proto = IPPROTO_ICMPV6;
4912130613Smlaier			if (direction == PF_IN)	{
4913130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4914130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4915130613Smlaier				key.ext.port = iih.icmp6_id;
4916130613Smlaier				key.gwy.port = iih.icmp6_id;
4917130613Smlaier			} else {
4918130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4919130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
4920130613Smlaier				key.lan.port = iih.icmp6_id;
4921130613Smlaier				key.ext.port = iih.icmp6_id;
4922130613Smlaier			}
4923126258Smlaier
4924126258Smlaier			STATE_LOOKUP();
4925126258Smlaier
4926126258Smlaier			if (STATE_TRANSLATE(*state)) {
4927126258Smlaier				if (direction == PF_IN) {
4928126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
4929126258Smlaier					    daddr, &(*state)->lan.addr,
4930126258Smlaier					    (*state)->lan.port, NULL,
4931126258Smlaier					    pd2.ip_sum, icmpsum,
4932126258Smlaier					    pd->ip_sum, 0, AF_INET6);
4933126258Smlaier				} else {
4934126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
4935126258Smlaier					    saddr, &(*state)->gwy.addr,
4936126258Smlaier					    (*state)->gwy.port, NULL,
4937126258Smlaier					    pd2.ip_sum, icmpsum,
4938126258Smlaier					    pd->ip_sum, 0, AF_INET6);
4939126258Smlaier				}
4940126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
4941126261Smlaier				    (caddr_t)pd->hdr.icmp6);
4942126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
4943126261Smlaier				    (caddr_t)&h2_6);
4944126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
4945126261Smlaier				    (caddr_t)&iih);
4946126258Smlaier			}
4947126258Smlaier
4948126258Smlaier			return (PF_PASS);
4949126258Smlaier			break;
4950126258Smlaier		}
4951126258Smlaier#endif /* INET6 */
4952126258Smlaier		default: {
4953130613Smlaier			struct pf_state		key;
4954126258Smlaier
4955126258Smlaier			key.af = pd2.af;
4956126258Smlaier			key.proto = pd2.proto;
4957130613Smlaier			if (direction == PF_IN)	{
4958130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4959130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4960130613Smlaier				key.ext.port = 0;
4961130613Smlaier				key.gwy.port = 0;
4962130613Smlaier			} else {
4963130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4964130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
4965130613Smlaier				key.lan.port = 0;
4966130613Smlaier				key.ext.port = 0;
4967130613Smlaier			}
4968126258Smlaier
4969126258Smlaier			STATE_LOOKUP();
4970126258Smlaier
4971126258Smlaier			if (STATE_TRANSLATE(*state)) {
4972126258Smlaier				if (direction == PF_IN) {
4973126258Smlaier					pf_change_icmp(pd2.src, NULL,
4974126258Smlaier					    daddr, &(*state)->lan.addr,
4975126258Smlaier					    0, NULL,
4976126258Smlaier					    pd2.ip_sum, icmpsum,
4977126258Smlaier					    pd->ip_sum, 0, pd2.af);
4978126258Smlaier				} else {
4979126258Smlaier					pf_change_icmp(pd2.dst, NULL,
4980126258Smlaier					    saddr, &(*state)->gwy.addr,
4981126258Smlaier					    0, NULL,
4982126258Smlaier					    pd2.ip_sum, icmpsum,
4983126258Smlaier					    pd->ip_sum, 0, pd2.af);
4984126258Smlaier				}
4985126258Smlaier				switch (pd2.af) {
4986126258Smlaier#ifdef INET
4987126258Smlaier				case AF_INET:
4988126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4989126261Smlaier					    (caddr_t)pd->hdr.icmp);
4990126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
4991126261Smlaier					    (caddr_t)&h2);
4992126258Smlaier					break;
4993126258Smlaier#endif /* INET */
4994126258Smlaier#ifdef INET6
4995126258Smlaier				case AF_INET6:
4996126258Smlaier					m_copyback(m, off,
4997126258Smlaier					    sizeof(struct icmp6_hdr),
4998126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4999126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5000126261Smlaier					    (caddr_t)&h2_6);
5001126258Smlaier					break;
5002126258Smlaier#endif /* INET6 */
5003126258Smlaier				}
5004126258Smlaier			}
5005126258Smlaier
5006126258Smlaier			return (PF_PASS);
5007126258Smlaier			break;
5008126258Smlaier		}
5009126258Smlaier		}
5010126258Smlaier	}
5011126258Smlaier}
5012126258Smlaier
5013126258Smlaierint
5014130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5015126258Smlaier    struct pf_pdesc *pd)
5016126258Smlaier{
5017126258Smlaier	struct pf_state_peer	*src, *dst;
5018130613Smlaier	struct pf_state		 key;
5019126258Smlaier
5020126258Smlaier	key.af = pd->af;
5021126258Smlaier	key.proto = pd->proto;
5022130613Smlaier	if (direction == PF_IN)	{
5023130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5024130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5025130613Smlaier		key.ext.port = 0;
5026130613Smlaier		key.gwy.port = 0;
5027130613Smlaier	} else {
5028130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5029130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5030130613Smlaier		key.lan.port = 0;
5031130613Smlaier		key.ext.port = 0;
5032130613Smlaier	}
5033126258Smlaier
5034126258Smlaier	STATE_LOOKUP();
5035126258Smlaier
5036126258Smlaier	if (direction == (*state)->direction) {
5037126258Smlaier		src = &(*state)->src;
5038126258Smlaier		dst = &(*state)->dst;
5039126258Smlaier	} else {
5040126258Smlaier		src = &(*state)->dst;
5041126258Smlaier		dst = &(*state)->src;
5042126258Smlaier	}
5043126258Smlaier
5044126258Smlaier	/* update states */
5045126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5046126258Smlaier		src->state = PFOTHERS_SINGLE;
5047126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5048126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5049126258Smlaier
5050126258Smlaier	/* update expire time */
5051127145Smlaier#ifdef __FreeBSD__
5052126261Smlaier	(*state)->expire = time_second;
5053126261Smlaier#else
5054126258Smlaier	(*state)->expire = time.tv_sec;
5055126261Smlaier#endif
5056126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5057126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5058126258Smlaier	else
5059126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5060126258Smlaier
5061126258Smlaier	/* translate source/destination address, if necessary */
5062126258Smlaier	if (STATE_TRANSLATE(*state)) {
5063126258Smlaier		if (direction == PF_OUT)
5064126258Smlaier			switch (pd->af) {
5065126258Smlaier#ifdef INET
5066126258Smlaier			case AF_INET:
5067126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5068126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5069126258Smlaier				    0);
5070126258Smlaier				break;
5071126258Smlaier#endif /* INET */
5072126258Smlaier#ifdef INET6
5073126258Smlaier			case AF_INET6:
5074126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5075126258Smlaier				break;
5076126258Smlaier#endif /* INET6 */
5077126258Smlaier			}
5078126258Smlaier		else
5079126258Smlaier			switch (pd->af) {
5080126258Smlaier#ifdef INET
5081126258Smlaier			case AF_INET:
5082126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5083126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5084126258Smlaier				    0);
5085126258Smlaier				break;
5086126258Smlaier#endif /* INET */
5087126258Smlaier#ifdef INET6
5088126258Smlaier			case AF_INET6:
5089126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5090126258Smlaier				break;
5091126258Smlaier#endif /* INET6 */
5092126258Smlaier			}
5093126258Smlaier	}
5094126258Smlaier
5095126258Smlaier	return (PF_PASS);
5096126258Smlaier}
5097126258Smlaier
5098126258Smlaier/*
5099126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5100126258Smlaier * h must be at "ipoff" on the mbuf chain.
5101126258Smlaier */
5102126258Smlaiervoid *
5103126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5104126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5105126258Smlaier{
5106126258Smlaier	switch (af) {
5107126258Smlaier#ifdef INET
5108126258Smlaier	case AF_INET: {
5109126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5110126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5111126258Smlaier
5112126258Smlaier		if (fragoff) {
5113126258Smlaier			if (fragoff >= len)
5114126258Smlaier				ACTION_SET(actionp, PF_PASS);
5115126258Smlaier			else {
5116126258Smlaier				ACTION_SET(actionp, PF_DROP);
5117126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5118126258Smlaier			}
5119126258Smlaier			return (NULL);
5120126258Smlaier		}
5121130613Smlaier		if (m->m_pkthdr.len < off + len ||
5122130613Smlaier		    ntohs(h->ip_len) < off + len) {
5123126258Smlaier			ACTION_SET(actionp, PF_DROP);
5124126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5125126258Smlaier			return (NULL);
5126126258Smlaier		}
5127126258Smlaier		break;
5128126258Smlaier	}
5129126258Smlaier#endif /* INET */
5130126258Smlaier#ifdef INET6
5131126258Smlaier	case AF_INET6: {
5132126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5133126258Smlaier
5134126258Smlaier		if (m->m_pkthdr.len < off + len ||
5135126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5136126258Smlaier		    (unsigned)(off + len)) {
5137126258Smlaier			ACTION_SET(actionp, PF_DROP);
5138126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5139126258Smlaier			return (NULL);
5140126258Smlaier		}
5141126258Smlaier		break;
5142126258Smlaier	}
5143126258Smlaier#endif /* INET6 */
5144126258Smlaier	}
5145126258Smlaier	m_copydata(m, off, len, p);
5146126258Smlaier	return (p);
5147126258Smlaier}
5148126258Smlaier
5149126258Smlaierint
5150126258Smlaierpf_routable(struct pf_addr *addr, sa_family_t af)
5151126258Smlaier{
5152126258Smlaier	struct sockaddr_in	*dst;
5153126258Smlaier	struct route		 ro;
5154126258Smlaier	int			 ret = 0;
5155126258Smlaier
5156126258Smlaier	bzero(&ro, sizeof(ro));
5157126258Smlaier	dst = satosin(&ro.ro_dst);
5158126258Smlaier	dst->sin_family = af;
5159126258Smlaier	dst->sin_len = sizeof(*dst);
5160126258Smlaier	dst->sin_addr = addr->v4;
5161127145Smlaier#ifdef __FreeBSD__
5162126261Smlaier#ifdef RTF_PRCLONING
5163126261Smlaier	rtalloc_ign(&ro, (RTF_CLONING|RTF_PRCLONING));
5164126261Smlaier#else /* !RTF_PRCLONING */
5165126261Smlaier	rtalloc_ign(&ro, RTF_CLONING);
5166126261Smlaier#endif
5167126261Smlaier#else /* ! __FreeBSD__ */
5168126258Smlaier	rtalloc_noclone(&ro, NO_CLONING);
5169126261Smlaier#endif
5170126258Smlaier
5171126258Smlaier	if (ro.ro_rt != NULL) {
5172126258Smlaier		ret = 1;
5173126258Smlaier		RTFREE(ro.ro_rt);
5174126258Smlaier	}
5175126258Smlaier
5176126258Smlaier	return (ret);
5177126258Smlaier}
5178126258Smlaier
5179126258Smlaier#ifdef INET
5180126261Smlaier
5181126258Smlaiervoid
5182126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5183126258Smlaier    struct pf_state *s)
5184126258Smlaier{
5185126258Smlaier	struct mbuf		*m0, *m1;
5186132303Smlaier	struct m_tag		*mtag;
5187126258Smlaier	struct route		 iproute;
5188127629Smlaier	struct route		*ro = NULL;	/* XXX: was uninitialized */
5189126258Smlaier	struct sockaddr_in	*dst;
5190126258Smlaier	struct ip		*ip;
5191126258Smlaier	struct ifnet		*ifp = NULL;
5192126258Smlaier	struct pf_addr		 naddr;
5193130613Smlaier	struct pf_src_node	*sn = NULL;
5194126258Smlaier	int			 error = 0;
5195127145Smlaier#ifdef __FreeBSD__
5196126261Smlaier	int sw_csum;
5197126261Smlaier#endif
5198126258Smlaier
5199126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5200126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5201126258Smlaier		panic("pf_route: invalid parameters");
5202126258Smlaier
5203132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5204132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5205132303Smlaier		    NULL) {
5206132303Smlaier			m0 = *m;
5207132303Smlaier			*m = NULL;
5208132303Smlaier			goto bad;
5209132303Smlaier		}
5210132303Smlaier		*(char *)(mtag + 1) = 1;
5211132303Smlaier		m_tag_prepend(*m, mtag);
5212132303Smlaier	} else {
5213132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5214132303Smlaier			m0 = *m;
5215132303Smlaier			*m = NULL;
5216132303Smlaier			goto bad;
5217132303Smlaier		}
5218132303Smlaier		(*(char *)(mtag + 1))++;
5219132303Smlaier	}
5220132303Smlaier
5221126258Smlaier	if (r->rt == PF_DUPTO) {
5222127145Smlaier#ifdef __FreeBSD__
5223132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5224126261Smlaier#else
5225132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5226126261Smlaier#endif
5227126258Smlaier			return;
5228132321Smlaier#ifdef __FreeBSD__
5229132321Smlaier		if ((mtag = m_tag_copy(mtag, M_DONTWAIT)) == NULL)
5230132321Smlaier#else
5231132303Smlaier		if ((mtag = m_tag_copy(mtag)) == NULL)
5232132321Smlaier#endif
5233132303Smlaier			goto bad;
5234132303Smlaier		m_tag_prepend(m0, mtag);
5235126258Smlaier	} else {
5236126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5237126258Smlaier			return;
5238126258Smlaier		m0 = *m;
5239126258Smlaier	}
5240126258Smlaier
5241126258Smlaier	if (m0->m_len < sizeof(struct ip))
5242126258Smlaier		panic("pf_route: m0->m_len < sizeof(struct ip)");
5243126258Smlaier	ip = mtod(m0, struct ip *);
5244126258Smlaier
5245126258Smlaier	ro = &iproute;
5246126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5247126258Smlaier	dst = satosin(&ro->ro_dst);
5248126258Smlaier	dst->sin_family = AF_INET;
5249126258Smlaier	dst->sin_len = sizeof(*dst);
5250126258Smlaier	dst->sin_addr = ip->ip_dst;
5251126258Smlaier
5252126258Smlaier	if (r->rt == PF_FASTROUTE) {
5253126258Smlaier		rtalloc(ro);
5254126258Smlaier		if (ro->ro_rt == 0) {
5255126258Smlaier			ipstat.ips_noroute++;
5256126258Smlaier			goto bad;
5257126258Smlaier		}
5258126258Smlaier
5259126258Smlaier		ifp = ro->ro_rt->rt_ifp;
5260126258Smlaier		ro->ro_rt->rt_use++;
5261126258Smlaier
5262126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
5263126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
5264126258Smlaier	} else {
5265126258Smlaier		if (TAILQ_EMPTY(&r->rpool.list))
5266126258Smlaier			panic("pf_route: TAILQ_EMPTY(&r->rpool.list)");
5267126258Smlaier		if (s == NULL) {
5268130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
5269130613Smlaier			    &naddr, NULL, &sn);
5270126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
5271126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
5272130613Smlaier			ifp = r->rpool.cur->kif ?
5273130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
5274126258Smlaier		} else {
5275126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
5276126258Smlaier				dst->sin_addr.s_addr =
5277126258Smlaier				    s->rt_addr.v4.s_addr;
5278130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5279126258Smlaier		}
5280126258Smlaier	}
5281126258Smlaier	if (ifp == NULL)
5282126258Smlaier		goto bad;
5283126258Smlaier
5284130639Smlaier	if (oifp != ifp) {
5285127145Smlaier#ifdef __FreeBSD__
5286126261Smlaier		PF_UNLOCK();
5287135920Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) {
5288126261Smlaier			PF_LOCK();
5289126261Smlaier			goto bad;
5290126261Smlaier		} else if (m0 == NULL) {
5291126261Smlaier			PF_LOCK();
5292126261Smlaier			goto done;
5293126261Smlaier		}
5294126261Smlaier		PF_LOCK();
5295126261Smlaier#else
5296126258Smlaier		if (pf_test(PF_OUT, ifp, &m0) != PF_PASS)
5297126258Smlaier			goto bad;
5298126258Smlaier		else if (m0 == NULL)
5299126258Smlaier			goto done;
5300126261Smlaier#endif
5301126258Smlaier		if (m0->m_len < sizeof(struct ip))
5302126258Smlaier			panic("pf_route: m0->m_len < sizeof(struct ip)");
5303126258Smlaier		ip = mtod(m0, struct ip *);
5304126258Smlaier	}
5305126258Smlaier
5306127145Smlaier#ifdef __FreeBSD__
5307126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
5308126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
5309126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
5310126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
5311126261Smlaier		/*
5312126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
5313126261Smlaier		 */
5314126261Smlaier		NTOHS(ip->ip_len);
5315126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
5316126261Smlaier		in_delayed_cksum(m0);
5317126261Smlaier		HTONS(ip->ip_len);
5318126261Smlaier		HTONS(ip->ip_off);
5319126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
5320126261Smlaier	}
5321126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
5322126261Smlaier
5323126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
5324126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
5325126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
5326126261Smlaier		/*
5327126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
5328126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
5329126261Smlaier		 */
5330126261Smlaier		ip->ip_sum = 0;
5331126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
5332126261Smlaier			/* From KAME */
5333126261Smlaier			if (ip->ip_v == IPVERSION &&
5334126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
5335126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
5336126261Smlaier			} else {
5337126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5338126261Smlaier			}
5339126261Smlaier		}
5340126261Smlaier		PF_UNLOCK();
5341126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
5342126261Smlaier		PF_LOCK();
5343126261Smlaier		goto done;
5344126261Smlaier	}
5345126261Smlaier
5346126261Smlaier#else
5347126258Smlaier	/* Copied from ip_output. */
5348130613Smlaier#ifdef IPSEC
5349130613Smlaier	/*
5350130613Smlaier	 * If deferred crypto processing is needed, check that the
5351130613Smlaier	 * interface supports it.
5352130613Smlaier	 */
5353130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
5354130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
5355130613Smlaier		/* Notify IPsec to do its own crypto. */
5356130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
5357130613Smlaier		goto bad;
5358130613Smlaier	}
5359130613Smlaier#endif /* IPSEC */
5360130613Smlaier
5361130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
5362130613Smlaier	if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
5363130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
5364130613Smlaier		    ifp->if_bridge != NULL) {
5365130613Smlaier			in_delayed_cksum(m0);
5366130613Smlaier			m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
5367130613Smlaier		}
5368130613Smlaier	} else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
5369130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
5370130613Smlaier		    ifp->if_bridge != NULL) {
5371130613Smlaier			in_delayed_cksum(m0);
5372130613Smlaier			m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
5373130613Smlaier		}
5374130613Smlaier	}
5375130613Smlaier
5376126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
5377126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
5378126258Smlaier		    ifp->if_bridge == NULL) {
5379126258Smlaier			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
5380126258Smlaier			ipstat.ips_outhwcsum++;
5381126258Smlaier		} else {
5382126258Smlaier			ip->ip_sum = 0;
5383126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5384126258Smlaier		}
5385126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
5386126258Smlaier		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
5387126258Smlaier			tcpstat.tcps_outhwcsum++;
5388126258Smlaier		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
5389126258Smlaier			udpstat.udps_outhwcsum++;
5390126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
5391126258Smlaier		goto done;
5392126258Smlaier	}
5393126261Smlaier#endif
5394126258Smlaier	/*
5395126258Smlaier	 * Too large for interface; fragment if possible.
5396126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
5397126258Smlaier	 */
5398126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
5399126258Smlaier		ipstat.ips_cantfrag++;
5400126258Smlaier		if (r->rt != PF_DUPTO) {
5401127145Smlaier#ifdef __FreeBSD__
5402126261Smlaier			/* icmp_error() expects host byte ordering */
5403126261Smlaier			NTOHS(ip->ip_len);
5404126261Smlaier			NTOHS(ip->ip_off);
5405126261Smlaier			PF_UNLOCK();
5406126261Smlaier#endif
5407126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5408126258Smlaier			    ifp);
5409127145Smlaier#ifdef __FreeBSD__
5410126261Smlaier			PF_LOCK();
5411126261Smlaier#endif
5412126258Smlaier			goto done;
5413126258Smlaier		} else
5414126258Smlaier			goto bad;
5415126258Smlaier	}
5416126258Smlaier
5417126258Smlaier	m1 = m0;
5418127145Smlaier#ifdef __FreeBSD__
5419126261Smlaier	/*
5420126261Smlaier	 * XXX: is cheaper + less error prone than own function
5421126261Smlaier	 */
5422126261Smlaier	NTOHS(ip->ip_len);
5423126261Smlaier	NTOHS(ip->ip_off);
5424126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
5425126261Smlaier#else
5426126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
5427126261Smlaier#endif
5428127531Smlaier	if (error) {
5429127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
5430127531Smlaier		m0 = NULL;
5431126261Smlaier#endif
5432126258Smlaier		goto bad;
5433127531Smlaier	}
5434126258Smlaier
5435126258Smlaier	for (m0 = m1; m0; m0 = m1) {
5436126258Smlaier		m1 = m0->m_nextpkt;
5437126258Smlaier		m0->m_nextpkt = 0;
5438127145Smlaier#ifdef __FreeBSD__
5439126261Smlaier		if (error == 0) {
5440126261Smlaier			PF_UNLOCK();
5441126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5442126261Smlaier			    NULL);
5443126261Smlaier			PF_LOCK();
5444126261Smlaier		} else
5445126261Smlaier#else
5446126258Smlaier		if (error == 0)
5447126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5448126258Smlaier			    NULL);
5449126258Smlaier		else
5450126261Smlaier#endif
5451126258Smlaier			m_freem(m0);
5452126258Smlaier	}
5453126258Smlaier
5454126258Smlaier	if (error == 0)
5455126258Smlaier		ipstat.ips_fragmented++;
5456126258Smlaier
5457126258Smlaierdone:
5458126258Smlaier	if (r->rt != PF_DUPTO)
5459126258Smlaier		*m = NULL;
5460126258Smlaier	if (ro == &iproute && ro->ro_rt)
5461126258Smlaier		RTFREE(ro->ro_rt);
5462126258Smlaier	return;
5463126258Smlaier
5464126258Smlaierbad:
5465126258Smlaier	m_freem(m0);
5466126258Smlaier	goto done;
5467126258Smlaier}
5468126258Smlaier#endif /* INET */
5469126258Smlaier
5470126258Smlaier#ifdef INET6
5471126258Smlaiervoid
5472126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5473126258Smlaier    struct pf_state *s)
5474126258Smlaier{
5475126258Smlaier	struct mbuf		*m0;
5476126258Smlaier	struct m_tag		*mtag;
5477126258Smlaier	struct route_in6	 ip6route;
5478126258Smlaier	struct route_in6	*ro;
5479126258Smlaier	struct sockaddr_in6	*dst;
5480126258Smlaier	struct ip6_hdr		*ip6;
5481126258Smlaier	struct ifnet		*ifp = NULL;
5482126258Smlaier	struct pf_addr		 naddr;
5483130613Smlaier	struct pf_src_node	*sn = NULL;
5484126258Smlaier	int			 error = 0;
5485126258Smlaier
5486126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5487126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5488126258Smlaier		panic("pf_route6: invalid parameters");
5489126258Smlaier
5490132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5491132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5492132303Smlaier		    NULL) {
5493132303Smlaier			m0 = *m;
5494132303Smlaier			*m = NULL;
5495132303Smlaier			goto bad;
5496132303Smlaier		}
5497132303Smlaier		*(char *)(mtag + 1) = 1;
5498132303Smlaier		m_tag_prepend(*m, mtag);
5499132303Smlaier	} else {
5500132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5501132303Smlaier			m0 = *m;
5502132303Smlaier			*m = NULL;
5503132303Smlaier			goto bad;
5504132303Smlaier		}
5505132303Smlaier		(*(char *)(mtag + 1))++;
5506132303Smlaier	}
5507132303Smlaier
5508126258Smlaier	if (r->rt == PF_DUPTO) {
5509127145Smlaier#ifdef __FreeBSD__
5510132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5511126261Smlaier#else
5512132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5513126261Smlaier#endif
5514126258Smlaier			return;
5515132321Smlaier#ifdef __FreeBSD__
5516132321Smlaier		if ((mtag = m_tag_copy(mtag, M_DONTWAIT)) == NULL)
5517132321Smlaier#else
5518132303Smlaier		if ((mtag = m_tag_copy(mtag)) == NULL)
5519132321Smlaier#endif
5520132303Smlaier			goto bad;
5521132303Smlaier		m_tag_prepend(m0, mtag);
5522126258Smlaier	} else {
5523126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5524126258Smlaier			return;
5525126258Smlaier		m0 = *m;
5526126258Smlaier	}
5527126258Smlaier
5528126258Smlaier	if (m0->m_len < sizeof(struct ip6_hdr))
5529126258Smlaier		panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
5530126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
5531126258Smlaier
5532126258Smlaier	ro = &ip6route;
5533126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5534126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
5535126258Smlaier	dst->sin6_family = AF_INET6;
5536126258Smlaier	dst->sin6_len = sizeof(*dst);
5537126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
5538126258Smlaier
5539126258Smlaier	/* Cheat. */
5540126258Smlaier	if (r->rt == PF_FASTROUTE) {
5541127145Smlaier#ifdef __FreeBSD__
5542132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
5543126261Smlaier		PF_UNLOCK();
5544126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
5545126261Smlaier		PF_LOCK();
5546126261Smlaier#else
5547132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
5548132280Smlaier		if (mtag == NULL)
5549132280Smlaier			goto bad;
5550132280Smlaier		m_tag_prepend(m0, mtag);
5551126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
5552126261Smlaier#endif
5553126258Smlaier		return;
5554126258Smlaier	}
5555126258Smlaier
5556126258Smlaier	if (TAILQ_EMPTY(&r->rpool.list))
5557126258Smlaier		panic("pf_route6: TAILQ_EMPTY(&r->rpool.list)");
5558126258Smlaier	if (s == NULL) {
5559130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
5560130613Smlaier		    &naddr, NULL, &sn);
5561126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
5562126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
5563126258Smlaier			    &naddr, AF_INET6);
5564130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
5565126258Smlaier	} else {
5566126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
5567126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
5568126258Smlaier			    &s->rt_addr, AF_INET6);
5569130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5570126258Smlaier	}
5571126258Smlaier	if (ifp == NULL)
5572126258Smlaier		goto bad;
5573126258Smlaier
5574126258Smlaier	if (oifp != ifp) {
5575127145Smlaier#ifdef __FreeBSD__
5576132303Smlaier		PF_UNLOCK();
5577135920Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) {
5578126261Smlaier			PF_LOCK();
5579132303Smlaier			goto bad;
5580132303Smlaier		} else if (m0 == NULL) {
5581132303Smlaier			PF_LOCK();
5582132303Smlaier			goto done;
5583132303Smlaier		}
5584132303Smlaier		PF_LOCK();
5585126261Smlaier#else
5586132303Smlaier		if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
5587132303Smlaier			goto bad;
5588132303Smlaier		else if (m0 == NULL)
5589132303Smlaier			goto done;
5590126261Smlaier#endif
5591132303Smlaier		if (m0->m_len < sizeof(struct ip6_hdr))
5592132303Smlaier			panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
5593132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
5594126258Smlaier	}
5595126258Smlaier
5596126258Smlaier	/*
5597126258Smlaier	 * If the packet is too large for the outgoing interface,
5598126258Smlaier	 * send back an icmp6 error.
5599126258Smlaier	 */
5600126258Smlaier	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
5601126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
5602126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
5603127145Smlaier#ifdef __FreeBSD__
5604126261Smlaier		PF_UNLOCK();
5605126261Smlaier#endif
5606126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
5607127145Smlaier#ifdef __FreeBSD__
5608126261Smlaier		PF_LOCK();
5609126261Smlaier#endif
5610126258Smlaier	} else {
5611126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
5612127145Smlaier#ifdef __FreeBSD__
5613126261Smlaier		if (r->rt != PF_DUPTO) {
5614126261Smlaier			PF_UNLOCK();
5615126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
5616126261Smlaier			PF_LOCK();
5617126261Smlaier		 } else
5618126261Smlaier#else
5619126258Smlaier		if (r->rt != PF_DUPTO)
5620126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
5621126258Smlaier		else
5622126261Smlaier#endif
5623126258Smlaier			goto bad;
5624126258Smlaier	}
5625126258Smlaier
5626126258Smlaierdone:
5627126258Smlaier	if (r->rt != PF_DUPTO)
5628126258Smlaier		*m = NULL;
5629126258Smlaier	return;
5630126258Smlaier
5631126258Smlaierbad:
5632126258Smlaier	m_freem(m0);
5633126258Smlaier	goto done;
5634126258Smlaier}
5635126258Smlaier#endif /* INET6 */
5636126258Smlaier
5637126258Smlaier
5638127145Smlaier#ifdef __FreeBSD__
5639126258Smlaier/*
5640132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
5641132566Smlaier *  em(4), fxp(4), gx(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
5642132566Smlaier *   ti(4), txp(4), xl(4)
5643132566Smlaier *
5644132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
5645132566Smlaier *  network driver performed cksum including pseudo header, need to verify
5646132566Smlaier *   csum_data
5647132566Smlaier * CSUM_DATA_VALID :
5648132566Smlaier *  network driver performed cksum, needs to additional pseudo header
5649132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
5650132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
5651132566Smlaier *
5652132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
5653132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
5654132566Smlaier * TCP/UDP layer.
5655132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
5656126261Smlaier */
5657126261Smlaierint
5658126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
5659126261Smlaier{
5660126261Smlaier	u_int16_t sum = 0;
5661126261Smlaier	int hw_assist = 0;
5662126261Smlaier	struct ip *ip;
5663126261Smlaier
5664126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
5665126261Smlaier		return (1);
5666126261Smlaier	if (m->m_pkthdr.len < off + len)
5667126261Smlaier		return (1);
5668126261Smlaier
5669126261Smlaier	switch (p) {
5670126261Smlaier	case IPPROTO_TCP:
5671126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
5672126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
5673126261Smlaier				sum = m->m_pkthdr.csum_data;
5674126261Smlaier			} else {
5675126261Smlaier				ip = mtod(m, struct ip *);
5676126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
5677135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
5678135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
5679126261Smlaier			}
5680126261Smlaier			sum ^= 0xffff;
5681126261Smlaier			++hw_assist;
5682126261Smlaier		}
5683126261Smlaier		break;
5684126261Smlaier	case IPPROTO_UDP:
5685126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
5686126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
5687126261Smlaier				sum = m->m_pkthdr.csum_data;
5688126261Smlaier			} else {
5689126261Smlaier				ip = mtod(m, struct ip *);
5690126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
5691126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
5692126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
5693126261Smlaier			}
5694126261Smlaier			sum ^= 0xffff;
5695126261Smlaier			++hw_assist;
5696126261Smlaier                }
5697126261Smlaier		break;
5698126261Smlaier	case IPPROTO_ICMP:
5699126261Smlaier#ifdef INET6
5700126261Smlaier	case IPPROTO_ICMPV6:
5701126261Smlaier#endif /* INET6 */
5702126261Smlaier		break;
5703126261Smlaier	default:
5704126261Smlaier		return (1);
5705126261Smlaier	}
5706126261Smlaier
5707126261Smlaier	if (!hw_assist) {
5708126261Smlaier		switch (af) {
5709126261Smlaier		case AF_INET:
5710126261Smlaier			if (p == IPPROTO_ICMP) {
5711126261Smlaier				if (m->m_len < off)
5712126261Smlaier					return (1);
5713126261Smlaier				m->m_data += off;
5714126261Smlaier				m->m_len -= off;
5715126261Smlaier				sum = in_cksum(m, len);
5716126261Smlaier				m->m_data -= off;
5717126261Smlaier				m->m_len += off;
5718126261Smlaier			} else {
5719126261Smlaier				if (m->m_len < sizeof(struct ip))
5720126261Smlaier					return (1);
5721126261Smlaier				sum = in4_cksum(m, p, off, len);
5722126261Smlaier			}
5723126261Smlaier			break;
5724126261Smlaier#ifdef INET6
5725126261Smlaier		case AF_INET6:
5726126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
5727126261Smlaier				return (1);
5728126261Smlaier			sum = in6_cksum(m, p, off, len);
5729126261Smlaier			break;
5730126261Smlaier#endif /* INET6 */
5731126261Smlaier		default:
5732126261Smlaier			return (1);
5733126261Smlaier		}
5734126261Smlaier	}
5735126261Smlaier	if (sum) {
5736126261Smlaier		switch (p) {
5737126261Smlaier		case IPPROTO_TCP:
5738126261Smlaier			tcpstat.tcps_rcvbadsum++;
5739126261Smlaier			break;
5740126261Smlaier		case IPPROTO_UDP:
5741126261Smlaier			udpstat.udps_badsum++;
5742126261Smlaier			break;
5743126261Smlaier		case IPPROTO_ICMP:
5744126261Smlaier			icmpstat.icps_checksum++;
5745126261Smlaier			break;
5746126261Smlaier#ifdef INET6
5747126261Smlaier		case IPPROTO_ICMPV6:
5748126261Smlaier			icmp6stat.icp6s_checksum++;
5749126261Smlaier			break;
5750126261Smlaier#endif /* INET6 */
5751126261Smlaier		}
5752126261Smlaier		return (1);
5753132566Smlaier	} else {
5754132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
5755132566Smlaier			m->m_pkthdr.csum_flags |=
5756132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
5757132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
5758132566Smlaier		}
5759126261Smlaier	}
5760126261Smlaier	return (0);
5761126261Smlaier}
5762126261Smlaier#else
5763126261Smlaier/*
5764126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
5765126258Smlaier *   off is the offset where the protocol header starts
5766126258Smlaier *   len is the total length of protocol header plus payload
5767126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
5768126258Smlaier */
5769126258Smlaierint
5770130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
5771130613Smlaier    sa_family_t af)
5772126258Smlaier{
5773126258Smlaier	u_int16_t flag_ok, flag_bad;
5774126258Smlaier	u_int16_t sum;
5775126258Smlaier
5776126258Smlaier	switch (p) {
5777126258Smlaier	case IPPROTO_TCP:
5778126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
5779126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
5780126258Smlaier		break;
5781126258Smlaier	case IPPROTO_UDP:
5782126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
5783126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
5784126258Smlaier		break;
5785126258Smlaier	case IPPROTO_ICMP:
5786126258Smlaier#ifdef INET6
5787126258Smlaier	case IPPROTO_ICMPV6:
5788126258Smlaier#endif /* INET6 */
5789126258Smlaier		flag_ok = flag_bad = 0;
5790126258Smlaier		break;
5791126258Smlaier	default:
5792126258Smlaier		return (1);
5793126258Smlaier	}
5794126258Smlaier	if (m->m_pkthdr.csum & flag_ok)
5795126258Smlaier		return (0);
5796126258Smlaier	if (m->m_pkthdr.csum & flag_bad)
5797126258Smlaier		return (1);
5798126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
5799126258Smlaier		return (1);
5800126258Smlaier	if (m->m_pkthdr.len < off + len)
5801126258Smlaier		return (1);
5802126258Smlaier		switch (af) {
5803126258Smlaier	case AF_INET:
5804126258Smlaier		if (p == IPPROTO_ICMP) {
5805126258Smlaier			if (m->m_len < off)
5806126258Smlaier				return (1);
5807126258Smlaier			m->m_data += off;
5808126258Smlaier			m->m_len -= off;
5809126258Smlaier			sum = in_cksum(m, len);
5810126258Smlaier			m->m_data -= off;
5811126258Smlaier			m->m_len += off;
5812126258Smlaier		} else {
5813126258Smlaier			if (m->m_len < sizeof(struct ip))
5814126258Smlaier				return (1);
5815126258Smlaier			sum = in4_cksum(m, p, off, len);
5816126258Smlaier		}
5817126258Smlaier		break;
5818126258Smlaier#ifdef INET6
5819126258Smlaier	case AF_INET6:
5820126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
5821126258Smlaier			return (1);
5822126258Smlaier		sum = in6_cksum(m, p, off, len);
5823126258Smlaier		break;
5824126258Smlaier#endif /* INET6 */
5825126258Smlaier	default:
5826126258Smlaier		return (1);
5827126258Smlaier	}
5828126258Smlaier	if (sum) {
5829126258Smlaier		m->m_pkthdr.csum |= flag_bad;
5830126258Smlaier		switch (p) {
5831126258Smlaier		case IPPROTO_TCP:
5832126258Smlaier			tcpstat.tcps_rcvbadsum++;
5833126258Smlaier			break;
5834126258Smlaier		case IPPROTO_UDP:
5835126258Smlaier			udpstat.udps_badsum++;
5836126258Smlaier			break;
5837126258Smlaier		case IPPROTO_ICMP:
5838126258Smlaier			icmpstat.icps_checksum++;
5839126258Smlaier			break;
5840126258Smlaier#ifdef INET6
5841126258Smlaier		case IPPROTO_ICMPV6:
5842126258Smlaier			icmp6stat.icp6s_checksum++;
5843126258Smlaier			break;
5844126258Smlaier#endif /* INET6 */
5845126258Smlaier		}
5846126258Smlaier		return (1);
5847126258Smlaier	}
5848126258Smlaier	m->m_pkthdr.csum |= flag_ok;
5849126258Smlaier	return (0);
5850126258Smlaier}
5851126261Smlaier#endif
5852126258Smlaier
5853130613Smlaierstatic int
5854130613Smlaierpf_add_mbuf_tag(struct mbuf *m, u_int tag)
5855130613Smlaier{
5856130613Smlaier	struct m_tag *mtag;
5857130613Smlaier
5858130613Smlaier	if (m_tag_find(m, tag, NULL) != NULL)
5859130613Smlaier		return (0);
5860130613Smlaier	mtag = m_tag_get(tag, 0, M_NOWAIT);
5861130613Smlaier	if (mtag == NULL)
5862130613Smlaier		return (1);
5863130613Smlaier	m_tag_prepend(m, mtag);
5864130613Smlaier	return (0);
5865130613Smlaier}
5866130613Smlaier
5867126258Smlaier#ifdef INET
5868126258Smlaierint
5869135920Smlaier#ifdef __FreeBSD__
5870135920Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
5871135920Smlaier#else
5872126258Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
5873135920Smlaier#endif
5874126258Smlaier{
5875130613Smlaier	struct pfi_kif		*kif;
5876130613Smlaier	u_short			 action, reason = 0, log = 0;
5877130613Smlaier	struct mbuf		*m = *m0;
5878130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
5879130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
5880130613Smlaier	struct pf_state		*s = NULL;
5881130613Smlaier	struct pf_ruleset	*ruleset = NULL;
5882130613Smlaier	struct pf_pdesc		 pd;
5883130613Smlaier	int			 off, dirndx, pqid = 0;
5884126258Smlaier
5885127145Smlaier#ifdef __FreeBSD__
5886126261Smlaier	PF_LOCK();
5887126261Smlaier#endif
5888126258Smlaier	if (!pf_status.running ||
5889127145Smlaier#ifdef __FreeBSD__
5890132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
5891126261Smlaier		PF_UNLOCK();
5892132280Smlaier#else
5893132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
5894126261Smlaier#endif
5895126261Smlaier	    	return (PF_PASS);
5896126261Smlaier	}
5897126258Smlaier
5898130613Smlaier	kif = pfi_index2kif[ifp->if_index];
5899130613Smlaier	if (kif == NULL) {
5900130613Smlaier#ifdef __FreeBSD__
5901130613Smlaier		PF_UNLOCK();
5902130613Smlaier#endif
5903130613Smlaier		return (PF_DROP);
5904130613Smlaier	}
5905130613Smlaier
5906130613Smlaier#ifdef __FreeBSD__
5907126261Smlaier	M_ASSERTPKTHDR(m);
5908126261Smlaier#else
5909126258Smlaier#ifdef DIAGNOSTIC
5910126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
5911126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
5912126258Smlaier#endif
5913126261Smlaier#endif
5914126258Smlaier
5915130613Smlaier	memset(&pd, 0, sizeof(pd));
5916126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
5917126258Smlaier		action = PF_DROP;
5918126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
5919126258Smlaier		log = 1;
5920126258Smlaier		goto done;
5921126258Smlaier	}
5922126258Smlaier
5923126258Smlaier	/* We do IP header normalization and packet reassembly here */
5924130613Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason) != PF_PASS) {
5925126258Smlaier		action = PF_DROP;
5926126258Smlaier		goto done;
5927126258Smlaier	}
5928126258Smlaier	m = *m0;
5929126258Smlaier	h = mtod(m, struct ip *);
5930126258Smlaier
5931126258Smlaier	off = h->ip_hl << 2;
5932126258Smlaier	if (off < (int)sizeof(*h)) {
5933126258Smlaier		action = PF_DROP;
5934126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
5935126258Smlaier		log = 1;
5936126258Smlaier		goto done;
5937126258Smlaier	}
5938126258Smlaier
5939126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
5940126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
5941130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
5942126258Smlaier	pd.ip_sum = &h->ip_sum;
5943126258Smlaier	pd.proto = h->ip_p;
5944126258Smlaier	pd.af = AF_INET;
5945126258Smlaier	pd.tos = h->ip_tos;
5946126258Smlaier	pd.tot_len = ntohs(h->ip_len);
5947126258Smlaier
5948126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
5949126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
5950130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
5951126258Smlaier		    &pd, &a, &ruleset);
5952126258Smlaier		goto done;
5953126258Smlaier	}
5954126258Smlaier
5955126258Smlaier	switch (h->ip_p) {
5956126258Smlaier
5957126258Smlaier	case IPPROTO_TCP: {
5958126258Smlaier		struct tcphdr	th;
5959126258Smlaier
5960126258Smlaier		pd.hdr.tcp = &th;
5961126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
5962126258Smlaier		    &action, &reason, AF_INET)) {
5963126258Smlaier			log = action != PF_PASS;
5964126258Smlaier			goto done;
5965126258Smlaier		}
5966126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
5967126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
5968126258Smlaier			action = PF_DROP;
5969126258Smlaier			goto done;
5970126258Smlaier		}
5971126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
5972126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
5973126258Smlaier			pqid = 1;
5974130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
5975126258Smlaier		if (action == PF_DROP)
5976130613Smlaier			goto done;
5977130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
5978126258Smlaier		    &reason);
5979126258Smlaier		if (action == PF_PASS) {
5980130613Smlaier#if NPFSYNC
5981130613Smlaier			pfsync_update_state(s);
5982130613Smlaier#endif
5983126258Smlaier			r = s->rule.ptr;
5984130613Smlaier			a = s->anchor.ptr;
5985126258Smlaier			log = s->log;
5986126258Smlaier		} else if (s == NULL)
5987135920Smlaier#ifdef __FreeBSD__
5988130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
5989135920Smlaier			    m, off, h, &pd, &a, &ruleset, inp);
5990135920Smlaier#else
5991135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
5992130613Smlaier			    m, off, h, &pd, &a, &ruleset);
5993135920Smlaier#endif
5994126258Smlaier		break;
5995126258Smlaier	}
5996126258Smlaier
5997126258Smlaier	case IPPROTO_UDP: {
5998126258Smlaier		struct udphdr	uh;
5999126258Smlaier
6000126258Smlaier		pd.hdr.udp = &uh;
6001126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6002126258Smlaier		    &action, &reason, AF_INET)) {
6003126258Smlaier			log = action != PF_PASS;
6004126258Smlaier			goto done;
6005126258Smlaier		}
6006126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6007126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6008126258Smlaier			action = PF_DROP;
6009126258Smlaier			goto done;
6010126258Smlaier		}
6011130613Smlaier		if (uh.uh_dport == 0 ||
6012130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6013130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6014130613Smlaier			action = PF_DROP;
6015130613Smlaier			goto done;
6016130613Smlaier		}
6017130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6018126258Smlaier		if (action == PF_PASS) {
6019130613Smlaier#if NPFSYNC
6020130613Smlaier			pfsync_update_state(s);
6021130613Smlaier#endif
6022126258Smlaier			r = s->rule.ptr;
6023126258Smlaier			a = s->anchor.ptr;
6024126258Smlaier			log = s->log;
6025126258Smlaier		} else if (s == NULL)
6026135920Smlaier#ifdef __FreeBSD__
6027130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6028135920Smlaier			    m, off, h, &pd, &a, &ruleset, inp);
6029135920Smlaier#else
6030135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6031130613Smlaier			    m, off, h, &pd, &a, &ruleset);
6032135920Smlaier#endif
6033126258Smlaier		break;
6034126258Smlaier	}
6035126258Smlaier
6036126258Smlaier	case IPPROTO_ICMP: {
6037126258Smlaier		struct icmp	ih;
6038126258Smlaier
6039126258Smlaier		pd.hdr.icmp = &ih;
6040126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6041126258Smlaier		    &action, &reason, AF_INET)) {
6042126258Smlaier			log = action != PF_PASS;
6043126258Smlaier			goto done;
6044126258Smlaier		}
6045126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6046126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6047126258Smlaier			action = PF_DROP;
6048126258Smlaier			goto done;
6049126258Smlaier		}
6050130613Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd);
6051126258Smlaier		if (action == PF_PASS) {
6052130613Smlaier#if NPFSYNC
6053130613Smlaier			pfsync_update_state(s);
6054130613Smlaier#endif
6055126258Smlaier			r = s->rule.ptr;
6056126258Smlaier			a = s->anchor.ptr;
6057126258Smlaier			log = s->log;
6058126258Smlaier		} else if (s == NULL)
6059130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6060130613Smlaier			    m, off, h, &pd, &a, &ruleset);
6061126258Smlaier		break;
6062126258Smlaier	}
6063126258Smlaier
6064126258Smlaier	default:
6065130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6066126258Smlaier		if (action == PF_PASS) {
6067130613Smlaier#if NPFSYNC
6068130613Smlaier			pfsync_update_state(s);
6069130613Smlaier#endif
6070126258Smlaier			r = s->rule.ptr;
6071126258Smlaier			a = s->anchor.ptr;
6072126258Smlaier			log = s->log;
6073126258Smlaier		} else if (s == NULL)
6074130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6075126258Smlaier			    &pd, &a, &ruleset);
6076126258Smlaier		break;
6077126258Smlaier	}
6078126258Smlaier
6079126258Smlaierdone:
6080126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
6081126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
6082126258Smlaier		action = PF_DROP;
6083126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6084126258Smlaier		log = 1;
6085126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
6086126258Smlaier		    ("pf: dropping packet with ip options\n"));
6087126258Smlaier	}
6088126258Smlaier
6089126258Smlaier#ifdef ALTQ
6090126258Smlaier	if (action == PF_PASS && r->qid) {
6091126258Smlaier		struct m_tag	*mtag;
6092126258Smlaier		struct altq_tag	*atag;
6093126258Smlaier
6094126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6095126258Smlaier		if (mtag != NULL) {
6096126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6097126258Smlaier			if (pqid || pd.tos == IPTOS_LOWDELAY)
6098126258Smlaier				atag->qid = r->pqid;
6099126258Smlaier			else
6100126258Smlaier				atag->qid = r->qid;
6101126258Smlaier			/* add hints for ecn */
6102126258Smlaier			atag->af = AF_INET;
6103126258Smlaier			atag->hdr = h;
6104126258Smlaier			m_tag_prepend(m, mtag);
6105126258Smlaier		}
6106126258Smlaier	}
6107126258Smlaier#endif
6108126258Smlaier
6109130613Smlaier	/*
6110130613Smlaier	 * connections redirected to loopback should not match sockets
6111130613Smlaier	 * bound specifically to loopback due to security implications,
6112130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
6113130613Smlaier	 */
6114130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6115130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6116130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6117130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6118130613Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
6119130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6120130613Smlaier		action = PF_DROP;
6121130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6122130613Smlaier	}
6123130613Smlaier
6124126258Smlaier	if (log)
6125130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
6126126258Smlaier
6127130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6128130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
6129130613Smlaier
6130130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6131130613Smlaier		r->packets++;
6132130613Smlaier		r->bytes += pd.tot_len;
6133130613Smlaier		if (a != NULL) {
6134130613Smlaier			a->packets++;
6135130613Smlaier			a->bytes += pd.tot_len;
6136130613Smlaier		}
6137130613Smlaier		if (s != NULL) {
6138130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6139130613Smlaier			s->packets[dirndx]++;
6140130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6141130613Smlaier			if (s->nat_rule.ptr != NULL) {
6142130613Smlaier				s->nat_rule.ptr->packets++;
6143130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6144130613Smlaier			}
6145130613Smlaier			if (s->src_node != NULL) {
6146130613Smlaier				s->src_node->packets++;
6147130613Smlaier				s->src_node->bytes += pd.tot_len;
6148130613Smlaier			}
6149130613Smlaier			if (s->nat_src_node != NULL) {
6150130613Smlaier				s->nat_src_node->packets++;
6151130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6152130613Smlaier			}
6153130613Smlaier		}
6154130613Smlaier		tr = r;
6155130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6156130613Smlaier		if (nr != NULL) {
6157130613Smlaier			struct pf_addr *x;
6158130613Smlaier			/*
6159130613Smlaier			 * XXX: we need to make sure that the addresses
6160130613Smlaier			 * passed to pfr_update_stats() are the same than
6161130613Smlaier			 * the addresses used during matching (pfr_match)
6162130613Smlaier			 */
6163130613Smlaier			if (r == &pf_default_rule) {
6164130613Smlaier				tr = nr;
6165130613Smlaier				x = (s == NULL || s->direction == dir) ?
6166130613Smlaier				    &pd.baddr : &pd.naddr;
6167130613Smlaier			} else
6168130613Smlaier				x = (s == NULL || s->direction == dir) ?
6169130613Smlaier				    &pd.naddr : &pd.baddr;
6170130613Smlaier			if (x == &pd.baddr || s == NULL) {
6171130613Smlaier				/* we need to change the address */
6172130613Smlaier				if (dir == PF_OUT)
6173130613Smlaier					pd.src = x;
6174130613Smlaier				else
6175130613Smlaier					pd.dst = x;
6176130613Smlaier			}
6177130613Smlaier		}
6178130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6179130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6180130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6181130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6182130613Smlaier			    tr->src.not);
6183130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6184130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6185130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6186130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6187130613Smlaier			    tr->dst.not);
6188130613Smlaier	}
6189130613Smlaier
6190130613Smlaier
6191126258Smlaier	if (action == PF_SYNPROXY_DROP) {
6192126258Smlaier		m_freem(*m0);
6193126258Smlaier		*m0 = NULL;
6194126258Smlaier		action = PF_PASS;
6195126258Smlaier	} else if (r->rt)
6196126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
6197126258Smlaier		pf_route(m0, r, dir, ifp, s);
6198126258Smlaier
6199127145Smlaier#ifdef __FreeBSD__
6200126261Smlaier	PF_UNLOCK();
6201126261Smlaier#endif
6202126261Smlaier
6203126258Smlaier	return (action);
6204126258Smlaier}
6205126258Smlaier#endif /* INET */
6206126258Smlaier
6207126258Smlaier#ifdef INET6
6208126258Smlaierint
6209135920Smlaier#ifdef __FreeBSD__
6210135920Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
6211135920Smlaier#else
6212126258Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
6213135920Smlaier#endif
6214126258Smlaier{
6215130613Smlaier	struct pfi_kif		*kif;
6216130613Smlaier	u_short			 action, reason = 0, log = 0;
6217130613Smlaier	struct mbuf		*m = *m0;
6218130613Smlaier	struct ip6_hdr		*h = NULL;	/* make the compiler happy */
6219130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6220130613Smlaier	struct pf_state		*s = NULL;
6221130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6222130613Smlaier	struct pf_pdesc		 pd;
6223130613Smlaier	int			 off, terminal = 0, dirndx;
6224126258Smlaier
6225127145Smlaier#ifdef __FreeBSD__
6226126261Smlaier	PF_LOCK();
6227126261Smlaier#endif
6228126261Smlaier
6229126258Smlaier	if (!pf_status.running ||
6230127145Smlaier#ifdef __FreeBSD__
6231132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6232126261Smlaier		PF_UNLOCK();
6233132280Smlaier#else
6234132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6235126261Smlaier#endif
6236126258Smlaier		return (PF_PASS);
6237126261Smlaier	}
6238126258Smlaier
6239130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6240130613Smlaier	if (kif == NULL) {
6241130613Smlaier#ifdef __FreeBSD__
6242130613Smlaier		PF_UNLOCK();
6243130613Smlaier#endif
6244130613Smlaier		return (PF_DROP);
6245130613Smlaier	}
6246130613Smlaier
6247130613Smlaier#ifdef __FreeBSD__
6248126261Smlaier	M_ASSERTPKTHDR(m);
6249126261Smlaier#else
6250126258Smlaier#ifdef DIAGNOSTIC
6251126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6252126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6253126258Smlaier#endif
6254126261Smlaier#endif
6255126258Smlaier
6256130613Smlaier	memset(&pd, 0, sizeof(pd));
6257126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6258126258Smlaier		action = PF_DROP;
6259126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6260126258Smlaier		log = 1;
6261126258Smlaier		goto done;
6262126258Smlaier	}
6263126258Smlaier
6264126258Smlaier	/* We do IP header normalization and packet reassembly here */
6265130613Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason) != PF_PASS) {
6266126258Smlaier		action = PF_DROP;
6267126258Smlaier		goto done;
6268126258Smlaier	}
6269126258Smlaier	m = *m0;
6270126258Smlaier	h = mtod(m, struct ip6_hdr *);
6271126258Smlaier
6272126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
6273126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
6274130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
6275126258Smlaier	pd.ip_sum = NULL;
6276126258Smlaier	pd.af = AF_INET6;
6277126258Smlaier	pd.tos = 0;
6278126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
6279126258Smlaier
6280126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
6281126258Smlaier	pd.proto = h->ip6_nxt;
6282126258Smlaier	do {
6283126258Smlaier		switch (pd.proto) {
6284126258Smlaier		case IPPROTO_FRAGMENT:
6285130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
6286126258Smlaier			    &pd, &a, &ruleset);
6287126258Smlaier			if (action == PF_DROP)
6288126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
6289126258Smlaier			goto done;
6290126258Smlaier		case IPPROTO_AH:
6291126258Smlaier		case IPPROTO_HOPOPTS:
6292126258Smlaier		case IPPROTO_ROUTING:
6293126258Smlaier		case IPPROTO_DSTOPTS: {
6294126258Smlaier			/* get next header and header length */
6295126258Smlaier			struct ip6_ext	opt6;
6296126258Smlaier
6297126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
6298126258Smlaier			    NULL, NULL, pd.af)) {
6299126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
6300126258Smlaier				    ("pf: IPv6 short opt\n"));
6301126258Smlaier				action = PF_DROP;
6302126258Smlaier				REASON_SET(&reason, PFRES_SHORT);
6303126258Smlaier				log = 1;
6304126258Smlaier				goto done;
6305126258Smlaier			}
6306126258Smlaier			if (pd.proto == IPPROTO_AH)
6307126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
6308126258Smlaier			else
6309126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
6310126258Smlaier			pd.proto = opt6.ip6e_nxt;
6311126258Smlaier			/* goto the next header */
6312126258Smlaier			break;
6313126258Smlaier		}
6314126258Smlaier		default:
6315126258Smlaier			terminal++;
6316126258Smlaier			break;
6317126258Smlaier		}
6318126258Smlaier	} while (!terminal);
6319126258Smlaier
6320126258Smlaier	switch (pd.proto) {
6321126258Smlaier
6322126258Smlaier	case IPPROTO_TCP: {
6323126258Smlaier		struct tcphdr	th;
6324126258Smlaier
6325126258Smlaier		pd.hdr.tcp = &th;
6326126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6327126258Smlaier		    &action, &reason, AF_INET6)) {
6328126258Smlaier			log = action != PF_PASS;
6329126258Smlaier			goto done;
6330126258Smlaier		}
6331126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6332126258Smlaier		    ntohs(h->ip6_plen), IPPROTO_TCP, AF_INET6)) {
6333126258Smlaier			action = PF_DROP;
6334126258Smlaier			goto done;
6335126258Smlaier		}
6336126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6337130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6338126258Smlaier		if (action == PF_DROP)
6339130613Smlaier			goto done;
6340130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6341126258Smlaier		    &reason);
6342126258Smlaier		if (action == PF_PASS) {
6343130613Smlaier#if NPFSYNC
6344130613Smlaier			pfsync_update_state(s);
6345130613Smlaier#endif
6346126258Smlaier			r = s->rule.ptr;
6347130613Smlaier			a = s->anchor.ptr;
6348126258Smlaier			log = s->log;
6349126258Smlaier		} else if (s == NULL)
6350135920Smlaier#ifdef __FreeBSD__
6351130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6352135920Smlaier			    m, off, h, &pd, &a, &ruleset, inp);
6353135920Smlaier#else
6354135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6355130613Smlaier			    m, off, h, &pd, &a, &ruleset);
6356135920Smlaier#endif
6357126258Smlaier		break;
6358126258Smlaier	}
6359126258Smlaier
6360126258Smlaier	case IPPROTO_UDP: {
6361126258Smlaier		struct udphdr	uh;
6362126258Smlaier
6363126258Smlaier		pd.hdr.udp = &uh;
6364126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6365126258Smlaier		    &action, &reason, AF_INET6)) {
6366126258Smlaier			log = action != PF_PASS;
6367126258Smlaier			goto done;
6368126258Smlaier		}
6369126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6370126258Smlaier		    off, ntohs(h->ip6_plen), IPPROTO_UDP, AF_INET6)) {
6371126258Smlaier			action = PF_DROP;
6372126258Smlaier			goto done;
6373126258Smlaier		}
6374130613Smlaier		if (uh.uh_dport == 0 ||
6375130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6376130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6377130613Smlaier			action = PF_DROP;
6378130613Smlaier			goto done;
6379130613Smlaier		}
6380130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6381126258Smlaier		if (action == PF_PASS) {
6382130613Smlaier#if NPFSYNC
6383130613Smlaier			pfsync_update_state(s);
6384130613Smlaier#endif
6385126258Smlaier			r = s->rule.ptr;
6386130613Smlaier			a = s->anchor.ptr;
6387126258Smlaier			log = s->log;
6388126258Smlaier		} else if (s == NULL)
6389135920Smlaier#ifdef __FreeBSD__
6390130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6391135920Smlaier			    m, off, h, &pd, &a, &ruleset, inp);
6392135920Smlaier#else
6393135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6394130613Smlaier			    m, off, h, &pd, &a, &ruleset);
6395135920Smlaier#endif
6396126258Smlaier		break;
6397126258Smlaier	}
6398126258Smlaier
6399126258Smlaier	case IPPROTO_ICMPV6: {
6400126258Smlaier		struct icmp6_hdr	ih;
6401126258Smlaier
6402126258Smlaier		pd.hdr.icmp6 = &ih;
6403126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
6404126258Smlaier		    &action, &reason, AF_INET6)) {
6405126258Smlaier			log = action != PF_PASS;
6406126258Smlaier			goto done;
6407126258Smlaier		}
6408126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6409126258Smlaier		    ntohs(h->ip6_plen), IPPROTO_ICMPV6, AF_INET6)) {
6410126258Smlaier			action = PF_DROP;
6411126258Smlaier			goto done;
6412126258Smlaier		}
6413130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
6414130613Smlaier		    m, off, h, &pd);
6415126258Smlaier		if (action == PF_PASS) {
6416130613Smlaier#if NPFSYNC
6417130613Smlaier			pfsync_update_state(s);
6418130613Smlaier#endif
6419126258Smlaier			r = s->rule.ptr;
6420130613Smlaier			a = s->anchor.ptr;
6421126258Smlaier			log = s->log;
6422126258Smlaier		} else if (s == NULL)
6423130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6424130613Smlaier			    m, off, h, &pd, &a, &ruleset);
6425126258Smlaier		break;
6426126258Smlaier	}
6427126258Smlaier
6428126258Smlaier	default:
6429130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6430130613Smlaier		if (action == PF_PASS) {
6431130613Smlaier			r = s->rule.ptr;
6432130613Smlaier			a = s->anchor.ptr;
6433130613Smlaier			log = s->log;
6434130613Smlaier		} else if (s == NULL)
6435130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6436130613Smlaier			    &pd, &a, &ruleset);
6437126258Smlaier		break;
6438126258Smlaier	}
6439126258Smlaier
6440126258Smlaierdone:
6441126258Smlaier	/* XXX handle IPv6 options, if not allowed. not implemented. */
6442126258Smlaier
6443126258Smlaier#ifdef ALTQ
6444126258Smlaier	if (action == PF_PASS && r->qid) {
6445126258Smlaier		struct m_tag	*mtag;
6446126258Smlaier		struct altq_tag	*atag;
6447126258Smlaier
6448126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6449126258Smlaier		if (mtag != NULL) {
6450126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6451126258Smlaier			if (pd.tos == IPTOS_LOWDELAY)
6452126258Smlaier				atag->qid = r->pqid;
6453126258Smlaier			else
6454126258Smlaier				atag->qid = r->qid;
6455126258Smlaier			/* add hints for ecn */
6456126258Smlaier			atag->af = AF_INET6;
6457126258Smlaier			atag->hdr = h;
6458126258Smlaier			m_tag_prepend(m, mtag);
6459126258Smlaier		}
6460126258Smlaier	}
6461126258Smlaier#endif
6462126258Smlaier
6463130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6464130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6465130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6466130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6467130613Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
6468130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6469130613Smlaier		action = PF_DROP;
6470130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6471130613Smlaier	}
6472130613Smlaier
6473126258Smlaier	if (log)
6474130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
6475126258Smlaier
6476130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6477130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
6478130613Smlaier
6479130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6480130613Smlaier		r->packets++;
6481130613Smlaier		r->bytes += pd.tot_len;
6482130613Smlaier		if (a != NULL) {
6483130613Smlaier			a->packets++;
6484130613Smlaier			a->bytes += pd.tot_len;
6485130613Smlaier		}
6486130613Smlaier		if (s != NULL) {
6487130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6488130613Smlaier			s->packets[dirndx]++;
6489130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6490130613Smlaier			if (s->nat_rule.ptr != NULL) {
6491130613Smlaier				s->nat_rule.ptr->packets++;
6492130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6493130613Smlaier			}
6494130613Smlaier			if (s->src_node != NULL) {
6495130613Smlaier				s->src_node->packets++;
6496130613Smlaier				s->src_node->bytes += pd.tot_len;
6497130613Smlaier			}
6498130613Smlaier			if (s->nat_src_node != NULL) {
6499130613Smlaier				s->nat_src_node->packets++;
6500130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6501130613Smlaier			}
6502130613Smlaier		}
6503130613Smlaier		tr = r;
6504130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6505130613Smlaier		if (nr != NULL) {
6506130613Smlaier			struct pf_addr *x;
6507130613Smlaier			/*
6508130613Smlaier			 * XXX: we need to make sure that the addresses
6509130613Smlaier			 * passed to pfr_update_stats() are the same than
6510130613Smlaier			 * the addresses used during matching (pfr_match)
6511130613Smlaier			 */
6512130613Smlaier			if (r == &pf_default_rule) {
6513130613Smlaier				tr = nr;
6514130613Smlaier				x = (s == NULL || s->direction == dir) ?
6515130613Smlaier				    &pd.baddr : &pd.naddr;
6516130613Smlaier			} else {
6517130613Smlaier				x = (s == NULL || s->direction == dir) ?
6518130613Smlaier				    &pd.naddr : &pd.baddr;
6519130613Smlaier			}
6520130613Smlaier			if (x == &pd.baddr || s == NULL) {
6521130613Smlaier				if (dir == PF_OUT)
6522130613Smlaier					pd.src = x;
6523130613Smlaier				else
6524130613Smlaier					pd.dst = x;
6525130613Smlaier			}
6526130613Smlaier		}
6527130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6528130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6529130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6530130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6531130613Smlaier			    tr->src.not);
6532130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6533130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6534130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6535130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6536130613Smlaier			    tr->dst.not);
6537130613Smlaier	}
6538130613Smlaier
6539130613Smlaier
6540126258Smlaier	if (action == PF_SYNPROXY_DROP) {
6541126258Smlaier		m_freem(*m0);
6542126258Smlaier		*m0 = NULL;
6543126258Smlaier		action = PF_PASS;
6544126258Smlaier	} else if (r->rt)
6545126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
6546126258Smlaier		pf_route6(m0, r, dir, ifp, s);
6547126258Smlaier
6548127145Smlaier#ifdef __FreeBSD__
6549126261Smlaier	PF_UNLOCK();
6550126261Smlaier#endif
6551126258Smlaier	return (action);
6552126258Smlaier}
6553126258Smlaier#endif /* INET6 */
6554