pf.c revision 126258
1126258Smlaier/*	$OpenBSD: pf.c,v 1.390 2003/09/24 17:18:03 mcbride Exp $ */
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
5126258Smlaier * All rights reserved.
6126258Smlaier *
7126258Smlaier * Redistribution and use in source and binary forms, with or without
8126258Smlaier * modification, are permitted provided that the following conditions
9126258Smlaier * are met:
10126258Smlaier *
11126258Smlaier *    - Redistributions of source code must retain the above copyright
12126258Smlaier *      notice, this list of conditions and the following disclaimer.
13126258Smlaier *    - Redistributions in binary form must reproduce the above
14126258Smlaier *      copyright notice, this list of conditions and the following
15126258Smlaier *      disclaimer in the documentation and/or other materials provided
16126258Smlaier *      with the distribution.
17126258Smlaier *
18126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
30126258Smlaier *
31126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
32126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
33126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
34126258Smlaier *
35126258Smlaier */
36126258Smlaier
37126258Smlaier#include "bpfilter.h"
38126258Smlaier#include "pflog.h"
39126258Smlaier#include "pfsync.h"
40126258Smlaier
41126258Smlaier#include <sys/param.h>
42126258Smlaier#include <sys/systm.h>
43126258Smlaier#include <sys/mbuf.h>
44126258Smlaier#include <sys/filio.h>
45126258Smlaier#include <sys/socket.h>
46126258Smlaier#include <sys/socketvar.h>
47126258Smlaier#include <sys/kernel.h>
48126258Smlaier#include <sys/time.h>
49126258Smlaier#include <sys/pool.h>
50126258Smlaier
51126258Smlaier#include <net/if.h>
52126258Smlaier#include <net/if_types.h>
53126258Smlaier#include <net/bpf.h>
54126258Smlaier#include <net/route.h>
55126258Smlaier
56126258Smlaier#include <netinet/in.h>
57126258Smlaier#include <netinet/in_var.h>
58126258Smlaier#include <netinet/in_systm.h>
59126258Smlaier#include <netinet/ip.h>
60126258Smlaier#include <netinet/ip_var.h>
61126258Smlaier#include <netinet/tcp.h>
62126258Smlaier#include <netinet/tcp_seq.h>
63126258Smlaier#include <netinet/udp.h>
64126258Smlaier#include <netinet/ip_icmp.h>
65126258Smlaier#include <netinet/in_pcb.h>
66126258Smlaier#include <netinet/tcp_timer.h>
67126258Smlaier#include <netinet/tcp_var.h>
68126258Smlaier#include <netinet/udp_var.h>
69126258Smlaier#include <netinet/icmp_var.h>
70126258Smlaier
71126258Smlaier#include <dev/rndvar.h>
72126258Smlaier#include <net/pfvar.h>
73126258Smlaier#include <net/if_pflog.h>
74126258Smlaier#include <net/if_pfsync.h>
75126258Smlaier
76126258Smlaier#ifdef INET6
77126258Smlaier#include <netinet/ip6.h>
78126258Smlaier#include <netinet/in_pcb.h>
79126258Smlaier#include <netinet/icmp6.h>
80126258Smlaier#include <netinet6/nd6.h>
81126258Smlaier#endif /* INET6 */
82126258Smlaier
83126258Smlaier#ifdef ALTQ
84126258Smlaier#include <altq/if_altq.h>
85126258Smlaier#endif
86126258Smlaier
87126258Smlaier
88126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
89126258Smlaierstruct pf_state_tree;
90126258Smlaier
91126258Smlaier/*
92126258Smlaier * Global variables
93126258Smlaier */
94126258Smlaier
95126258Smlaierstruct pf_anchorqueue	 pf_anchors;
96126258Smlaierstruct pf_ruleset	 pf_main_ruleset;
97126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
98126258Smlaierstruct pf_palist	 pf_pabuf;
99126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
100126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
101126258Smlaierstruct pf_status	 pf_status;
102126258Smlaierstruct ifnet		*status_ifp;
103126258Smlaier
104126258Smlaieru_int32_t		 ticket_altqs_active;
105126258Smlaieru_int32_t		 ticket_altqs_inactive;
106126258Smlaieru_int32_t		 ticket_pabuf;
107126258Smlaier
108126258Smlaierstruct timeout		 pf_expire_to;			/* expire timeout */
109126258Smlaier
110126258Smlaierstruct pool		 pf_tree_pl, pf_rule_pl, pf_addr_pl;
111126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
112126258Smlaier
113126258Smlaiervoid			 pf_dynaddr_update(void *);
114126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
115126258Smlaiervoid			 pf_print_state(struct pf_state *);
116126258Smlaiervoid			 pf_print_flags(u_int8_t);
117126258Smlaier
118126258Smlaieru_int16_t		 pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
119126258Smlaier			    u_int8_t);
120126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
121126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
122126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
123126258Smlaier#ifdef INET6
124126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
125126258Smlaier			    struct pf_addr *, u_int8_t);
126126258Smlaier#endif /* INET6 */
127126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
128126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
129126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
130126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
131126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
132126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
133126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
134126258Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t);
135126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
136126258Smlaier			    sa_family_t, struct pf_rule *);
137126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
138126258Smlaier			    int, int, struct ifnet *,
139126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
140126258Smlaier			    u_int16_t, int);
141126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
142126258Smlaier			    int, int, struct ifnet *,
143126258Smlaier			    struct pf_addr *, u_int16_t,
144126258Smlaier			    struct pf_addr *, u_int16_t,
145126258Smlaier			    struct pf_addr *, u_int16_t *);
146126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
147126258Smlaier			    int, struct ifnet *, struct mbuf *, int, int,
148126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
149126258Smlaier			    struct pf_ruleset **);
150126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
151126258Smlaier			    int, struct ifnet *, struct mbuf *, int, int,
152126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
153126258Smlaier			    struct pf_ruleset **);
154126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
155126258Smlaier			    int, struct ifnet *, struct mbuf *, int, int,
156126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
157126258Smlaier			    struct pf_ruleset **);
158126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
159126258Smlaier			    int, struct ifnet *, struct mbuf *, int, void *,
160126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
161126258Smlaier			    struct pf_ruleset **);
162126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
163126258Smlaier			    struct ifnet *, struct mbuf *, void *,
164126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
165126258Smlaier			    struct pf_ruleset **);
166126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
167126258Smlaier			    struct ifnet *, struct mbuf *, int, int,
168126258Smlaier			    void *, struct pf_pdesc *, u_short *);
169126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
170126258Smlaier			    struct ifnet *, struct mbuf *, int, int,
171126258Smlaier			    void *, struct pf_pdesc *);
172126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
173126258Smlaier			    struct ifnet *, struct mbuf *, int, int,
174126258Smlaier			    void *, struct pf_pdesc *);
175126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
176126258Smlaier			    struct ifnet *, struct pf_pdesc *);
177126258Smlaierstruct pf_tag		*pf_get_tag(struct mbuf *);
178126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
179126258Smlaier			     struct pf_rule *, struct pf_rule *,
180126258Smlaier			     struct pf_tag *, int *);
181126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
182126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
183126258Smlaierint			 pf_map_addr(u_int8_t, struct pf_pool *,
184126258Smlaier			    struct pf_addr *, struct pf_addr *,
185126258Smlaier			    struct pf_addr *);
186126258Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_pool *,
187126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
188126258Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t);
189126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
190126258Smlaier			    struct ifnet *, struct pf_state *);
191126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
192126258Smlaier			    struct ifnet *, struct pf_state *);
193126258Smlaierint			 pf_socket_lookup(uid_t *, gid_t *, int, sa_family_t,
194126258Smlaier			    int, struct pf_pdesc *);
195126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
196126258Smlaier			    sa_family_t);
197126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
198126258Smlaier			    sa_family_t);
199126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
200126258Smlaier				u_int16_t);
201126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
202126258Smlaier			    struct pf_addr *);
203126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
204126258Smlaier			    u_int8_t, sa_family_t);
205126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
206126258Smlaier			    struct pf_addr_wrap *);
207126258Smlaier
208126258Smlaier
209126258Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] =
210126258Smlaier    { { &pf_state_pl, PFSTATE_HIWAT }, { &pf_frent_pl, PFFRAG_FRENT_HIWAT } };
211126258Smlaier
212126258Smlaier#define STATE_LOOKUP()							\
213126258Smlaier	do {								\
214126258Smlaier		if (direction == PF_IN)					\
215126258Smlaier			*state = pf_find_state(&tree_ext_gwy, &key);	\
216126258Smlaier		else							\
217126258Smlaier			*state = pf_find_state(&tree_lan_ext, &key);	\
218126258Smlaier		if (*state == NULL)					\
219126258Smlaier			return (PF_DROP);				\
220126258Smlaier		if (direction == PF_OUT &&				\
221126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
222126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
223126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
224126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
225126258Smlaier		    (*state)->rt_ifp != NULL &&				\
226126258Smlaier		    (*state)->rt_ifp != ifp)				\
227126258Smlaier			return (PF_PASS);				\
228126258Smlaier	} while (0)
229126258Smlaier
230126258Smlaier#define	STATE_TRANSLATE(s) \
231126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
232126258Smlaier	((s)->af == AF_INET6 && \
233126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
234126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
235126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
236126258Smlaier	(s)->lan.port != (s)->gwy.port
237126258Smlaier
238126258Smlaierstatic __inline int pf_state_compare(struct pf_tree_node *,
239126258Smlaier			struct pf_tree_node *);
240126258Smlaier
241126258Smlaierstruct pf_state_tree tree_lan_ext, tree_ext_gwy;
242126258SmlaierRB_GENERATE(pf_state_tree, pf_tree_node, entry, pf_state_compare);
243126258Smlaier
244126258Smlaierstatic __inline int
245126258Smlaierpf_state_compare(struct pf_tree_node *a, struct pf_tree_node *b)
246126258Smlaier{
247126258Smlaier	int	diff;
248126258Smlaier
249126258Smlaier	if ((diff = a->proto - b->proto) != 0)
250126258Smlaier		return (diff);
251126258Smlaier	if ((diff = a->af - b->af) != 0)
252126258Smlaier		return (diff);
253126258Smlaier	switch (a->af) {
254126258Smlaier#ifdef INET
255126258Smlaier	case AF_INET:
256126258Smlaier		if (a->addr[0].addr32[0] > b->addr[0].addr32[0])
257126258Smlaier			return (1);
258126258Smlaier		if (a->addr[0].addr32[0] < b->addr[0].addr32[0])
259126258Smlaier			return (-1);
260126258Smlaier		if (a->addr[1].addr32[0] > b->addr[1].addr32[0])
261126258Smlaier			return (1);
262126258Smlaier		if (a->addr[1].addr32[0] < b->addr[1].addr32[0])
263126258Smlaier			return (-1);
264126258Smlaier		break;
265126258Smlaier#endif /* INET */
266126258Smlaier#ifdef INET6
267126258Smlaier	case AF_INET6:
268126258Smlaier		if (a->addr[0].addr32[3] > b->addr[0].addr32[3])
269126258Smlaier			return (1);
270126258Smlaier		if (a->addr[0].addr32[3] < b->addr[0].addr32[3])
271126258Smlaier			return (-1);
272126258Smlaier		if (a->addr[1].addr32[3] > b->addr[1].addr32[3])
273126258Smlaier			return (1);
274126258Smlaier		if (a->addr[1].addr32[3] < b->addr[1].addr32[3])
275126258Smlaier			return (-1);
276126258Smlaier		if (a->addr[0].addr32[2] > b->addr[0].addr32[2])
277126258Smlaier			return (1);
278126258Smlaier		if (a->addr[0].addr32[2] < b->addr[0].addr32[2])
279126258Smlaier			return (-1);
280126258Smlaier		if (a->addr[1].addr32[2] > b->addr[1].addr32[2])
281126258Smlaier			return (1);
282126258Smlaier		if (a->addr[1].addr32[2] < b->addr[1].addr32[2])
283126258Smlaier			return (-1);
284126258Smlaier		if (a->addr[0].addr32[1] > b->addr[0].addr32[1])
285126258Smlaier			return (1);
286126258Smlaier		if (a->addr[0].addr32[1] < b->addr[0].addr32[1])
287126258Smlaier			return (-1);
288126258Smlaier		if (a->addr[1].addr32[1] > b->addr[1].addr32[1])
289126258Smlaier			return (1);
290126258Smlaier		if (a->addr[1].addr32[1] < b->addr[1].addr32[1])
291126258Smlaier			return (-1);
292126258Smlaier		if (a->addr[0].addr32[0] > b->addr[0].addr32[0])
293126258Smlaier			return (1);
294126258Smlaier		if (a->addr[0].addr32[0] < b->addr[0].addr32[0])
295126258Smlaier			return (-1);
296126258Smlaier		if (a->addr[1].addr32[0] > b->addr[1].addr32[0])
297126258Smlaier			return (1);
298126258Smlaier		if (a->addr[1].addr32[0] < b->addr[1].addr32[0])
299126258Smlaier			return (-1);
300126258Smlaier		break;
301126258Smlaier#endif /* INET6 */
302126258Smlaier	}
303126258Smlaier
304126258Smlaier	if ((diff = a->port[0] - b->port[0]) != 0)
305126258Smlaier		return (diff);
306126258Smlaier	if ((diff = a->port[1] - b->port[1]) != 0)
307126258Smlaier		return (diff);
308126258Smlaier
309126258Smlaier	return (0);
310126258Smlaier}
311126258Smlaier
312126258Smlaier#ifdef INET6
313126258Smlaiervoid
314126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
315126258Smlaier{
316126258Smlaier	switch (af) {
317126258Smlaier#ifdef INET
318126258Smlaier	case AF_INET:
319126258Smlaier		dst->addr32[0] = src->addr32[0];
320126258Smlaier		break;
321126258Smlaier#endif /* INET */
322126258Smlaier	case AF_INET6:
323126258Smlaier		dst->addr32[0] = src->addr32[0];
324126258Smlaier		dst->addr32[1] = src->addr32[1];
325126258Smlaier		dst->addr32[2] = src->addr32[2];
326126258Smlaier		dst->addr32[3] = src->addr32[3];
327126258Smlaier		break;
328126258Smlaier	}
329126258Smlaier}
330126258Smlaier#endif
331126258Smlaier
332126258Smlaierstruct pf_state *
333126258Smlaierpf_find_state(struct pf_state_tree *tree, struct pf_tree_node *key)
334126258Smlaier{
335126258Smlaier	struct pf_tree_node	*k;
336126258Smlaier
337126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
338126258Smlaier	k = RB_FIND(pf_state_tree, tree, key);
339126258Smlaier	if (k)
340126258Smlaier		return (k->state);
341126258Smlaier	else
342126258Smlaier		return (NULL);
343126258Smlaier}
344126258Smlaier
345126258Smlaierint
346126258Smlaierpf_insert_state(struct pf_state *state)
347126258Smlaier{
348126258Smlaier	struct pf_tree_node	*keya, *keyb;
349126258Smlaier
350126258Smlaier	keya = pool_get(&pf_tree_pl, PR_NOWAIT);
351126258Smlaier	if (keya == NULL)
352126258Smlaier		return (-1);
353126258Smlaier	keya->state = state;
354126258Smlaier	keya->proto = state->proto;
355126258Smlaier	keya->af = state->af;
356126258Smlaier	PF_ACPY(&keya->addr[0], &state->lan.addr, state->af);
357126258Smlaier	keya->port[0] = state->lan.port;
358126258Smlaier	PF_ACPY(&keya->addr[1], &state->ext.addr, state->af);
359126258Smlaier	keya->port[1] = state->ext.port;
360126258Smlaier
361126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
362126258Smlaier	if (RB_INSERT(pf_state_tree, &tree_lan_ext, keya) != NULL) {
363126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
364126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
365126258Smlaier			printf(" lan: ");
366126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
367126258Smlaier			    state->af);
368126258Smlaier			printf(" gwy: ");
369126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
370126258Smlaier			    state->af);
371126258Smlaier			printf(" ext: ");
372126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
373126258Smlaier			    state->af);
374126258Smlaier			printf("\n");
375126258Smlaier		}
376126258Smlaier		pool_put(&pf_tree_pl, keya);
377126258Smlaier		return (-1);
378126258Smlaier	}
379126258Smlaier
380126258Smlaier	keyb = pool_get(&pf_tree_pl, PR_NOWAIT);
381126258Smlaier	if (keyb == NULL) {
382126258Smlaier		/* Need to pull out the other state */
383126258Smlaier		RB_REMOVE(pf_state_tree, &tree_lan_ext, keya);
384126258Smlaier		pool_put(&pf_tree_pl, keya);
385126258Smlaier		return (-1);
386126258Smlaier	}
387126258Smlaier	keyb->state = state;
388126258Smlaier	keyb->proto = state->proto;
389126258Smlaier	keyb->af = state->af;
390126258Smlaier	PF_ACPY(&keyb->addr[0], &state->ext.addr, state->af);
391126258Smlaier	keyb->port[0] = state->ext.port;
392126258Smlaier	PF_ACPY(&keyb->addr[1], &state->gwy.addr, state->af);
393126258Smlaier	keyb->port[1] = state->gwy.port;
394126258Smlaier
395126258Smlaier	if (RB_INSERT(pf_state_tree, &tree_ext_gwy, keyb) != NULL) {
396126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
397126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
398126258Smlaier			printf(" lan: ");
399126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
400126258Smlaier			    state->af);
401126258Smlaier			printf(" gwy: ");
402126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
403126258Smlaier			    state->af);
404126258Smlaier			printf(" ext: ");
405126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
406126258Smlaier			    state->af);
407126258Smlaier			printf("\n");
408126258Smlaier		}
409126258Smlaier		RB_REMOVE(pf_state_tree, &tree_lan_ext, keya);
410126258Smlaier		pool_put(&pf_tree_pl, keya);
411126258Smlaier		pool_put(&pf_tree_pl, keyb);
412126258Smlaier		return (-1);
413126258Smlaier	}
414126258Smlaier
415126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
416126258Smlaier	pf_status.states++;
417126258Smlaier#if NPFSYNC
418126258Smlaier	pfsync_insert_state(state);
419126258Smlaier#endif
420126258Smlaier	return (0);
421126258Smlaier}
422126258Smlaier
423126258Smlaiervoid
424126258Smlaierpf_purge_timeout(void *arg)
425126258Smlaier{
426126258Smlaier	struct timeout	*to = arg;
427126258Smlaier	int		 s;
428126258Smlaier
429126258Smlaier	s = splsoftnet();
430126258Smlaier	pf_purge_expired_states();
431126258Smlaier	pf_purge_expired_fragments();
432126258Smlaier	splx(s);
433126258Smlaier
434126258Smlaier	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
435126258Smlaier}
436126258Smlaier
437126258Smlaieru_int32_t
438126258Smlaierpf_state_expires(const struct pf_state *state)
439126258Smlaier{
440126258Smlaier	u_int32_t	timeout;
441126258Smlaier	u_int32_t	start;
442126258Smlaier	u_int32_t	end;
443126258Smlaier	u_int32_t	states;
444126258Smlaier
445126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
446126258Smlaier	if (state->timeout == PFTM_PURGE)
447126258Smlaier		return (time.tv_sec);
448126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
449126258Smlaier		return (0);
450126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
451126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
452126258Smlaier	if (!timeout)
453126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
454126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
455126258Smlaier	if (start) {
456126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
457126258Smlaier		states = state->rule.ptr->states;
458126258Smlaier	} else {
459126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
460126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
461126258Smlaier		states = pf_status.states;
462126258Smlaier	}
463126258Smlaier	if (end && states > start && start < end) {
464126258Smlaier		if (states < end)
465126258Smlaier			return (state->expire + timeout * (end - states) /
466126258Smlaier			    (end - start));
467126258Smlaier		else
468126258Smlaier			return (time.tv_sec);
469126258Smlaier	}
470126258Smlaier	return (state->expire + timeout);
471126258Smlaier}
472126258Smlaier
473126258Smlaiervoid
474126258Smlaierpf_purge_expired_states(void)
475126258Smlaier{
476126258Smlaier	struct pf_tree_node	*cur, *peer, *next;
477126258Smlaier	struct pf_tree_node	 key;
478126258Smlaier
479126258Smlaier	for (cur = RB_MIN(pf_state_tree, &tree_ext_gwy); cur; cur = next) {
480126258Smlaier		next = RB_NEXT(pf_state_tree, &tree_ext_gwy, cur);
481126258Smlaier
482126258Smlaier		if (pf_state_expires(cur->state) <= time.tv_sec) {
483126258Smlaier			if (cur->state->src.state == PF_TCPS_PROXY_DST)
484126258Smlaier				pf_send_tcp(cur->state->rule.ptr,
485126258Smlaier				    cur->state->af,
486126258Smlaier				    &cur->state->ext.addr,
487126258Smlaier				    &cur->state->lan.addr,
488126258Smlaier				    cur->state->ext.port,
489126258Smlaier				    cur->state->lan.port,
490126258Smlaier				    cur->state->src.seqhi,
491126258Smlaier				    cur->state->src.seqlo + 1,
492126258Smlaier					0,
493126258Smlaier				    TH_RST|TH_ACK, 0, 0);
494126258Smlaier			RB_REMOVE(pf_state_tree, &tree_ext_gwy, cur);
495126258Smlaier
496126258Smlaier			/* Need this key's peer (in the other tree) */
497126258Smlaier			key.state = cur->state;
498126258Smlaier			key.proto = cur->state->proto;
499126258Smlaier			key.af = cur->state->af;
500126258Smlaier			PF_ACPY(&key.addr[0], &cur->state->lan.addr,
501126258Smlaier			    cur->state->af);
502126258Smlaier			key.port[0] = cur->state->lan.port;
503126258Smlaier			PF_ACPY(&key.addr[1], &cur->state->ext.addr,
504126258Smlaier			    cur->state->af);
505126258Smlaier			key.port[1] = cur->state->ext.port;
506126258Smlaier
507126258Smlaier			peer = RB_FIND(pf_state_tree, &tree_lan_ext, &key);
508126258Smlaier			KASSERT(peer);
509126258Smlaier			KASSERT(peer->state == cur->state);
510126258Smlaier			RB_REMOVE(pf_state_tree, &tree_lan_ext, peer);
511126258Smlaier
512126258Smlaier#if NPFSYNC
513126258Smlaier			pfsync_delete_state(cur->state);
514126258Smlaier#endif
515126258Smlaier			if (--cur->state->rule.ptr->states <= 0)
516126258Smlaier				pf_rm_rule(NULL, cur->state->rule.ptr);
517126258Smlaier			if (cur->state->nat_rule.ptr != NULL)
518126258Smlaier				if (--cur->state->nat_rule.ptr->states <= 0)
519126258Smlaier					pf_rm_rule(NULL,
520126258Smlaier					    cur->state->nat_rule.ptr);
521126258Smlaier			if (cur->state->anchor.ptr != NULL)
522126258Smlaier				if (--cur->state->anchor.ptr->states <= 0)
523126258Smlaier					pf_rm_rule(NULL,
524126258Smlaier					    cur->state->anchor.ptr);
525126258Smlaier			pf_normalize_tcp_cleanup(cur->state);
526126258Smlaier			pool_put(&pf_state_pl, cur->state);
527126258Smlaier			pool_put(&pf_tree_pl, cur);
528126258Smlaier			pool_put(&pf_tree_pl, peer);
529126258Smlaier			pf_status.fcounters[FCNT_STATE_REMOVALS]++;
530126258Smlaier			pf_status.states--;
531126258Smlaier		}
532126258Smlaier	}
533126258Smlaier}
534126258Smlaier
535126258Smlaierint
536126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
537126258Smlaier{
538126258Smlaier	if (aw->type != PF_ADDR_TABLE)
539126258Smlaier		return (0);
540126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
541126258Smlaier		return (1);
542126258Smlaier	return (0);
543126258Smlaier}
544126258Smlaier
545126258Smlaiervoid
546126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
547126258Smlaier{
548126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
549126258Smlaier		return;
550126258Smlaier	pfr_detach_table(aw->p.tbl);
551126258Smlaier	aw->p.tbl = NULL;
552126258Smlaier}
553126258Smlaier
554126258Smlaiervoid
555126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
556126258Smlaier{
557126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
558126258Smlaier
559126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
560126258Smlaier		return;
561126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
562126258Smlaier		kt = kt->pfrkt_root;
563126258Smlaier	aw->p.tbl = NULL;
564126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
565126258Smlaier		kt->pfrkt_cnt : -1;
566126258Smlaier}
567126258Smlaier
568126258Smlaierint
569126258Smlaierpf_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
570126258Smlaier{
571126258Smlaier	if (aw->type != PF_ADDR_DYNIFTL)
572126258Smlaier		return (0);
573126258Smlaier	aw->p.dyn = pool_get(&pf_addr_pl, PR_NOWAIT);
574126258Smlaier	if (aw->p.dyn == NULL)
575126258Smlaier		return (1);
576126258Smlaier	bcopy(aw->v.ifname, aw->p.dyn->ifname, sizeof(aw->p.dyn->ifname));
577126258Smlaier	aw->p.dyn->ifp = ifunit(aw->p.dyn->ifname);
578126258Smlaier	if (aw->p.dyn->ifp == NULL) {
579126258Smlaier		pool_put(&pf_addr_pl, aw->p.dyn);
580126258Smlaier		aw->p.dyn = NULL;
581126258Smlaier		return (1);
582126258Smlaier	}
583126258Smlaier	aw->p.dyn->addr = &aw->v.a.addr;
584126258Smlaier	aw->p.dyn->af = af;
585126258Smlaier	aw->p.dyn->undefined = 1;
586126258Smlaier	aw->p.dyn->hook_cookie = hook_establish(
587126258Smlaier	    aw->p.dyn->ifp->if_addrhooks, 1,
588126258Smlaier	    pf_dynaddr_update, aw->p.dyn);
589126258Smlaier	if (aw->p.dyn->hook_cookie == NULL) {
590126258Smlaier		pool_put(&pf_addr_pl, aw->p.dyn);
591126258Smlaier		aw->p.dyn = NULL;
592126258Smlaier		return (1);
593126258Smlaier	}
594126258Smlaier	pf_dynaddr_update(aw->p.dyn);
595126258Smlaier	return (0);
596126258Smlaier}
597126258Smlaier
598126258Smlaiervoid
599126258Smlaierpf_dynaddr_update(void *p)
600126258Smlaier{
601126258Smlaier	struct pf_addr_dyn	*ad = (struct pf_addr_dyn *)p;
602126258Smlaier	struct ifaddr		*ia;
603126258Smlaier	int			 s, changed = 0;
604126258Smlaier
605126258Smlaier	if (ad == NULL || ad->ifp == NULL)
606126258Smlaier		panic("pf_dynaddr_update");
607126258Smlaier	s = splsoftnet();
608126258Smlaier	TAILQ_FOREACH(ia, &ad->ifp->if_addrlist, ifa_list)
609126258Smlaier		if (ia->ifa_addr != NULL &&
610126258Smlaier		    ia->ifa_addr->sa_family == ad->af) {
611126258Smlaier			if (ad->af == AF_INET) {
612126258Smlaier				struct in_addr *a, *b;
613126258Smlaier
614126258Smlaier				a = &ad->addr->v4;
615126258Smlaier				b = &((struct sockaddr_in *)ia->ifa_addr)
616126258Smlaier				    ->sin_addr;
617126258Smlaier				if (ad->undefined ||
618126258Smlaier				    memcmp(a, b, sizeof(*a))) {
619126258Smlaier					bcopy(b, a, sizeof(*a));
620126258Smlaier					changed = 1;
621126258Smlaier				}
622126258Smlaier			} else if (ad->af == AF_INET6) {
623126258Smlaier				struct in6_addr *a, *b;
624126258Smlaier
625126258Smlaier				a = &ad->addr->v6;
626126258Smlaier				b = &((struct sockaddr_in6 *)ia->ifa_addr)
627126258Smlaier				    ->sin6_addr;
628126258Smlaier				if (ad->undefined ||
629126258Smlaier				    memcmp(a, b, sizeof(*a))) {
630126258Smlaier					bcopy(b, a, sizeof(*a));
631126258Smlaier					changed = 1;
632126258Smlaier				}
633126258Smlaier			}
634126258Smlaier			if (changed)
635126258Smlaier				ad->undefined = 0;
636126258Smlaier			break;
637126258Smlaier		}
638126258Smlaier	if (ia == NULL)
639126258Smlaier		ad->undefined = 1;
640126258Smlaier	splx(s);
641126258Smlaier}
642126258Smlaier
643126258Smlaiervoid
644126258Smlaierpf_dynaddr_remove(struct pf_addr_wrap *aw)
645126258Smlaier{
646126258Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL)
647126258Smlaier		return;
648126258Smlaier	hook_disestablish(aw->p.dyn->ifp->if_addrhooks,
649126258Smlaier	    aw->p.dyn->hook_cookie);
650126258Smlaier	pool_put(&pf_addr_pl, aw->p.dyn);
651126258Smlaier	aw->p.dyn = NULL;
652126258Smlaier}
653126258Smlaier
654126258Smlaiervoid
655126258Smlaierpf_dynaddr_copyout(struct pf_addr_wrap *aw)
656126258Smlaier{
657126258Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL)
658126258Smlaier		return;
659126258Smlaier	bcopy(aw->p.dyn->ifname, aw->v.ifname, sizeof(aw->v.ifname));
660126258Smlaier	aw->p.dyn = (struct pf_addr_dyn *)1;
661126258Smlaier}
662126258Smlaier
663126258Smlaiervoid
664126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
665126258Smlaier{
666126258Smlaier	switch (af) {
667126258Smlaier#ifdef INET
668126258Smlaier	case AF_INET: {
669126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
670126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
671126258Smlaier		    (a>>8)&255, a&255);
672126258Smlaier		if (p) {
673126258Smlaier			p = ntohs(p);
674126258Smlaier			printf(":%u", p);
675126258Smlaier		}
676126258Smlaier		break;
677126258Smlaier	}
678126258Smlaier#endif /* INET */
679126258Smlaier#ifdef INET6
680126258Smlaier	case AF_INET6: {
681126258Smlaier		u_int16_t b;
682126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
683126258Smlaier		    maxstart = 0, maxend = 0;
684126258Smlaier		for (i = 0; i < 8; i++) {
685126258Smlaier			if (!addr->addr16[i]) {
686126258Smlaier				if (curstart == 255)
687126258Smlaier					curstart = i;
688126258Smlaier				else
689126258Smlaier					curend = i;
690126258Smlaier			} else {
691126258Smlaier				if (curstart) {
692126258Smlaier					if ((curend - curstart) >
693126258Smlaier					    (maxend - maxstart)) {
694126258Smlaier						maxstart = curstart;
695126258Smlaier						maxend = curend;
696126258Smlaier						curstart = 255;
697126258Smlaier					}
698126258Smlaier				}
699126258Smlaier			}
700126258Smlaier		}
701126258Smlaier		for (i = 0; i < 8; i++) {
702126258Smlaier			if (i >= maxstart && i <= maxend) {
703126258Smlaier				if (maxend != 7) {
704126258Smlaier					if (i == maxstart)
705126258Smlaier						printf(":");
706126258Smlaier				} else {
707126258Smlaier					if (i == maxend)
708126258Smlaier						printf(":");
709126258Smlaier				}
710126258Smlaier			} else {
711126258Smlaier				b = ntohs(addr->addr16[i]);
712126258Smlaier				printf("%x", b);
713126258Smlaier				if (i < 7)
714126258Smlaier					printf(":");
715126258Smlaier			}
716126258Smlaier		}
717126258Smlaier		if (p) {
718126258Smlaier			p = ntohs(p);
719126258Smlaier			printf("[%u]", p);
720126258Smlaier		}
721126258Smlaier		break;
722126258Smlaier	}
723126258Smlaier#endif /* INET6 */
724126258Smlaier	}
725126258Smlaier}
726126258Smlaier
727126258Smlaiervoid
728126258Smlaierpf_print_state(struct pf_state *s)
729126258Smlaier{
730126258Smlaier	switch (s->proto) {
731126258Smlaier	case IPPROTO_TCP:
732126258Smlaier		printf("TCP ");
733126258Smlaier		break;
734126258Smlaier	case IPPROTO_UDP:
735126258Smlaier		printf("UDP ");
736126258Smlaier		break;
737126258Smlaier	case IPPROTO_ICMP:
738126258Smlaier		printf("ICMP ");
739126258Smlaier		break;
740126258Smlaier	case IPPROTO_ICMPV6:
741126258Smlaier		printf("ICMPV6 ");
742126258Smlaier		break;
743126258Smlaier	default:
744126258Smlaier		printf("%u ", s->proto);
745126258Smlaier		break;
746126258Smlaier	}
747126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
748126258Smlaier	printf(" ");
749126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
750126258Smlaier	printf(" ");
751126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
752126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
753126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
754126258Smlaier	if (s->src.wscale && s->dst.wscale)
755126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
756126258Smlaier	printf("]");
757126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
758126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
759126258Smlaier	if (s->src.wscale && s->dst.wscale)
760126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
761126258Smlaier	printf("]");
762126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
763126258Smlaier}
764126258Smlaier
765126258Smlaiervoid
766126258Smlaierpf_print_flags(u_int8_t f)
767126258Smlaier{
768126258Smlaier	if (f)
769126258Smlaier		printf(" ");
770126258Smlaier	if (f & TH_FIN)
771126258Smlaier		printf("F");
772126258Smlaier	if (f & TH_SYN)
773126258Smlaier		printf("S");
774126258Smlaier	if (f & TH_RST)
775126258Smlaier		printf("R");
776126258Smlaier	if (f & TH_PUSH)
777126258Smlaier		printf("P");
778126258Smlaier	if (f & TH_ACK)
779126258Smlaier		printf("A");
780126258Smlaier	if (f & TH_URG)
781126258Smlaier		printf("U");
782126258Smlaier	if (f & TH_ECE)
783126258Smlaier		printf("E");
784126258Smlaier	if (f & TH_CWR)
785126258Smlaier		printf("W");
786126258Smlaier}
787126258Smlaier
788126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
789126258Smlaier	do {							\
790126258Smlaier		while (head[i] != cur) {			\
791126258Smlaier			head[i]->skip[i].ptr = cur;		\
792126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
793126258Smlaier		}						\
794126258Smlaier	} while (0)
795126258Smlaier
796126258Smlaiervoid
797126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
798126258Smlaier{
799126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
800126258Smlaier	int i;
801126258Smlaier
802126258Smlaier	cur = TAILQ_FIRST(rules);
803126258Smlaier	prev = cur;
804126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
805126258Smlaier		head[i] = cur;
806126258Smlaier	while (cur != NULL) {
807126258Smlaier
808126258Smlaier		if (cur->ifp != prev->ifp || cur->ifnot != prev->ifnot)
809126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
810126258Smlaier		if (cur->direction != prev->direction)
811126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
812126258Smlaier		if (cur->af != prev->af)
813126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
814126258Smlaier		if (cur->proto != prev->proto)
815126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
816126258Smlaier		if (cur->src.not != prev->src.not ||
817126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
818126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
819126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
820126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
821126258Smlaier		    cur->src.port_op != prev->src.port_op)
822126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
823126258Smlaier		if (cur->dst.not != prev->dst.not ||
824126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
825126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
826126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
827126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
828126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
829126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
830126258Smlaier
831126258Smlaier		prev = cur;
832126258Smlaier		cur = TAILQ_NEXT(cur, entries);
833126258Smlaier	}
834126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
835126258Smlaier		PF_SET_SKIP_STEPS(i);
836126258Smlaier}
837126258Smlaier
838126258Smlaierint
839126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
840126258Smlaier{
841126258Smlaier	if (aw1->type != aw2->type)
842126258Smlaier		return (1);
843126258Smlaier	switch (aw1->type) {
844126258Smlaier	case PF_ADDR_ADDRMASK:
845126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
846126258Smlaier			return (1);
847126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
848126258Smlaier			return (1);
849126258Smlaier		return (0);
850126258Smlaier	case PF_ADDR_DYNIFTL:
851126258Smlaier		if (aw1->p.dyn->ifp != aw2->p.dyn->ifp)
852126258Smlaier			return (1);
853126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
854126258Smlaier			return (1);
855126258Smlaier		return (0);
856126258Smlaier	case PF_ADDR_NOROUTE:
857126258Smlaier		return (0);
858126258Smlaier	case PF_ADDR_TABLE:
859126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
860126258Smlaier	default:
861126258Smlaier		printf("invalid address type: %d\n", aw1->type);
862126258Smlaier		return (1);
863126258Smlaier	}
864126258Smlaier}
865126258Smlaier
866126258Smlaiervoid
867126258Smlaierpf_rule_set_qid(struct pf_rulequeue *rules)
868126258Smlaier{
869126258Smlaier	struct pf_rule *rule;
870126258Smlaier
871126258Smlaier	TAILQ_FOREACH(rule, rules, entries)
872126258Smlaier		if (rule->qname[0] != 0) {
873126258Smlaier			rule->qid = pf_qname_to_qid(rule->qname);
874126258Smlaier			if (rule->pqname[0] != 0)
875126258Smlaier				rule->pqid = pf_qname_to_qid(rule->pqname);
876126258Smlaier			else
877126258Smlaier				rule->pqid = rule->qid;
878126258Smlaier		}
879126258Smlaier}
880126258Smlaier
881126258Smlaieru_int32_t
882126258Smlaierpf_qname_to_qid(char *qname)
883126258Smlaier{
884126258Smlaier	struct pf_altq		*altq;
885126258Smlaier
886126258Smlaier	TAILQ_FOREACH(altq, pf_altqs_active, entries)
887126258Smlaier		if (!strcmp(altq->qname, qname))
888126258Smlaier			return (altq->qid);
889126258Smlaier
890126258Smlaier	return (0);
891126258Smlaier}
892126258Smlaier
893126258Smlaiervoid
894126258Smlaierpf_update_anchor_rules()
895126258Smlaier{
896126258Smlaier	struct pf_rule	*rule;
897126258Smlaier	int		 i;
898126258Smlaier
899126258Smlaier	for (i = 0; i < PF_RULESET_MAX; ++i)
900126258Smlaier		TAILQ_FOREACH(rule, pf_main_ruleset.rules[i].active.ptr,
901126258Smlaier		    entries)
902126258Smlaier			if (rule->anchorname[0])
903126258Smlaier				rule->anchor = pf_find_anchor(rule->anchorname);
904126258Smlaier			else
905126258Smlaier				rule->anchor = NULL;
906126258Smlaier}
907126258Smlaier
908126258Smlaieru_int16_t
909126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
910126258Smlaier{
911126258Smlaier	u_int32_t	l;
912126258Smlaier
913126258Smlaier	if (udp && !cksum)
914126258Smlaier		return (0x0000);
915126258Smlaier	l = cksum + old - new;
916126258Smlaier	l = (l >> 16) + (l & 65535);
917126258Smlaier	l = l & 65535;
918126258Smlaier	if (udp && !l)
919126258Smlaier		return (0xFFFF);
920126258Smlaier	return (l);
921126258Smlaier}
922126258Smlaier
923126258Smlaiervoid
924126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
925126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
926126258Smlaier{
927126258Smlaier	struct pf_addr	ao;
928126258Smlaier	u_int16_t	po = *p;
929126258Smlaier
930126258Smlaier	PF_ACPY(&ao, a, af);
931126258Smlaier	PF_ACPY(a, an, af);
932126258Smlaier
933126258Smlaier	*p = pn;
934126258Smlaier
935126258Smlaier	switch (af) {
936126258Smlaier#ifdef INET
937126258Smlaier	case AF_INET:
938126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
939126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
940126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
941126258Smlaier		*p = pn;
942126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
943126258Smlaier		    ao.addr16[0], an->addr16[0], u),
944126258Smlaier		    ao.addr16[1], an->addr16[1], u),
945126258Smlaier		    po, pn, u);
946126258Smlaier		break;
947126258Smlaier#endif /* INET */
948126258Smlaier#ifdef INET6
949126258Smlaier	case AF_INET6:
950126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
951126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
952126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
953126258Smlaier		    ao.addr16[0], an->addr16[0], u),
954126258Smlaier		    ao.addr16[1], an->addr16[1], u),
955126258Smlaier		    ao.addr16[2], an->addr16[2], u),
956126258Smlaier		    ao.addr16[3], an->addr16[3], u),
957126258Smlaier		    ao.addr16[4], an->addr16[4], u),
958126258Smlaier		    ao.addr16[5], an->addr16[5], u),
959126258Smlaier		    ao.addr16[6], an->addr16[6], u),
960126258Smlaier		    ao.addr16[7], an->addr16[7], u),
961126258Smlaier		    po, pn, u);
962126258Smlaier		break;
963126258Smlaier#endif /* INET6 */
964126258Smlaier	}
965126258Smlaier}
966126258Smlaier
967126258Smlaier
968126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
969126258Smlaiervoid
970126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
971126258Smlaier{
972126258Smlaier	u_int32_t	ao;
973126258Smlaier
974126258Smlaier	memcpy(&ao, a, sizeof(ao));
975126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
976126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
977126258Smlaier	    ao % 65536, an % 65536, u);
978126258Smlaier}
979126258Smlaier
980126258Smlaier#ifdef INET6
981126258Smlaiervoid
982126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
983126258Smlaier{
984126258Smlaier	struct pf_addr	ao;
985126258Smlaier
986126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
987126258Smlaier	PF_ACPY(a, an, AF_INET6);
988126258Smlaier
989126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
990126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
991126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
992126258Smlaier	    ao.addr16[0], an->addr16[0], u),
993126258Smlaier	    ao.addr16[1], an->addr16[1], u),
994126258Smlaier	    ao.addr16[2], an->addr16[2], u),
995126258Smlaier	    ao.addr16[3], an->addr16[3], u),
996126258Smlaier	    ao.addr16[4], an->addr16[4], u),
997126258Smlaier	    ao.addr16[5], an->addr16[5], u),
998126258Smlaier	    ao.addr16[6], an->addr16[6], u),
999126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1000126258Smlaier}
1001126258Smlaier#endif /* INET6 */
1002126258Smlaier
1003126258Smlaiervoid
1004126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1005126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1006126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1007126258Smlaier{
1008126258Smlaier	struct pf_addr	oia, ooa;
1009126258Smlaier
1010126258Smlaier	PF_ACPY(&oia, ia, af);
1011126258Smlaier	PF_ACPY(&ooa, oa, af);
1012126258Smlaier
1013126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1014126258Smlaier	if (ip != NULL) {
1015126258Smlaier		u_int16_t	oip = *ip;
1016126258Smlaier		u_int32_t	opc;
1017126258Smlaier
1018126258Smlaier		if (pc != NULL)
1019126258Smlaier			opc = *pc;
1020126258Smlaier		*ip = np;
1021126258Smlaier		if (pc != NULL)
1022126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1023126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1024126258Smlaier		if (pc != NULL)
1025126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1026126258Smlaier	}
1027126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1028126258Smlaier	PF_ACPY(ia, na, af);
1029126258Smlaier	switch (af) {
1030126258Smlaier#ifdef INET
1031126258Smlaier	case AF_INET: {
1032126258Smlaier		u_int32_t	 oh2c = *h2c;
1033126258Smlaier
1034126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1035126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1036126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1037126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1038126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1039126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1040126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1041126258Smlaier		break;
1042126258Smlaier	}
1043126258Smlaier#endif /* INET */
1044126258Smlaier#ifdef INET6
1045126258Smlaier	case AF_INET6:
1046126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1047126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1048126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1049126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1050126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1051126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1052126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1053126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1054126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1055126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1056126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1057126258Smlaier		break;
1058126258Smlaier#endif /* INET6 */
1059126258Smlaier	}
1060126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1061126258Smlaier	PF_ACPY(oa, na, af);
1062126258Smlaier	switch (af) {
1063126258Smlaier#ifdef INET
1064126258Smlaier	case AF_INET:
1065126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1066126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1067126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1068126258Smlaier		break;
1069126258Smlaier#endif /* INET */
1070126258Smlaier#ifdef INET6
1071126258Smlaier	case AF_INET6:
1072126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1073126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1074126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1075126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1076126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1077126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1078126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1079126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1080126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1081126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1082126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1083126258Smlaier		break;
1084126258Smlaier#endif /* INET6 */
1085126258Smlaier	}
1086126258Smlaier}
1087126258Smlaier
1088126258Smlaiervoid
1089126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1090126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1091126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1092126258Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl)
1093126258Smlaier{
1094126258Smlaier	struct mbuf	*m;
1095126258Smlaier	struct m_tag	*mtag;
1096126258Smlaier	int		 len, tlen;
1097126258Smlaier#ifdef INET
1098126258Smlaier	struct ip	*h;
1099126258Smlaier#endif /* INET */
1100126258Smlaier#ifdef INET6
1101126258Smlaier	struct ip6_hdr	*h6;
1102126258Smlaier#endif /* INET6 */
1103126258Smlaier	struct tcphdr	*th;
1104126258Smlaier	char *opt;
1105126258Smlaier
1106126258Smlaier	/* maximum segment size tcp option */
1107126258Smlaier	tlen = sizeof(struct tcphdr);
1108126258Smlaier	if (mss)
1109126258Smlaier		tlen += 4;
1110126258Smlaier
1111126258Smlaier	switch (af) {
1112126258Smlaier#ifdef INET
1113126258Smlaier	case AF_INET:
1114126258Smlaier		len = sizeof(struct ip) + tlen;
1115126258Smlaier		break;
1116126258Smlaier#endif /* INET */
1117126258Smlaier#ifdef INET6
1118126258Smlaier	case AF_INET6:
1119126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1120126258Smlaier		break;
1121126258Smlaier#endif /* INET6 */
1122126258Smlaier	}
1123126258Smlaier
1124126258Smlaier	/* create outgoing mbuf */
1125126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1126126258Smlaier	if (mtag == NULL)
1127126258Smlaier		return;
1128126258Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1129126258Smlaier	if (m == NULL) {
1130126258Smlaier		m_tag_free(mtag);
1131126258Smlaier		return;
1132126258Smlaier	}
1133126258Smlaier	m_tag_prepend(m, mtag);
1134126258Smlaier#ifdef ALTQ
1135126258Smlaier	if (r != NULL && r->qid) {
1136126258Smlaier		struct altq_tag *atag;
1137126258Smlaier
1138126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1139126258Smlaier		if (mtag != NULL) {
1140126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1141126258Smlaier			atag->qid = r->qid;
1142126258Smlaier			/* add hints for ecn */
1143126258Smlaier			atag->af = af;
1144126258Smlaier			atag->hdr = mtod(m, struct ip *);
1145126258Smlaier			m_tag_prepend(m, mtag);
1146126258Smlaier		}
1147126258Smlaier	}
1148126258Smlaier#endif
1149126258Smlaier	m->m_data += max_linkhdr;
1150126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1151126258Smlaier	m->m_pkthdr.rcvif = NULL;
1152126258Smlaier	bzero(m->m_data, len);
1153126258Smlaier	switch (af) {
1154126258Smlaier#ifdef INET
1155126258Smlaier	case AF_INET:
1156126258Smlaier		h = mtod(m, struct ip *);
1157126258Smlaier
1158126258Smlaier		/* IP header fields included in the TCP checksum */
1159126258Smlaier		h->ip_p = IPPROTO_TCP;
1160126258Smlaier		h->ip_len = htons(tlen);
1161126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1162126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1163126258Smlaier
1164126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1165126258Smlaier		break;
1166126258Smlaier#endif /* INET */
1167126258Smlaier#ifdef INET6
1168126258Smlaier	case AF_INET6:
1169126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1170126258Smlaier
1171126258Smlaier		/* IP header fields included in the TCP checksum */
1172126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1173126258Smlaier		h6->ip6_plen = htons(tlen);
1174126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1175126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1176126258Smlaier
1177126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1178126258Smlaier		break;
1179126258Smlaier#endif /* INET6 */
1180126258Smlaier	}
1181126258Smlaier
1182126258Smlaier	/* TCP header */
1183126258Smlaier	th->th_sport = sport;
1184126258Smlaier	th->th_dport = dport;
1185126258Smlaier	th->th_seq = htonl(seq);
1186126258Smlaier	th->th_ack = htonl(ack);
1187126258Smlaier	th->th_off = tlen >> 2;
1188126258Smlaier	th->th_flags = flags;
1189126258Smlaier	th->th_win = htons(win);
1190126258Smlaier
1191126258Smlaier	if (mss) {
1192126258Smlaier		opt = (char *)(th + 1);
1193126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1194126258Smlaier		opt[1] = 4;
1195126258Smlaier		HTONS(mss);
1196126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1197126258Smlaier	}
1198126258Smlaier
1199126258Smlaier	switch (af) {
1200126258Smlaier#ifdef INET
1201126258Smlaier	case AF_INET:
1202126258Smlaier		/* TCP checksum */
1203126258Smlaier		th->th_sum = in_cksum(m, len);
1204126258Smlaier
1205126258Smlaier		/* Finish the IP header */
1206126258Smlaier		h->ip_v = 4;
1207126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1208126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1209126258Smlaier		h->ip_len = htons(len);
1210126258Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1211126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1212126258Smlaier		h->ip_sum = 0;
1213126258Smlaier		ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
1214126258Smlaier		    (void *)NULL);
1215126258Smlaier		break;
1216126258Smlaier#endif /* INET */
1217126258Smlaier#ifdef INET6
1218126258Smlaier	case AF_INET6:
1219126258Smlaier		/* TCP checksum */
1220126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1221126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1222126258Smlaier
1223126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1224126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1225126258Smlaier
1226126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1227126258Smlaier		break;
1228126258Smlaier#endif /* INET6 */
1229126258Smlaier	}
1230126258Smlaier}
1231126258Smlaier
1232126258Smlaiervoid
1233126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1234126258Smlaier    struct pf_rule *r)
1235126258Smlaier{
1236126258Smlaier	struct m_tag	*mtag;
1237126258Smlaier	struct mbuf	*m0;
1238126258Smlaier
1239126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1240126258Smlaier	if (mtag == NULL)
1241126258Smlaier		return;
1242126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
1243126258Smlaier	if (m0 == NULL) {
1244126258Smlaier		m_tag_free(mtag);
1245126258Smlaier		return;
1246126258Smlaier	}
1247126258Smlaier	m_tag_prepend(m0, mtag);
1248126258Smlaier
1249126258Smlaier#ifdef ALTQ
1250126258Smlaier	if (r->qid) {
1251126258Smlaier		struct altq_tag *atag;
1252126258Smlaier
1253126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1254126258Smlaier		if (mtag != NULL) {
1255126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1256126258Smlaier			atag->qid = r->qid;
1257126258Smlaier			/* add hints for ecn */
1258126258Smlaier			atag->af = af;
1259126258Smlaier			atag->hdr = mtod(m0, struct ip *);
1260126258Smlaier			m_tag_prepend(m0, mtag);
1261126258Smlaier		}
1262126258Smlaier	}
1263126258Smlaier#endif
1264126258Smlaier
1265126258Smlaier	switch (af) {
1266126258Smlaier#ifdef INET
1267126258Smlaier	case AF_INET:
1268126258Smlaier		icmp_error(m0, type, code, 0, 0);
1269126258Smlaier		break;
1270126258Smlaier#endif /* INET */
1271126258Smlaier#ifdef INET6
1272126258Smlaier	case AF_INET6:
1273126258Smlaier		icmp6_error(m0, type, code, 0);
1274126258Smlaier		break;
1275126258Smlaier#endif /* INET6 */
1276126258Smlaier	}
1277126258Smlaier}
1278126258Smlaier
1279126258Smlaier/*
1280126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
1281126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
1282126258Smlaier * are different.
1283126258Smlaier */
1284126258Smlaierint
1285126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
1286126258Smlaier    struct pf_addr *b, sa_family_t af)
1287126258Smlaier{
1288126258Smlaier	int	match = 0;
1289126258Smlaier
1290126258Smlaier	switch (af) {
1291126258Smlaier#ifdef INET
1292126258Smlaier	case AF_INET:
1293126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
1294126258Smlaier		    (b->addr32[0] & m->addr32[0]))
1295126258Smlaier			match++;
1296126258Smlaier		break;
1297126258Smlaier#endif /* INET */
1298126258Smlaier#ifdef INET6
1299126258Smlaier	case AF_INET6:
1300126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
1301126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
1302126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
1303126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
1304126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
1305126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
1306126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
1307126258Smlaier		     (b->addr32[3] & m->addr32[3])))
1308126258Smlaier			match++;
1309126258Smlaier		break;
1310126258Smlaier#endif /* INET6 */
1311126258Smlaier	}
1312126258Smlaier	if (match) {
1313126258Smlaier		if (n)
1314126258Smlaier			return (0);
1315126258Smlaier		else
1316126258Smlaier			return (1);
1317126258Smlaier	} else {
1318126258Smlaier		if (n)
1319126258Smlaier			return (1);
1320126258Smlaier		else
1321126258Smlaier			return (0);
1322126258Smlaier	}
1323126258Smlaier}
1324126258Smlaier
1325126258Smlaierint
1326126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
1327126258Smlaier{
1328126258Smlaier	switch (op) {
1329126258Smlaier	case PF_OP_IRG:
1330126258Smlaier		return ((p > a1) && (p < a2));
1331126258Smlaier	case PF_OP_XRG:
1332126258Smlaier		return ((p < a1) || (p > a2));
1333126258Smlaier	case PF_OP_RRG:
1334126258Smlaier		return ((p >= a1) && (p <= a2));
1335126258Smlaier	case PF_OP_EQ:
1336126258Smlaier		return (p == a1);
1337126258Smlaier	case PF_OP_NE:
1338126258Smlaier		return (p != a1);
1339126258Smlaier	case PF_OP_LT:
1340126258Smlaier		return (p < a1);
1341126258Smlaier	case PF_OP_LE:
1342126258Smlaier		return (p <= a1);
1343126258Smlaier	case PF_OP_GT:
1344126258Smlaier		return (p > a1);
1345126258Smlaier	case PF_OP_GE:
1346126258Smlaier		return (p >= a1);
1347126258Smlaier	}
1348126258Smlaier	return (0); /* never reached */
1349126258Smlaier}
1350126258Smlaier
1351126258Smlaierint
1352126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
1353126258Smlaier{
1354126258Smlaier	NTOHS(a1);
1355126258Smlaier	NTOHS(a2);
1356126258Smlaier	NTOHS(p);
1357126258Smlaier	return (pf_match(op, a1, a2, p));
1358126258Smlaier}
1359126258Smlaier
1360126258Smlaierint
1361126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
1362126258Smlaier{
1363126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1364126258Smlaier		return (0);
1365126258Smlaier	return (pf_match(op, a1, a2, u));
1366126258Smlaier}
1367126258Smlaier
1368126258Smlaierint
1369126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
1370126258Smlaier{
1371126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1372126258Smlaier		return (0);
1373126258Smlaier	return (pf_match(op, a1, a2, g));
1374126258Smlaier}
1375126258Smlaier
1376126258Smlaierstruct pf_tag *
1377126258Smlaierpf_get_tag(struct mbuf *m)
1378126258Smlaier{
1379126258Smlaier	struct m_tag	*mtag;
1380126258Smlaier
1381126258Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
1382126258Smlaier		return ((struct pf_tag *)(mtag + 1));
1383126258Smlaier	else
1384126258Smlaier		return (NULL);
1385126258Smlaier}
1386126258Smlaier
1387126258Smlaierint
1388126258Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_rule *nat,
1389126258Smlaier    struct pf_rule *rdr, struct pf_tag *pftag, int *tag)
1390126258Smlaier{
1391126258Smlaier	if (*tag == -1) {	/* find mbuf tag */
1392126258Smlaier		pftag = pf_get_tag(m);
1393126258Smlaier		if (pftag != NULL)
1394126258Smlaier			*tag = pftag->tag;
1395126258Smlaier		else
1396126258Smlaier			*tag = 0;
1397126258Smlaier		if (nat != NULL && nat->tag)
1398126258Smlaier			*tag = nat->tag;
1399126258Smlaier		if (rdr != NULL && rdr->tag)
1400126258Smlaier			*tag = rdr->tag;
1401126258Smlaier	}
1402126258Smlaier
1403126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
1404126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
1405126258Smlaier}
1406126258Smlaier
1407126258Smlaierint
1408126258Smlaierpf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
1409126258Smlaier{
1410126258Smlaier	struct m_tag	*mtag;
1411126258Smlaier
1412126258Smlaier	if (tag <= 0)
1413126258Smlaier		return (0);
1414126258Smlaier
1415126258Smlaier	if (pftag == NULL) {
1416126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
1417126258Smlaier		if (mtag == NULL)
1418126258Smlaier			return (1);
1419126258Smlaier		((struct pf_tag *)(mtag + 1))->tag = tag;
1420126258Smlaier		m_tag_prepend(m, mtag);
1421126258Smlaier	} else
1422126258Smlaier		pftag->tag = tag;
1423126258Smlaier
1424126258Smlaier	return (0);
1425126258Smlaier}
1426126258Smlaier
1427126258Smlaier#define PF_STEP_INTO_ANCHOR(r, a, s, n)					\
1428126258Smlaier	do {								\
1429126258Smlaier		if ((r) == NULL || (r)->anchor == NULL ||		\
1430126258Smlaier		    (s) != NULL || (a) != NULL)				\
1431126258Smlaier			panic("PF_STEP_INTO_ANCHOR");			\
1432126258Smlaier		(a) = (r);						\
1433126258Smlaier		(s) = TAILQ_FIRST(&(r)->anchor->rulesets);		\
1434126258Smlaier		(r) = NULL;						\
1435126258Smlaier		while ((s) != NULL && ((r) =				\
1436126258Smlaier		    TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL)	\
1437126258Smlaier			(s) = TAILQ_NEXT((s), entries);			\
1438126258Smlaier		if ((r) == NULL) {					\
1439126258Smlaier			(r) = TAILQ_NEXT((a), entries);			\
1440126258Smlaier			(a) = NULL;					\
1441126258Smlaier		}							\
1442126258Smlaier	} while (0)
1443126258Smlaier
1444126258Smlaier#define PF_STEP_OUT_OF_ANCHOR(r, a, s, n)				\
1445126258Smlaier	do {								\
1446126258Smlaier		if ((r) != NULL || (a) == NULL || (s) == NULL)		\
1447126258Smlaier			panic("PF_STEP_OUT_OF_ANCHOR");			\
1448126258Smlaier		(s) = TAILQ_NEXT((s), entries);				\
1449126258Smlaier		while ((s) != NULL && ((r) =				\
1450126258Smlaier		    TAILQ_FIRST((s)->rules[n].active.ptr)) == NULL)	\
1451126258Smlaier			(s) = TAILQ_NEXT((s), entries);			\
1452126258Smlaier		if ((r) == NULL) {					\
1453126258Smlaier			(r) = TAILQ_NEXT((a), entries);			\
1454126258Smlaier			(a) = NULL;					\
1455126258Smlaier		}							\
1456126258Smlaier	} while (0)
1457126258Smlaier
1458126258Smlaier#ifdef INET6
1459126258Smlaiervoid
1460126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
1461126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
1462126258Smlaier{
1463126258Smlaier	switch (af) {
1464126258Smlaier#ifdef INET
1465126258Smlaier	case AF_INET:
1466126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
1467126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
1468126258Smlaier		break;
1469126258Smlaier#endif /* INET */
1470126258Smlaier	case AF_INET6:
1471126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
1472126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
1473126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
1474126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
1475126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
1476126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
1477126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
1478126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
1479126258Smlaier		break;
1480126258Smlaier	}
1481126258Smlaier}
1482126258Smlaier
1483126258Smlaiervoid
1484126258Smlaierpf_addr_inc(struct pf_addr *addr, u_int8_t af)
1485126258Smlaier{
1486126258Smlaier	switch (af) {
1487126258Smlaier#ifdef INET
1488126258Smlaier	case AF_INET:
1489126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
1490126258Smlaier		break;
1491126258Smlaier#endif /* INET */
1492126258Smlaier	case AF_INET6:
1493126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
1494126258Smlaier			addr->addr32[3] = 0;
1495126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
1496126258Smlaier				addr->addr32[2] = 0;
1497126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
1498126258Smlaier					addr->addr32[1] = 0;
1499126258Smlaier					addr->addr32[0] =
1500126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
1501126258Smlaier				} else
1502126258Smlaier					addr->addr32[1] =
1503126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
1504126258Smlaier			} else
1505126258Smlaier				addr->addr32[2] =
1506126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
1507126258Smlaier		} else
1508126258Smlaier			addr->addr32[3] =
1509126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
1510126258Smlaier		break;
1511126258Smlaier	}
1512126258Smlaier}
1513126258Smlaier#endif /* INET6 */
1514126258Smlaier
1515126258Smlaier#define mix(a,b,c) \
1516126258Smlaier	do {					\
1517126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
1518126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
1519126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
1520126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
1521126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
1522126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
1523126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
1524126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
1525126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
1526126258Smlaier	} while (0)
1527126258Smlaier
1528126258Smlaier/*
1529126258Smlaier * hash function based on bridge_hash in if_bridge.c
1530126258Smlaier */
1531126258Smlaiervoid
1532126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
1533126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
1534126258Smlaier{
1535126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
1536126258Smlaier
1537126258Smlaier	switch (af) {
1538126258Smlaier#ifdef INET
1539126258Smlaier	case AF_INET:
1540126258Smlaier		a += inaddr->addr32[0];
1541126258Smlaier		b += key->key32[1];
1542126258Smlaier		mix(a, b, c);
1543126258Smlaier		hash->addr32[0] = c + key->key32[2];
1544126258Smlaier		break;
1545126258Smlaier#endif /* INET */
1546126258Smlaier#ifdef INET6
1547126258Smlaier	case AF_INET6:
1548126258Smlaier		a += inaddr->addr32[0];
1549126258Smlaier		b += inaddr->addr32[2];
1550126258Smlaier		mix(a, b, c);
1551126258Smlaier		hash->addr32[0] = c;
1552126258Smlaier		a += inaddr->addr32[1];
1553126258Smlaier		b += inaddr->addr32[3];
1554126258Smlaier		c += key->key32[1];
1555126258Smlaier		mix(a, b, c);
1556126258Smlaier		hash->addr32[1] = c;
1557126258Smlaier		a += inaddr->addr32[2];
1558126258Smlaier		b += inaddr->addr32[1];
1559126258Smlaier		c += key->key32[2];
1560126258Smlaier		mix(a, b, c);
1561126258Smlaier		hash->addr32[2] = c;
1562126258Smlaier		a += inaddr->addr32[3];
1563126258Smlaier		b += inaddr->addr32[0];
1564126258Smlaier		c += key->key32[3];
1565126258Smlaier		mix(a, b, c);
1566126258Smlaier		hash->addr32[3] = c;
1567126258Smlaier		break;
1568126258Smlaier#endif /* INET6 */
1569126258Smlaier	}
1570126258Smlaier}
1571126258Smlaier
1572126258Smlaierint
1573126258Smlaierpf_map_addr(u_int8_t af, struct pf_pool *rpool, struct pf_addr *saddr,
1574126258Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr)
1575126258Smlaier{
1576126258Smlaier	unsigned char		 hash[16];
1577126258Smlaier	struct pf_addr		*raddr;
1578126258Smlaier	struct pf_addr		*rmask;
1579126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
1580126258Smlaier
1581126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
1582126258Smlaier		return (1);
1583126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL &&
1584126258Smlaier	    rpool->cur->addr.p.dyn->undefined)
1585126258Smlaier		return (1);
1586126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_TABLE) {
1587126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
1588126258Smlaier			return (1); /* unsupported */
1589126258Smlaier	} else {
1590126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
1591126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
1592126258Smlaier	}
1593126258Smlaier
1594126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
1595126258Smlaier	case PF_POOL_NONE:
1596126258Smlaier		PF_ACPY(naddr, raddr, af);
1597126258Smlaier		break;
1598126258Smlaier	case PF_POOL_BITMASK:
1599126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
1600126258Smlaier		break;
1601126258Smlaier	case PF_POOL_RANDOM:
1602126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
1603126258Smlaier			switch (af) {
1604126258Smlaier#ifdef INET
1605126258Smlaier			case AF_INET:
1606126258Smlaier				rpool->counter.addr32[0] = arc4random();
1607126258Smlaier				break;
1608126258Smlaier#endif /* INET */
1609126258Smlaier#ifdef INET6
1610126258Smlaier			case AF_INET6:
1611126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
1612126258Smlaier					rpool->counter.addr32[3] = arc4random();
1613126258Smlaier				else
1614126258Smlaier					break;
1615126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
1616126258Smlaier					rpool->counter.addr32[2] = arc4random();
1617126258Smlaier				else
1618126258Smlaier					break;
1619126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
1620126258Smlaier					rpool->counter.addr32[1] = arc4random();
1621126258Smlaier				else
1622126258Smlaier					break;
1623126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
1624126258Smlaier					rpool->counter.addr32[0] = arc4random();
1625126258Smlaier				break;
1626126258Smlaier#endif /* INET6 */
1627126258Smlaier			}
1628126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
1629126258Smlaier			PF_ACPY(init_addr, naddr, af);
1630126258Smlaier
1631126258Smlaier		} else {
1632126258Smlaier			PF_AINC(&rpool->counter, af);
1633126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
1634126258Smlaier		}
1635126258Smlaier		break;
1636126258Smlaier	case PF_POOL_SRCHASH:
1637126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
1638126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
1639126258Smlaier		break;
1640126258Smlaier	case PF_POOL_ROUNDROBIN:
1641126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
1642126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
1643126258Smlaier			    &rpool->tblidx, &rpool->counter,
1644126258Smlaier			    &raddr, &rmask, af))
1645126258Smlaier				goto get_addr;
1646126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
1647126258Smlaier			goto get_addr;
1648126258Smlaier
1649126258Smlaier	try_next:
1650126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
1651126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
1652126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
1653126258Smlaier			rpool->tblidx = -1;
1654126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
1655126258Smlaier			    &rpool->tblidx, &rpool->counter,
1656126258Smlaier			    &raddr, &rmask, af)) {
1657126258Smlaier				/* table contain no address of type 'af' */
1658126258Smlaier				if (rpool->cur != acur)
1659126258Smlaier					goto try_next;
1660126258Smlaier				return (1);
1661126258Smlaier			}
1662126258Smlaier		} else {
1663126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
1664126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
1665126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
1666126258Smlaier		}
1667126258Smlaier
1668126258Smlaier	get_addr:
1669126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
1670126258Smlaier		PF_AINC(&rpool->counter, af);
1671126258Smlaier		break;
1672126258Smlaier	}
1673126258Smlaier
1674126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
1675126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
1676126258Smlaier		printf("pf_map_addr: selected address: ");
1677126258Smlaier		pf_print_host(naddr, 0, af);
1678126258Smlaier		printf("\n");
1679126258Smlaier	}
1680126258Smlaier
1681126258Smlaier	return (0);
1682126258Smlaier}
1683126258Smlaier
1684126258Smlaierint
1685126258Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_pool *rpool,
1686126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
1687126258Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high)
1688126258Smlaier{
1689126258Smlaier	struct pf_tree_node	key;
1690126258Smlaier	struct pf_addr		init_addr;
1691126258Smlaier	u_int16_t		cut;
1692126258Smlaier
1693126258Smlaier	bzero(&init_addr, sizeof(init_addr));
1694126258Smlaier	if (pf_map_addr(af, rpool, saddr, naddr, &init_addr))
1695126258Smlaier		return (1);
1696126258Smlaier
1697126258Smlaier	do {
1698126258Smlaier		key.af = af;
1699126258Smlaier		key.proto = proto;
1700126258Smlaier		PF_ACPY(&key.addr[0], daddr, key.af);
1701126258Smlaier		PF_ACPY(&key.addr[1], naddr, key.af);
1702126258Smlaier		key.port[0] = dport;
1703126258Smlaier
1704126258Smlaier		/*
1705126258Smlaier		 * port search; start random, step;
1706126258Smlaier		 * similar 2 portloop in in_pcbbind
1707126258Smlaier		 */
1708126258Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
1709126258Smlaier			key.port[1] = 0;
1710126258Smlaier			if (pf_find_state(&tree_ext_gwy, &key) == NULL)
1711126258Smlaier				return (0);
1712126258Smlaier		} else if (low == 0 && high == 0) {
1713126258Smlaier			key.port[1] = *nport;
1714126258Smlaier			if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
1715126258Smlaier				return (0);
1716126258Smlaier			}
1717126258Smlaier		} else if (low == high) {
1718126258Smlaier			key.port[1] = htons(low);
1719126258Smlaier			if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
1720126258Smlaier				*nport = htons(low);
1721126258Smlaier				return (0);
1722126258Smlaier			}
1723126258Smlaier		} else {
1724126258Smlaier			u_int16_t tmp;
1725126258Smlaier
1726126258Smlaier			if (low > high) {
1727126258Smlaier				tmp = low;
1728126258Smlaier				low = high;
1729126258Smlaier				high = tmp;
1730126258Smlaier			}
1731126258Smlaier			/* low < high */
1732126258Smlaier			cut = arc4random() % (1 + high - low) + low;
1733126258Smlaier			/* low <= cut <= high */
1734126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
1735126258Smlaier				key.port[1] = htons(tmp);
1736126258Smlaier				if (pf_find_state(&tree_ext_gwy, &key) ==
1737126258Smlaier				    NULL) {
1738126258Smlaier					*nport = htons(tmp);
1739126258Smlaier					return (0);
1740126258Smlaier				}
1741126258Smlaier			}
1742126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
1743126258Smlaier				key.port[1] = htons(tmp);
1744126258Smlaier				if (pf_find_state(&tree_ext_gwy, &key) ==
1745126258Smlaier				    NULL) {
1746126258Smlaier					*nport = htons(tmp);
1747126258Smlaier					return (0);
1748126258Smlaier				}
1749126258Smlaier			}
1750126258Smlaier		}
1751126258Smlaier
1752126258Smlaier		switch (rpool->opts & PF_POOL_TYPEMASK) {
1753126258Smlaier		case PF_POOL_RANDOM:
1754126258Smlaier		case PF_POOL_ROUNDROBIN:
1755126258Smlaier			if (pf_map_addr(af, rpool, saddr, naddr, &init_addr))
1756126258Smlaier				return (1);
1757126258Smlaier			break;
1758126258Smlaier		case PF_POOL_NONE:
1759126258Smlaier		case PF_POOL_SRCHASH:
1760126258Smlaier		case PF_POOL_BITMASK:
1761126258Smlaier		default:
1762126258Smlaier			return (1);
1763126258Smlaier			break;
1764126258Smlaier		}
1765126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
1766126258Smlaier
1767126258Smlaier	return (1);					/* none available */
1768126258Smlaier}
1769126258Smlaier
1770126258Smlaierstruct pf_rule *
1771126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
1772126258Smlaier    int direction, struct ifnet *ifp, struct pf_addr *saddr, u_int16_t sport,
1773126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
1774126258Smlaier{
1775126258Smlaier	struct pf_rule		*r, *rm = NULL, *anchorrule = NULL;
1776126258Smlaier	struct pf_ruleset	*ruleset = NULL;
1777126258Smlaier
1778126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
1779126258Smlaier	while (r && rm == NULL) {
1780126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
1781126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
1782126258Smlaier
1783126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
1784126258Smlaier			src = &r->dst;
1785126258Smlaier			if (r->rpool.cur != NULL)
1786126258Smlaier				xdst = &r->rpool.cur->addr;
1787126258Smlaier		} else {
1788126258Smlaier			src = &r->src;
1789126258Smlaier			dst = &r->dst;
1790126258Smlaier		}
1791126258Smlaier
1792126258Smlaier		r->evaluations++;
1793126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
1794126258Smlaier		    (r->ifp == ifp && r->ifnot)))
1795126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
1796126258Smlaier		else if (r->direction && r->direction != direction)
1797126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
1798126258Smlaier		else if (r->af && r->af != pd->af)
1799126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
1800126258Smlaier		else if (r->proto && r->proto != pd->proto)
1801126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
1802126258Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->not))
1803126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
1804126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
1805126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
1806126258Smlaier		    src->port[0], src->port[1], sport))
1807126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
1808126258Smlaier			    PF_SKIP_DST_PORT].ptr;
1809126258Smlaier		else if (dst != NULL &&
1810126258Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->not))
1811126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
1812126258Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
1813126258Smlaier			r = TAILQ_NEXT(r, entries);
1814126258Smlaier		else if (dst != NULL && dst->port_op &&
1815126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
1816126258Smlaier		    dst->port[1], dport))
1817126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
1818126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
1819126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
1820126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
1821126258Smlaier			r = TAILQ_NEXT(r, entries);
1822126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
1823126258Smlaier			r = TAILQ_NEXT(r, entries);
1824126258Smlaier		else if (r->anchor == NULL)
1825126258Smlaier				rm = r;
1826126258Smlaier		else
1827126258Smlaier			PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, rs_num);
1828126258Smlaier		if (r == NULL && anchorrule != NULL)
1829126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset,
1830126258Smlaier			    rs_num);
1831126258Smlaier	}
1832126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
1833126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
1834126258Smlaier		return (NULL);
1835126258Smlaier	return (rm);
1836126258Smlaier}
1837126258Smlaier
1838126258Smlaierstruct pf_rule *
1839126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
1840126258Smlaier    struct ifnet *ifp,
1841126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
1842126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
1843126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
1844126258Smlaier{
1845126258Smlaier	struct pf_rule	*r = NULL;
1846126258Smlaier
1847126258Smlaier	if (direction == PF_OUT) {
1848126258Smlaier		r = pf_match_translation(pd, m, off, direction, ifp, saddr,
1849126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
1850126258Smlaier		if (r == NULL)
1851126258Smlaier			r = pf_match_translation(pd, m, off, direction, ifp,
1852126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
1853126258Smlaier	} else {
1854126258Smlaier		r = pf_match_translation(pd, m, off, direction, ifp, saddr,
1855126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
1856126258Smlaier		if (r == NULL)
1857126258Smlaier			r = pf_match_translation(pd, m, off, direction, ifp,
1858126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
1859126258Smlaier	}
1860126258Smlaier
1861126258Smlaier	if (r != NULL) {
1862126258Smlaier		switch (r->action) {
1863126258Smlaier		case PF_NONAT:
1864126258Smlaier		case PF_NOBINAT:
1865126258Smlaier		case PF_NORDR:
1866126258Smlaier			return (NULL);
1867126258Smlaier			break;
1868126258Smlaier		case PF_NAT:
1869126258Smlaier			if (pf_get_sport(pd->af, pd->proto, &r->rpool, saddr,
1870126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
1871126258Smlaier			    r->rpool.proxy_port[1])) {
1872126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
1873126258Smlaier				    ("pf: NAT proxy port allocation "
1874126258Smlaier				    "(%u-%u) failed\n",
1875126258Smlaier				    r->rpool.proxy_port[0],
1876126258Smlaier				    r->rpool.proxy_port[1]));
1877126258Smlaier				return (NULL);
1878126258Smlaier			}
1879126258Smlaier			break;
1880126258Smlaier		case PF_BINAT:
1881126258Smlaier			switch (direction) {
1882126258Smlaier			case PF_OUT:
1883126258Smlaier				if (r->rpool.cur->addr.type ==
1884126258Smlaier				    PF_ADDR_DYNIFTL &&
1885126258Smlaier				    r->rpool.cur->addr.p.dyn->undefined)
1886126258Smlaier					return (NULL);
1887126258Smlaier				else
1888126258Smlaier					PF_POOLMASK(naddr,
1889126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
1890126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
1891126258Smlaier					    saddr, pd->af);
1892126258Smlaier				break;
1893126258Smlaier			case PF_IN:
1894126258Smlaier				if (r->src.addr.type == PF_ADDR_DYNIFTL &&
1895126258Smlaier				    r->src.addr.p.dyn->undefined)
1896126258Smlaier					return (NULL);
1897126258Smlaier				else
1898126258Smlaier					PF_POOLMASK(naddr,
1899126258Smlaier					    &r->src.addr.v.a.addr,
1900126258Smlaier					    &r->src.addr.v.a.mask, saddr,
1901126258Smlaier					    pd->af);
1902126258Smlaier				break;
1903126258Smlaier			}
1904126258Smlaier			break;
1905126258Smlaier		case PF_RDR: {
1906126258Smlaier			if (pf_map_addr(r->af, &r->rpool, saddr, naddr, NULL))
1907126258Smlaier				return (NULL);
1908126258Smlaier
1909126258Smlaier			if (r->rpool.proxy_port[1]) {
1910126258Smlaier				u_int32_t	tmp_nport;
1911126258Smlaier
1912126258Smlaier				tmp_nport = ((ntohs(dport) -
1913126258Smlaier				    ntohs(r->dst.port[0])) %
1914126258Smlaier				    (r->rpool.proxy_port[1] -
1915126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
1916126258Smlaier				    r->rpool.proxy_port[0];
1917126258Smlaier
1918126258Smlaier				/* wrap around if necessary */
1919126258Smlaier				if (tmp_nport > 65535)
1920126258Smlaier					tmp_nport -= 65535;
1921126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
1922126258Smlaier			} else if (r->rpool.proxy_port[0])
1923126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
1924126258Smlaier			break;
1925126258Smlaier		}
1926126258Smlaier		default:
1927126258Smlaier			return (NULL);
1928126258Smlaier			break;
1929126258Smlaier		}
1930126258Smlaier	}
1931126258Smlaier
1932126258Smlaier	return (r);
1933126258Smlaier}
1934126258Smlaier
1935126258Smlaierint
1936126258Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
1937126258Smlaier    int proto, struct pf_pdesc *pd)
1938126258Smlaier{
1939126258Smlaier	struct pf_addr		*saddr, *daddr;
1940126258Smlaier	u_int16_t		 sport, dport;
1941126258Smlaier	struct inpcbtable	*tb;
1942126258Smlaier	struct inpcb		*inp;
1943126258Smlaier
1944126258Smlaier	*uid = UID_MAX;
1945126258Smlaier	*gid = GID_MAX;
1946126258Smlaier	switch (proto) {
1947126258Smlaier	case IPPROTO_TCP:
1948126258Smlaier		sport = pd->hdr.tcp->th_sport;
1949126258Smlaier		dport = pd->hdr.tcp->th_dport;
1950126258Smlaier		tb = &tcbtable;
1951126258Smlaier		break;
1952126258Smlaier	case IPPROTO_UDP:
1953126258Smlaier		sport = pd->hdr.udp->uh_sport;
1954126258Smlaier		dport = pd->hdr.udp->uh_dport;
1955126258Smlaier		tb = &udbtable;
1956126258Smlaier		break;
1957126258Smlaier	default:
1958126258Smlaier		return (0);
1959126258Smlaier	}
1960126258Smlaier	if (direction == PF_IN) {
1961126258Smlaier		saddr = pd->src;
1962126258Smlaier		daddr = pd->dst;
1963126258Smlaier	} else {
1964126258Smlaier		u_int16_t	p;
1965126258Smlaier
1966126258Smlaier		p = sport;
1967126258Smlaier		sport = dport;
1968126258Smlaier		dport = p;
1969126258Smlaier		saddr = pd->dst;
1970126258Smlaier		daddr = pd->src;
1971126258Smlaier	}
1972126258Smlaier	switch(af) {
1973126258Smlaier	case AF_INET:
1974126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
1975126258Smlaier		if (inp == NULL) {
1976126258Smlaier			inp = in_pcblookup(tb, &saddr->v4, sport, &daddr->v4,
1977126258Smlaier			    dport, INPLOOKUP_WILDCARD);
1978126258Smlaier			if (inp == NULL)
1979126258Smlaier				return (0);
1980126258Smlaier		}
1981126258Smlaier		break;
1982126258Smlaier#ifdef INET6
1983126258Smlaier	case AF_INET6:
1984126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
1985126258Smlaier		    dport);
1986126258Smlaier		if (inp == NULL) {
1987126258Smlaier			inp = in_pcblookup(tb, &saddr->v6, sport, &daddr->v6,
1988126258Smlaier			    dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
1989126258Smlaier			if (inp == NULL)
1990126258Smlaier				return (0);
1991126258Smlaier		}
1992126258Smlaier		break;
1993126258Smlaier#endif /* INET6 */
1994126258Smlaier
1995126258Smlaier	default:
1996126258Smlaier		return (0);
1997126258Smlaier	}
1998126258Smlaier	*uid = inp->inp_socket->so_euid;
1999126258Smlaier	*gid = inp->inp_socket->so_egid;
2000126258Smlaier	return (1);
2001126258Smlaier}
2002126258Smlaier
2003126258Smlaieru_int8_t
2004126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2005126258Smlaier{
2006126258Smlaier	int		 hlen;
2007126258Smlaier	u_int8_t	 hdr[60];
2008126258Smlaier	u_int8_t	*opt, optlen;
2009126258Smlaier	u_int8_t	 wscale = 0;
2010126258Smlaier
2011126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
2012126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2013126258Smlaier		return (0);
2014126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2015126258Smlaier		return (0);
2016126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2017126258Smlaier	hlen -= sizeof(struct tcphdr);
2018126258Smlaier	while (hlen >= 3) {
2019126258Smlaier		switch (*opt) {
2020126258Smlaier		case TCPOPT_EOL:
2021126258Smlaier		case TCPOPT_NOP:
2022126258Smlaier			++opt;
2023126258Smlaier			--hlen;
2024126258Smlaier			break;
2025126258Smlaier		case TCPOPT_WINDOW:
2026126258Smlaier			wscale = opt[2];
2027126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
2028126258Smlaier				wscale = TCP_MAX_WINSHIFT;
2029126258Smlaier			wscale |= PF_WSCALE_FLAG;
2030126258Smlaier			/* fallthrough */
2031126258Smlaier		default:
2032126258Smlaier			optlen = opt[1];
2033126258Smlaier			if (optlen < 2)
2034126258Smlaier				optlen = 2;
2035126258Smlaier			hlen -= optlen;
2036126258Smlaier			opt += optlen;
2037126258Smlaier		}
2038126258Smlaier	}
2039126258Smlaier	return (wscale);
2040126258Smlaier}
2041126258Smlaier
2042126258Smlaieru_int16_t
2043126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2044126258Smlaier{
2045126258Smlaier	int		 hlen;
2046126258Smlaier	u_int8_t	 hdr[60];
2047126258Smlaier	u_int8_t	*opt, optlen;
2048126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
2049126258Smlaier
2050126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
2051126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2052126258Smlaier		return (0);
2053126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2054126258Smlaier		return (0);
2055126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2056126258Smlaier	hlen -= sizeof(struct tcphdr);
2057126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
2058126258Smlaier		switch (*opt) {
2059126258Smlaier		case TCPOPT_EOL:
2060126258Smlaier		case TCPOPT_NOP:
2061126258Smlaier			++opt;
2062126258Smlaier			--hlen;
2063126258Smlaier			break;
2064126258Smlaier		case TCPOPT_MAXSEG:
2065126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
2066126258Smlaier			/* fallthrough */
2067126258Smlaier		default:
2068126258Smlaier			optlen = opt[1];
2069126258Smlaier			if (optlen < 2)
2070126258Smlaier				optlen = 2;
2071126258Smlaier			hlen -= optlen;
2072126258Smlaier			opt += optlen;
2073126258Smlaier		}
2074126258Smlaier	}
2075126258Smlaier	return (mss);
2076126258Smlaier}
2077126258Smlaier
2078126258Smlaieru_int16_t
2079126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
2080126258Smlaier{
2081126258Smlaier#ifdef INET
2082126258Smlaier	struct sockaddr_in	*dst;
2083126258Smlaier	struct route		 ro;
2084126258Smlaier#endif /* INET */
2085126258Smlaier#ifdef INET6
2086126258Smlaier	struct sockaddr_in6	*dst6;
2087126258Smlaier	struct route_in6	 ro6;
2088126258Smlaier#endif /* INET6 */
2089126258Smlaier	struct rtentry		*rt = NULL;
2090126258Smlaier	int			 hlen;
2091126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2092126258Smlaier
2093126258Smlaier	switch (af) {
2094126258Smlaier#ifdef INET
2095126258Smlaier	case AF_INET:
2096126258Smlaier		hlen = sizeof(struct ip);
2097126258Smlaier		bzero(&ro, sizeof(ro));
2098126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
2099126258Smlaier		dst->sin_family = AF_INET;
2100126258Smlaier		dst->sin_len = sizeof(*dst);
2101126258Smlaier		dst->sin_addr = addr->v4;
2102126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
2103126258Smlaier		rt = ro.ro_rt;
2104126258Smlaier		break;
2105126258Smlaier#endif /* INET */
2106126258Smlaier#ifdef INET6
2107126258Smlaier	case AF_INET6:
2108126258Smlaier		hlen = sizeof(struct ip6_hdr);
2109126258Smlaier		bzero(&ro6, sizeof(ro6));
2110126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
2111126258Smlaier		dst6->sin6_family = AF_INET6;
2112126258Smlaier		dst6->sin6_len = sizeof(*dst6);
2113126258Smlaier		dst6->sin6_addr = addr->v6;
2114126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
2115126258Smlaier		rt = ro6.ro_rt;
2116126258Smlaier		break;
2117126258Smlaier#endif /* INET6 */
2118126258Smlaier	}
2119126258Smlaier
2120126258Smlaier	if (rt && rt->rt_ifp) {
2121126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
2122126258Smlaier		mss = max(tcp_mssdflt, mss);
2123126258Smlaier		RTFREE(rt);
2124126258Smlaier	}
2125126258Smlaier	mss = min(mss, offer);
2126126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
2127126258Smlaier	return (mss);
2128126258Smlaier}
2129126258Smlaier
2130126258Smlaiervoid
2131126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
2132126258Smlaier{
2133126258Smlaier	struct pf_rule *r = s->rule.ptr;
2134126258Smlaier
2135126258Smlaier	s->rt_ifp = NULL;
2136126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
2137126258Smlaier		return;
2138126258Smlaier	switch (s->af) {
2139126258Smlaier#ifdef INET
2140126258Smlaier	case AF_INET:
2141126258Smlaier		pf_map_addr(AF_INET, &r->rpool, saddr,
2142126258Smlaier		    &s->rt_addr, NULL);
2143126258Smlaier		s->rt_ifp = r->rpool.cur->ifp;
2144126258Smlaier		break;
2145126258Smlaier#endif /* INET */
2146126258Smlaier#ifdef INET6
2147126258Smlaier	case AF_INET6:
2148126258Smlaier		pf_map_addr(AF_INET6, &r->rpool, saddr,
2149126258Smlaier		    &s->rt_addr, NULL);
2150126258Smlaier		s->rt_ifp = r->rpool.cur->ifp;
2151126258Smlaier		break;
2152126258Smlaier#endif /* INET6 */
2153126258Smlaier	}
2154126258Smlaier}
2155126258Smlaier
2156126258Smlaierint
2157126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
2158126258Smlaier    struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h,
2159126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
2160126258Smlaier{
2161126258Smlaier	struct pf_rule		*nat = NULL, *rdr = NULL;
2162126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2163126258Smlaier	struct pf_addr		 baddr, naddr;
2164126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
2165126258Smlaier	u_int16_t		 bport, nport = 0;
2166126258Smlaier	sa_family_t		 af = pd->af;
2167126258Smlaier	int			 lookup = -1;
2168126258Smlaier	uid_t			 uid;
2169126258Smlaier	gid_t			 gid;
2170126258Smlaier	struct pf_rule		*r, *a = NULL;
2171126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2172126258Smlaier	u_short			 reason;
2173126258Smlaier	int			 rewrite = 0;
2174126258Smlaier	struct pf_tag		*pftag = NULL;
2175126258Smlaier	int			 tag = -1;
2176126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2177126258Smlaier
2178126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2179126258Smlaier
2180126258Smlaier	if (direction == PF_OUT) {
2181126258Smlaier		bport = nport = th->th_sport;
2182126258Smlaier		/* check outgoing packet for BINAT/NAT */
2183126258Smlaier		if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp,
2184126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
2185126258Smlaier		    &naddr, &nport)) != NULL) {
2186126258Smlaier			PF_ACPY(&baddr, saddr, af);
2187126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
2188126258Smlaier			    &th->th_sum, &naddr, nport, 0, af);
2189126258Smlaier			rewrite++;
2190126258Smlaier			if (nat->natpass)
2191126258Smlaier				r = NULL;
2192126258Smlaier		}
2193126258Smlaier	} else {
2194126258Smlaier		bport = nport = th->th_dport;
2195126258Smlaier		/* check incoming packet for BINAT/RDR */
2196126258Smlaier		if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr,
2197126258Smlaier		    th->th_sport, daddr, th->th_dport,
2198126258Smlaier		    &naddr, &nport)) != NULL) {
2199126258Smlaier			PF_ACPY(&baddr, daddr, af);
2200126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
2201126258Smlaier			    &th->th_sum, &naddr, nport, 0, af);
2202126258Smlaier			rewrite++;
2203126258Smlaier			if (rdr->natpass)
2204126258Smlaier				r = NULL;
2205126258Smlaier		}
2206126258Smlaier	}
2207126258Smlaier
2208126258Smlaier	while (r != NULL) {
2209126258Smlaier		r->evaluations++;
2210126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
2211126258Smlaier		    (r->ifp == ifp && r->ifnot)))
2212126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2213126258Smlaier		else if (r->direction && r->direction != direction)
2214126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2215126258Smlaier		else if (r->af && r->af != af)
2216126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2217126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
2218126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2219126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
2220126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
2221126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
2222126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
2223126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
2224126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
2225126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2226126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
2227126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
2228126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2229126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
2230126258Smlaier			r = TAILQ_NEXT(r, entries);
2231126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
2232126258Smlaier			r = TAILQ_NEXT(r, entries);
2233126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
2234126258Smlaier			r = TAILQ_NEXT(r, entries);
2235126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
2236126258Smlaier		    pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP,
2237126258Smlaier		    pd), 1)) &&
2238126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
2239126258Smlaier		    uid))
2240126258Smlaier			r = TAILQ_NEXT(r, entries);
2241126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
2242126258Smlaier		    pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP,
2243126258Smlaier		    pd), 1)) &&
2244126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
2245126258Smlaier		    gid))
2246126258Smlaier			r = TAILQ_NEXT(r, entries);
2247126258Smlaier		else if (r->match_tag &&
2248126258Smlaier		    !pf_match_tag(m, r, nat, rdr, pftag, &tag))
2249126258Smlaier			r = TAILQ_NEXT(r, entries);
2250126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
2251126258Smlaier			r = TAILQ_NEXT(r, entries);
2252126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
2253126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
2254126258Smlaier			r = TAILQ_NEXT(r, entries);
2255126258Smlaier		else {
2256126258Smlaier			if (r->tag)
2257126258Smlaier				tag = r->tag;
2258126258Smlaier			if (r->anchor == NULL) {
2259126258Smlaier				*rm = r;
2260126258Smlaier				*am = a;
2261126258Smlaier				*rsm = ruleset;
2262126258Smlaier				if ((*rm)->quick)
2263126258Smlaier					break;
2264126258Smlaier				r = TAILQ_NEXT(r, entries);
2265126258Smlaier			} else
2266126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
2267126258Smlaier				    PF_RULESET_FILTER);
2268126258Smlaier		}
2269126258Smlaier		if (r == NULL && a != NULL)
2270126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
2271126258Smlaier			    PF_RULESET_FILTER);
2272126258Smlaier	}
2273126258Smlaier	r = *rm;
2274126258Smlaier	a = *am;
2275126258Smlaier	ruleset = *rsm;
2276126258Smlaier
2277126258Smlaier	r->packets++;
2278126258Smlaier	r->bytes += pd->tot_len;
2279126258Smlaier	if (a != NULL) {
2280126258Smlaier		a->packets++;
2281126258Smlaier		a->bytes += pd->tot_len;
2282126258Smlaier	}
2283126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
2284126258Smlaier
2285126258Smlaier	if (r->log) {
2286126258Smlaier		if (rewrite)
2287126258Smlaier			m_copyback(m, off, sizeof(*th), th);
2288126258Smlaier		PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
2289126258Smlaier	}
2290126258Smlaier
2291126258Smlaier	if ((r->action == PF_DROP) &&
2292126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
2293126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
2294126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
2295126258Smlaier		/* undo NAT changes, if they have taken place */
2296126258Smlaier		if (nat != NULL) {
2297126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
2298126258Smlaier			    &th->th_sum, &baddr, bport, 0, af);
2299126258Smlaier			rewrite++;
2300126258Smlaier		} else if (rdr != NULL) {
2301126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
2302126258Smlaier			    &th->th_sum, &baddr, bport, 0, af);
2303126258Smlaier			rewrite++;
2304126258Smlaier		}
2305126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
2306126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
2307126258Smlaier		    !(th->th_flags & TH_RST)) {
2308126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
2309126258Smlaier
2310126258Smlaier			if (th->th_flags & TH_SYN)
2311126258Smlaier				ack++;
2312126258Smlaier			if (th->th_flags & TH_FIN)
2313126258Smlaier				ack++;
2314126258Smlaier			pf_send_tcp(r, af, pd->dst,
2315126258Smlaier			    pd->src, th->th_dport, th->th_sport,
2316126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
2317126258Smlaier			    r->return_ttl);
2318126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
2319126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
2320126258Smlaier			    r->return_icmp & 255, af, r);
2321126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
2322126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
2323126258Smlaier			    r->return_icmp6 & 255, af, r);
2324126258Smlaier	}
2325126258Smlaier
2326126258Smlaier	if (r->action == PF_DROP)
2327126258Smlaier		return (PF_DROP);
2328126258Smlaier
2329126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
2330126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
2331126258Smlaier		return (PF_DROP);
2332126258Smlaier	}
2333126258Smlaier
2334126258Smlaier	if (r->keep_state || nat != NULL || rdr != NULL ||
2335126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
2336126258Smlaier		/* create new state */
2337126258Smlaier		u_int16_t	 len;
2338126258Smlaier		struct pf_state	*s = NULL;
2339126258Smlaier
2340126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
2341126258Smlaier		if (!r->max_states || r->states < r->max_states)
2342126258Smlaier			s = pool_get(&pf_state_pl, PR_NOWAIT);
2343126258Smlaier		if (s == NULL) {
2344126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2345126258Smlaier			return (PF_DROP);
2346126258Smlaier		}
2347126258Smlaier		bzero(s, sizeof(*s));
2348126258Smlaier		r->states++;
2349126258Smlaier		if (a != NULL)
2350126258Smlaier			a->states++;
2351126258Smlaier		s->rule.ptr = r;
2352126258Smlaier		if (nat != NULL)
2353126258Smlaier			s->nat_rule.ptr = nat;
2354126258Smlaier		else
2355126258Smlaier			s->nat_rule.ptr = rdr;
2356126258Smlaier		if (s->nat_rule.ptr != NULL)
2357126258Smlaier			s->nat_rule.ptr->states++;
2358126258Smlaier		s->anchor.ptr = a;
2359126258Smlaier		s->allow_opts = r->allow_opts;
2360126258Smlaier		s->log = r->log & 2;
2361126258Smlaier		s->proto = IPPROTO_TCP;
2362126258Smlaier		s->direction = direction;
2363126258Smlaier		s->af = af;
2364126258Smlaier		if (direction == PF_OUT) {
2365126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
2366126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
2367126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
2368126258Smlaier			s->ext.port = th->th_dport;
2369126258Smlaier			if (nat != NULL) {
2370126258Smlaier				PF_ACPY(&s->lan.addr, &baddr, af);
2371126258Smlaier				s->lan.port = bport;
2372126258Smlaier			} else {
2373126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
2374126258Smlaier				s->lan.port = s->gwy.port;
2375126258Smlaier			}
2376126258Smlaier		} else {
2377126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
2378126258Smlaier			s->lan.port = th->th_dport;
2379126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
2380126258Smlaier			s->ext.port = th->th_sport;
2381126258Smlaier			if (rdr != NULL) {
2382126258Smlaier				PF_ACPY(&s->gwy.addr, &baddr, af);
2383126258Smlaier				s->gwy.port = bport;
2384126258Smlaier			} else {
2385126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
2386126258Smlaier				s->gwy.port = s->lan.port;
2387126258Smlaier			}
2388126258Smlaier		}
2389126258Smlaier
2390126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
2391126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
2392126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
2393126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
2394126258Smlaier			/* Generate sequence number modulator */
2395126258Smlaier			while ((s->src.seqdiff = arc4random()) == 0)
2396126258Smlaier				;
2397126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
2398126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
2399126258Smlaier			rewrite = 1;
2400126258Smlaier		} else
2401126258Smlaier			s->src.seqdiff = 0;
2402126258Smlaier		if (th->th_flags & TH_SYN) {
2403126258Smlaier			s->src.seqhi++;
2404126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
2405126258Smlaier		}
2406126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
2407126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
2408126258Smlaier			/* Remove scale factor from initial window */
2409126258Smlaier			int win = s->src.max_win;
2410126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
2411126258Smlaier			s->src.max_win = (win - 1) >>
2412126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
2413126258Smlaier		}
2414126258Smlaier		if (th->th_flags & TH_FIN)
2415126258Smlaier			s->src.seqhi++;
2416126258Smlaier		s->dst.seqhi = 1;
2417126258Smlaier		s->dst.max_win = 1;
2418126258Smlaier		s->src.state = TCPS_SYN_SENT;
2419126258Smlaier		s->dst.state = TCPS_CLOSED;
2420126258Smlaier		s->creation = time.tv_sec;
2421126258Smlaier		s->expire = time.tv_sec;
2422126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
2423126258Smlaier		s->packets[0] = 1;
2424126258Smlaier		s->bytes[0] = pd->tot_len;
2425126258Smlaier		pf_set_rt_ifp(s, saddr);
2426126258Smlaier
2427126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
2428126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
2429126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2430126258Smlaier			pool_put(&pf_state_pl, s);
2431126258Smlaier			return (PF_DROP);
2432126258Smlaier		}
2433126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
2434126258Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, &s->src,
2435126258Smlaier		    &s->dst, &rewrite)) {
2436126258Smlaier			pf_normalize_tcp_cleanup(s);
2437126258Smlaier			pool_put(&pf_state_pl, s);
2438126258Smlaier			return (PF_DROP);
2439126258Smlaier		}
2440126258Smlaier		if (pf_insert_state(s)) {
2441126258Smlaier			pf_normalize_tcp_cleanup(s);
2442126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2443126258Smlaier			pool_put(&pf_state_pl, s);
2444126258Smlaier			return (PF_DROP);
2445126258Smlaier		} else
2446126258Smlaier			*sm = s;
2447126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
2448126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
2449126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
2450126258Smlaier			if (nat != NULL)
2451126258Smlaier				pf_change_ap(saddr, &th->th_sport,
2452126258Smlaier				    pd->ip_sum, &th->th_sum, &baddr,
2453126258Smlaier				    bport, 0, af);
2454126258Smlaier			else if (rdr != NULL)
2455126258Smlaier				pf_change_ap(daddr, &th->th_dport,
2456126258Smlaier				    pd->ip_sum, &th->th_sum, &baddr,
2457126258Smlaier				    bport, 0, af);
2458126258Smlaier			s->src.seqhi = arc4random();
2459126258Smlaier			/* Find mss option */
2460126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
2461126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
2462126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
2463126258Smlaier			s->src.mss = mss;
2464126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
2465126258Smlaier			    th->th_sport, s->src.seqhi,
2466126258Smlaier			    ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, s->src.mss, 0);
2467126258Smlaier			return (PF_SYNPROXY_DROP);
2468126258Smlaier		}
2469126258Smlaier	}
2470126258Smlaier
2471126258Smlaier	/* copy back packet headers if we performed NAT operations */
2472126258Smlaier	if (rewrite)
2473126258Smlaier		m_copyback(m, off, sizeof(*th), th);
2474126258Smlaier
2475126258Smlaier	return (PF_PASS);
2476126258Smlaier}
2477126258Smlaier
2478126258Smlaierint
2479126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
2480126258Smlaier    struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h,
2481126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
2482126258Smlaier{
2483126258Smlaier	struct pf_rule		*nat = NULL, *rdr = NULL;
2484126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2485126258Smlaier	struct pf_addr		 baddr, naddr;
2486126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
2487126258Smlaier	u_int16_t		 bport, nport = 0;
2488126258Smlaier	sa_family_t		 af = pd->af;
2489126258Smlaier	int			 lookup = -1;
2490126258Smlaier	uid_t			 uid;
2491126258Smlaier	gid_t			 gid;
2492126258Smlaier	struct pf_rule		*r, *a = NULL;
2493126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2494126258Smlaier	u_short			 reason;
2495126258Smlaier	int			 rewrite = 0;
2496126258Smlaier	struct pf_tag		*pftag = NULL;
2497126258Smlaier	int			 tag = -1;
2498126258Smlaier
2499126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2500126258Smlaier
2501126258Smlaier	if (direction == PF_OUT) {
2502126258Smlaier		bport = nport = uh->uh_sport;
2503126258Smlaier		/* check outgoing packet for BINAT/NAT */
2504126258Smlaier		if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp,
2505126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
2506126258Smlaier		    &naddr, &nport)) != NULL) {
2507126258Smlaier			PF_ACPY(&baddr, saddr, af);
2508126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
2509126258Smlaier			    &uh->uh_sum, &naddr, nport, 1, af);
2510126258Smlaier			rewrite++;
2511126258Smlaier			if (nat->natpass)
2512126258Smlaier				r = NULL;
2513126258Smlaier		}
2514126258Smlaier	} else {
2515126258Smlaier		bport = nport = uh->uh_dport;
2516126258Smlaier		/* check incoming packet for BINAT/RDR */
2517126258Smlaier		if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr,
2518126258Smlaier		    uh->uh_sport, daddr, uh->uh_dport, &naddr, &nport))
2519126258Smlaier		    != NULL) {
2520126258Smlaier			PF_ACPY(&baddr, daddr, af);
2521126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
2522126258Smlaier			    &uh->uh_sum, &naddr, nport, 1, af);
2523126258Smlaier			rewrite++;
2524126258Smlaier			if (rdr->natpass)
2525126258Smlaier				r = NULL;
2526126258Smlaier		}
2527126258Smlaier	}
2528126258Smlaier
2529126258Smlaier	while (r != NULL) {
2530126258Smlaier		r->evaluations++;
2531126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
2532126258Smlaier		    (r->ifp == ifp && r->ifnot)))
2533126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2534126258Smlaier		else if (r->direction && r->direction != direction)
2535126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2536126258Smlaier		else if (r->af && r->af != af)
2537126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2538126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
2539126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2540126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
2541126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
2542126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
2543126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
2544126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
2545126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
2546126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2547126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
2548126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
2549126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2550126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
2551126258Smlaier			r = TAILQ_NEXT(r, entries);
2552126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
2553126258Smlaier			r = TAILQ_NEXT(r, entries);
2554126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
2555126258Smlaier		    pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP,
2556126258Smlaier		    pd), 1)) &&
2557126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
2558126258Smlaier		    uid))
2559126258Smlaier			r = TAILQ_NEXT(r, entries);
2560126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
2561126258Smlaier		    pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP,
2562126258Smlaier		    pd), 1)) &&
2563126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
2564126258Smlaier		    gid))
2565126258Smlaier			r = TAILQ_NEXT(r, entries);
2566126258Smlaier		else if (r->match_tag &&
2567126258Smlaier		    !pf_match_tag(m, r, nat, rdr, pftag, &tag))
2568126258Smlaier			r = TAILQ_NEXT(r, entries);
2569126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
2570126258Smlaier			r = TAILQ_NEXT(r, entries);
2571126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
2572126258Smlaier			r = TAILQ_NEXT(r, entries);
2573126258Smlaier		else {
2574126258Smlaier			if (r->tag)
2575126258Smlaier				tag = r->tag;
2576126258Smlaier			if (r->anchor == NULL) {
2577126258Smlaier				*rm = r;
2578126258Smlaier				*am = a;
2579126258Smlaier				*rsm = ruleset;
2580126258Smlaier				if ((*rm)->quick)
2581126258Smlaier					break;
2582126258Smlaier				r = TAILQ_NEXT(r, entries);
2583126258Smlaier			} else
2584126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
2585126258Smlaier				    PF_RULESET_FILTER);
2586126258Smlaier		}
2587126258Smlaier		if (r == NULL && a != NULL)
2588126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
2589126258Smlaier			    PF_RULESET_FILTER);
2590126258Smlaier	}
2591126258Smlaier	r = *rm;
2592126258Smlaier	a = *am;
2593126258Smlaier	ruleset = *rsm;
2594126258Smlaier
2595126258Smlaier	r->packets++;
2596126258Smlaier	r->bytes += pd->tot_len;
2597126258Smlaier	if (a != NULL) {
2598126258Smlaier		a->packets++;
2599126258Smlaier		a->bytes += pd->tot_len;
2600126258Smlaier	}
2601126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
2602126258Smlaier
2603126258Smlaier	if (r->log) {
2604126258Smlaier		if (rewrite)
2605126258Smlaier			m_copyback(m, off, sizeof(*uh), uh);
2606126258Smlaier		PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
2607126258Smlaier	}
2608126258Smlaier
2609126258Smlaier	if ((r->action == PF_DROP) &&
2610126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
2611126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
2612126258Smlaier		/* undo NAT changes, if they have taken place */
2613126258Smlaier		if (nat != NULL) {
2614126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
2615126258Smlaier			    &uh->uh_sum, &baddr, bport, 1, af);
2616126258Smlaier			rewrite++;
2617126258Smlaier		} else if (rdr != NULL) {
2618126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
2619126258Smlaier			    &uh->uh_sum, &baddr, bport, 1, af);
2620126258Smlaier			rewrite++;
2621126258Smlaier		}
2622126258Smlaier		if ((af == AF_INET) && r->return_icmp)
2623126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
2624126258Smlaier			    r->return_icmp & 255, af, r);
2625126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
2626126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
2627126258Smlaier			    r->return_icmp6 & 255, af, r);
2628126258Smlaier	}
2629126258Smlaier
2630126258Smlaier	if (r->action == PF_DROP)
2631126258Smlaier		return (PF_DROP);
2632126258Smlaier
2633126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
2634126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
2635126258Smlaier		return (PF_DROP);
2636126258Smlaier	}
2637126258Smlaier
2638126258Smlaier	if (r->keep_state || nat != NULL || rdr != NULL) {
2639126258Smlaier		/* create new state */
2640126258Smlaier		struct pf_state	*s = NULL;
2641126258Smlaier
2642126258Smlaier		if (!r->max_states || r->states < r->max_states)
2643126258Smlaier			s = pool_get(&pf_state_pl, PR_NOWAIT);
2644126258Smlaier		if (s == NULL) {
2645126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2646126258Smlaier			return (PF_DROP);
2647126258Smlaier		}
2648126258Smlaier		bzero(s, sizeof(*s));
2649126258Smlaier		r->states++;
2650126258Smlaier		if (a != NULL)
2651126258Smlaier			a->states++;
2652126258Smlaier		s->rule.ptr = r;
2653126258Smlaier		if (nat != NULL)
2654126258Smlaier			s->nat_rule.ptr = nat;
2655126258Smlaier		else
2656126258Smlaier			s->nat_rule.ptr = rdr;
2657126258Smlaier		if (s->nat_rule.ptr != NULL)
2658126258Smlaier			s->nat_rule.ptr->states++;
2659126258Smlaier		s->anchor.ptr = a;
2660126258Smlaier		s->allow_opts = r->allow_opts;
2661126258Smlaier		s->log = r->log & 2;
2662126258Smlaier		s->proto = IPPROTO_UDP;
2663126258Smlaier		s->direction = direction;
2664126258Smlaier		s->af = af;
2665126258Smlaier		if (direction == PF_OUT) {
2666126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
2667126258Smlaier			s->gwy.port = uh->uh_sport;
2668126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
2669126258Smlaier			s->ext.port = uh->uh_dport;
2670126258Smlaier			if (nat != NULL) {
2671126258Smlaier				PF_ACPY(&s->lan.addr, &baddr, af);
2672126258Smlaier				s->lan.port = bport;
2673126258Smlaier			} else {
2674126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
2675126258Smlaier				s->lan.port = s->gwy.port;
2676126258Smlaier			}
2677126258Smlaier		} else {
2678126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
2679126258Smlaier			s->lan.port = uh->uh_dport;
2680126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
2681126258Smlaier			s->ext.port = uh->uh_sport;
2682126258Smlaier			if (rdr != NULL) {
2683126258Smlaier				PF_ACPY(&s->gwy.addr, &baddr, af);
2684126258Smlaier				s->gwy.port = bport;
2685126258Smlaier			} else {
2686126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
2687126258Smlaier				s->gwy.port = s->lan.port;
2688126258Smlaier			}
2689126258Smlaier		}
2690126258Smlaier		s->src.state = PFUDPS_SINGLE;
2691126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
2692126258Smlaier		s->creation = time.tv_sec;
2693126258Smlaier		s->expire = time.tv_sec;
2694126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
2695126258Smlaier		s->packets[0] = 1;
2696126258Smlaier		s->bytes[0] = pd->tot_len;
2697126258Smlaier		pf_set_rt_ifp(s, saddr);
2698126258Smlaier		if (pf_insert_state(s)) {
2699126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2700126258Smlaier			pool_put(&pf_state_pl, s);
2701126258Smlaier			return (PF_DROP);
2702126258Smlaier		} else
2703126258Smlaier			*sm = s;
2704126258Smlaier	}
2705126258Smlaier
2706126258Smlaier	/* copy back packet headers if we performed NAT operations */
2707126258Smlaier	if (rewrite)
2708126258Smlaier		m_copyback(m, off, sizeof(*uh), uh);
2709126258Smlaier
2710126258Smlaier	return (PF_PASS);
2711126258Smlaier}
2712126258Smlaier
2713126258Smlaierint
2714126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
2715126258Smlaier    struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h,
2716126258Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm)
2717126258Smlaier{
2718126258Smlaier	struct pf_rule		*nat = NULL, *rdr = NULL;
2719126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2720126258Smlaier	struct pf_addr		 baddr, naddr;
2721126258Smlaier	struct pf_rule		*r, *a = NULL;
2722126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2723126258Smlaier	u_short			 reason;
2724126258Smlaier	u_int16_t		 icmpid;
2725126258Smlaier	sa_family_t		 af = pd->af;
2726126258Smlaier	u_int8_t		 icmptype, icmpcode;
2727126258Smlaier	int			 state_icmp = 0;
2728126258Smlaier	struct pf_tag		*pftag = NULL;
2729126258Smlaier	int			 tag = -1;
2730126258Smlaier#ifdef INET6
2731126258Smlaier	int			 rewrite = 0;
2732126258Smlaier#endif /* INET6 */
2733126258Smlaier
2734126258Smlaier	switch (pd->proto) {
2735126258Smlaier#ifdef INET
2736126258Smlaier	case IPPROTO_ICMP:
2737126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
2738126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
2739126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
2740126258Smlaier
2741126258Smlaier		if (icmptype == ICMP_UNREACH ||
2742126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
2743126258Smlaier		    icmptype == ICMP_REDIRECT ||
2744126258Smlaier		    icmptype == ICMP_TIMXCEED ||
2745126258Smlaier		    icmptype == ICMP_PARAMPROB)
2746126258Smlaier			state_icmp++;
2747126258Smlaier		break;
2748126258Smlaier#endif /* INET */
2749126258Smlaier#ifdef INET6
2750126258Smlaier	case IPPROTO_ICMPV6:
2751126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
2752126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
2753126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
2754126258Smlaier
2755126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
2756126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
2757126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
2758126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
2759126258Smlaier			state_icmp++;
2760126258Smlaier		break;
2761126258Smlaier#endif /* INET6 */
2762126258Smlaier	}
2763126258Smlaier
2764126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2765126258Smlaier
2766126258Smlaier	if (direction == PF_OUT) {
2767126258Smlaier		/* check outgoing packet for BINAT/NAT */
2768126258Smlaier		if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0,
2769126258Smlaier		    daddr, 0, &naddr, NULL)) != NULL) {
2770126258Smlaier			PF_ACPY(&baddr, saddr, af);
2771126258Smlaier			switch (af) {
2772126258Smlaier#ifdef INET
2773126258Smlaier			case AF_INET:
2774126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
2775126258Smlaier				    naddr.v4.s_addr, 0);
2776126258Smlaier				break;
2777126258Smlaier#endif /* INET */
2778126258Smlaier#ifdef INET6
2779126258Smlaier			case AF_INET6:
2780126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
2781126258Smlaier				    &naddr, 0);
2782126258Smlaier				rewrite++;
2783126258Smlaier				break;
2784126258Smlaier#endif /* INET6 */
2785126258Smlaier			}
2786126258Smlaier			if (nat->natpass)
2787126258Smlaier				r = NULL;
2788126258Smlaier		}
2789126258Smlaier	} else {
2790126258Smlaier		/* check incoming packet for BINAT/RDR */
2791126258Smlaier		if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0,
2792126258Smlaier		    daddr, 0, &naddr, NULL)) != NULL) {
2793126258Smlaier			PF_ACPY(&baddr, daddr, af);
2794126258Smlaier			switch (af) {
2795126258Smlaier#ifdef INET
2796126258Smlaier			case AF_INET:
2797126258Smlaier				pf_change_a(&daddr->v4.s_addr,
2798126258Smlaier				    pd->ip_sum, naddr.v4.s_addr, 0);
2799126258Smlaier				break;
2800126258Smlaier#endif /* INET */
2801126258Smlaier#ifdef INET6
2802126258Smlaier			case AF_INET6:
2803126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
2804126258Smlaier				    &naddr, 0);
2805126258Smlaier				rewrite++;
2806126258Smlaier				break;
2807126258Smlaier#endif /* INET6 */
2808126258Smlaier			}
2809126258Smlaier			if (rdr->natpass)
2810126258Smlaier				r = NULL;
2811126258Smlaier		}
2812126258Smlaier	}
2813126258Smlaier
2814126258Smlaier	while (r != NULL) {
2815126258Smlaier		r->evaluations++;
2816126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
2817126258Smlaier		    (r->ifp == ifp && r->ifnot)))
2818126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2819126258Smlaier		else if (r->direction && r->direction != direction)
2820126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2821126258Smlaier		else if (r->af && r->af != af)
2822126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2823126258Smlaier		else if (r->proto && r->proto != pd->proto)
2824126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2825126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.not))
2826126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
2827126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.not))
2828126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2829126258Smlaier		else if (r->type && r->type != icmptype + 1)
2830126258Smlaier			r = TAILQ_NEXT(r, entries);
2831126258Smlaier		else if (r->code && r->code != icmpcode + 1)
2832126258Smlaier			r = TAILQ_NEXT(r, entries);
2833126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
2834126258Smlaier			r = TAILQ_NEXT(r, entries);
2835126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
2836126258Smlaier			r = TAILQ_NEXT(r, entries);
2837126258Smlaier		else if (r->match_tag &&
2838126258Smlaier		    !pf_match_tag(m, r, nat, rdr, pftag, &tag))
2839126258Smlaier			r = TAILQ_NEXT(r, entries);
2840126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
2841126258Smlaier			r = TAILQ_NEXT(r, entries);
2842126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
2843126258Smlaier			r = TAILQ_NEXT(r, entries);
2844126258Smlaier		else {
2845126258Smlaier			if (r->tag)
2846126258Smlaier				tag = r->tag;
2847126258Smlaier			if (r->anchor == NULL) {
2848126258Smlaier				*rm = r;
2849126258Smlaier				*am = a;
2850126258Smlaier				*rsm = ruleset;
2851126258Smlaier				if ((*rm)->quick)
2852126258Smlaier					break;
2853126258Smlaier				r = TAILQ_NEXT(r, entries);
2854126258Smlaier			} else
2855126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
2856126258Smlaier				    PF_RULESET_FILTER);
2857126258Smlaier		}
2858126258Smlaier		if (r == NULL && a != NULL)
2859126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
2860126258Smlaier			    PF_RULESET_FILTER);
2861126258Smlaier	}
2862126258Smlaier	r = *rm;
2863126258Smlaier	a = *am;
2864126258Smlaier	ruleset = *rsm;
2865126258Smlaier
2866126258Smlaier	r->packets++;
2867126258Smlaier	r->bytes += pd->tot_len;
2868126258Smlaier	if (a != NULL) {
2869126258Smlaier		a->packets++;
2870126258Smlaier		a->bytes += pd->tot_len;
2871126258Smlaier	}
2872126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
2873126258Smlaier
2874126258Smlaier	if (r->log) {
2875126258Smlaier#ifdef INET6
2876126258Smlaier		if (rewrite)
2877126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
2878126258Smlaier			    pd->hdr.icmp6);
2879126258Smlaier#endif /* INET6 */
2880126258Smlaier		PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
2881126258Smlaier	}
2882126258Smlaier
2883126258Smlaier	if (r->action != PF_PASS)
2884126258Smlaier		return (PF_DROP);
2885126258Smlaier
2886126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
2887126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
2888126258Smlaier		return (PF_DROP);
2889126258Smlaier	}
2890126258Smlaier
2891126258Smlaier	if (!state_icmp && (r->keep_state ||
2892126258Smlaier	    nat != NULL || rdr != NULL)) {
2893126258Smlaier		/* create new state */
2894126258Smlaier		struct pf_state	*s = NULL;
2895126258Smlaier
2896126258Smlaier		if (!r->max_states || r->states < r->max_states)
2897126258Smlaier			s = pool_get(&pf_state_pl, PR_NOWAIT);
2898126258Smlaier		if (s == NULL) {
2899126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2900126258Smlaier			return (PF_DROP);
2901126258Smlaier		}
2902126258Smlaier		bzero(s, sizeof(*s));
2903126258Smlaier		r->states++;
2904126258Smlaier		if (a != NULL)
2905126258Smlaier			a->states++;
2906126258Smlaier		s->rule.ptr = r;
2907126258Smlaier		if (nat != NULL)
2908126258Smlaier			s->nat_rule.ptr = nat;
2909126258Smlaier		else
2910126258Smlaier			s->nat_rule.ptr = rdr;
2911126258Smlaier		if (s->nat_rule.ptr != NULL)
2912126258Smlaier			s->nat_rule.ptr->states++;
2913126258Smlaier		s->anchor.ptr = a;
2914126258Smlaier		s->allow_opts = r->allow_opts;
2915126258Smlaier		s->log = r->log & 2;
2916126258Smlaier		s->proto = pd->proto;
2917126258Smlaier		s->direction = direction;
2918126258Smlaier		s->af = af;
2919126258Smlaier		if (direction == PF_OUT) {
2920126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
2921126258Smlaier			s->gwy.port = icmpid;
2922126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
2923126258Smlaier			s->ext.port = icmpid;
2924126258Smlaier			if (nat != NULL)
2925126258Smlaier				PF_ACPY(&s->lan.addr, &baddr, af);
2926126258Smlaier			else
2927126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
2928126258Smlaier			s->lan.port = icmpid;
2929126258Smlaier		} else {
2930126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
2931126258Smlaier			s->lan.port = icmpid;
2932126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
2933126258Smlaier			s->ext.port = icmpid;
2934126258Smlaier			if (rdr != NULL)
2935126258Smlaier				PF_ACPY(&s->gwy.addr, &baddr, af);
2936126258Smlaier			else
2937126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
2938126258Smlaier			s->gwy.port = icmpid;
2939126258Smlaier		}
2940126258Smlaier		s->creation = time.tv_sec;
2941126258Smlaier		s->expire = time.tv_sec;
2942126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
2943126258Smlaier		s->packets[0] = 1;
2944126258Smlaier		s->bytes[0] = pd->tot_len;
2945126258Smlaier		pf_set_rt_ifp(s, saddr);
2946126258Smlaier		if (pf_insert_state(s)) {
2947126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
2948126258Smlaier			pool_put(&pf_state_pl, s);
2949126258Smlaier			return (PF_DROP);
2950126258Smlaier		} else
2951126258Smlaier			*sm = s;
2952126258Smlaier	}
2953126258Smlaier
2954126258Smlaier#ifdef INET6
2955126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
2956126258Smlaier	if (rewrite)
2957126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
2958126258Smlaier		    pd->hdr.icmp6);
2959126258Smlaier#endif /* INET6 */
2960126258Smlaier
2961126258Smlaier	return (PF_PASS);
2962126258Smlaier}
2963126258Smlaier
2964126258Smlaierint
2965126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
2966126258Smlaier    struct ifnet *ifp, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
2967126258Smlaier    struct pf_rule **am, struct pf_ruleset **rsm)
2968126258Smlaier{
2969126258Smlaier	struct pf_rule		*nat = NULL, *rdr = NULL;
2970126258Smlaier	struct pf_rule		*r, *a = NULL;
2971126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2972126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2973126258Smlaier	struct pf_addr		 baddr, naddr;
2974126258Smlaier	sa_family_t		 af = pd->af;
2975126258Smlaier	u_short			 reason;
2976126258Smlaier	struct pf_tag		*pftag = NULL;
2977126258Smlaier	int			 tag = -1;
2978126258Smlaier
2979126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2980126258Smlaier
2981126258Smlaier	if (direction == PF_OUT) {
2982126258Smlaier		/* check outgoing packet for BINAT/NAT */
2983126258Smlaier		if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0,
2984126258Smlaier		    daddr, 0, &naddr, NULL)) != NULL) {
2985126258Smlaier			PF_ACPY(&baddr, saddr, af);
2986126258Smlaier			switch (af) {
2987126258Smlaier#ifdef INET
2988126258Smlaier			case AF_INET:
2989126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
2990126258Smlaier				    naddr.v4.s_addr, 0);
2991126258Smlaier				break;
2992126258Smlaier#endif /* INET */
2993126258Smlaier#ifdef INET6
2994126258Smlaier			case AF_INET6:
2995126258Smlaier				PF_ACPY(saddr, &naddr, af);
2996126258Smlaier				break;
2997126258Smlaier#endif /* INET6 */
2998126258Smlaier			}
2999126258Smlaier			if (nat->natpass)
3000126258Smlaier				r = NULL;
3001126258Smlaier		}
3002126258Smlaier	} else {
3003126258Smlaier		/* check incoming packet for BINAT/RDR */
3004126258Smlaier		if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0,
3005126258Smlaier		    daddr, 0, &naddr, NULL)) != NULL) {
3006126258Smlaier			PF_ACPY(&baddr, daddr, af);
3007126258Smlaier			switch (af) {
3008126258Smlaier#ifdef INET
3009126258Smlaier			case AF_INET:
3010126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3011126258Smlaier				    pd->ip_sum, naddr.v4.s_addr, 0);
3012126258Smlaier				break;
3013126258Smlaier#endif /* INET */
3014126258Smlaier#ifdef INET6
3015126258Smlaier			case AF_INET6:
3016126258Smlaier				PF_ACPY(daddr, &naddr, af);
3017126258Smlaier				break;
3018126258Smlaier#endif /* INET6 */
3019126258Smlaier			}
3020126258Smlaier			if (rdr->natpass)
3021126258Smlaier				r = NULL;
3022126258Smlaier		}
3023126258Smlaier	}
3024126258Smlaier
3025126258Smlaier	while (r != NULL) {
3026126258Smlaier		r->evaluations++;
3027126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
3028126258Smlaier		    (r->ifp == ifp && r->ifnot)))
3029126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3030126258Smlaier		else if (r->direction && r->direction != direction)
3031126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3032126258Smlaier		else if (r->af && r->af != af)
3033126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3034126258Smlaier		else if (r->proto && r->proto != pd->proto)
3035126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3036126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
3037126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3038126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
3039126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3040126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3041126258Smlaier			r = TAILQ_NEXT(r, entries);
3042126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3043126258Smlaier			r = TAILQ_NEXT(r, entries);
3044126258Smlaier		else if (r->match_tag &&
3045126258Smlaier		    !pf_match_tag(m, r, nat, rdr, pftag, &tag))
3046126258Smlaier			r = TAILQ_NEXT(r, entries);
3047126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3048126258Smlaier			r = TAILQ_NEXT(r, entries);
3049126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3050126258Smlaier			r = TAILQ_NEXT(r, entries);
3051126258Smlaier		else {
3052126258Smlaier			if (r->tag)
3053126258Smlaier				tag = r->tag;
3054126258Smlaier			if (r->anchor == NULL) {
3055126258Smlaier				*rm = r;
3056126258Smlaier				*am = a;
3057126258Smlaier				*rsm = ruleset;
3058126258Smlaier				if ((*rm)->quick)
3059126258Smlaier					break;
3060126258Smlaier				r = TAILQ_NEXT(r, entries);
3061126258Smlaier			} else
3062126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3063126258Smlaier				    PF_RULESET_FILTER);
3064126258Smlaier		}
3065126258Smlaier		if (r == NULL && a != NULL)
3066126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3067126258Smlaier			    PF_RULESET_FILTER);
3068126258Smlaier	}
3069126258Smlaier	r = *rm;
3070126258Smlaier	a = *am;
3071126258Smlaier	ruleset = *rsm;
3072126258Smlaier
3073126258Smlaier	r->packets++;
3074126258Smlaier	r->bytes += pd->tot_len;
3075126258Smlaier	if (a != NULL) {
3076126258Smlaier		a->packets++;
3077126258Smlaier		a->bytes += pd->tot_len;
3078126258Smlaier	}
3079126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3080126258Smlaier	if (r->log)
3081126258Smlaier		PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
3082126258Smlaier
3083126258Smlaier	if ((r->action == PF_DROP) &&
3084126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3085126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3086126258Smlaier		struct pf_addr *a = NULL;
3087126258Smlaier
3088126258Smlaier		if (nat != NULL)
3089126258Smlaier			a = saddr;
3090126258Smlaier		else if (rdr != NULL)
3091126258Smlaier			a = daddr;
3092126258Smlaier		if (a != NULL) {
3093126258Smlaier			switch (af) {
3094126258Smlaier#ifdef INET
3095126258Smlaier			case AF_INET:
3096126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
3097126258Smlaier				    baddr.v4.s_addr, 0);
3098126258Smlaier				break;
3099126258Smlaier#endif /* INET */
3100126258Smlaier#ifdef INET6
3101126258Smlaier			case AF_INET6:
3102126258Smlaier				PF_ACPY(a, &baddr, af);
3103126258Smlaier				break;
3104126258Smlaier#endif /* INET6 */
3105126258Smlaier			}
3106126258Smlaier		}
3107126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3108126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3109126258Smlaier			    r->return_icmp & 255, af, r);
3110126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3111126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3112126258Smlaier			    r->return_icmp6 & 255, af, r);
3113126258Smlaier	}
3114126258Smlaier
3115126258Smlaier	if (r->action != PF_PASS)
3116126258Smlaier		return (PF_DROP);
3117126258Smlaier
3118126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3119126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3120126258Smlaier		return (PF_DROP);
3121126258Smlaier	}
3122126258Smlaier
3123126258Smlaier	if (r->keep_state || nat != NULL || rdr != NULL) {
3124126258Smlaier		/* create new state */
3125126258Smlaier		struct pf_state	*s = NULL;
3126126258Smlaier
3127126258Smlaier		if (!r->max_states || r->states < r->max_states)
3128126258Smlaier			s = pool_get(&pf_state_pl, PR_NOWAIT);
3129126258Smlaier		if (s == NULL) {
3130126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3131126258Smlaier			return (PF_DROP);
3132126258Smlaier		}
3133126258Smlaier		bzero(s, sizeof(*s));
3134126258Smlaier		r->states++;
3135126258Smlaier		if (a != NULL)
3136126258Smlaier			a->states++;
3137126258Smlaier		s->rule.ptr = r;
3138126258Smlaier		if (nat != NULL)
3139126258Smlaier			s->nat_rule.ptr = nat;
3140126258Smlaier		else
3141126258Smlaier			s->nat_rule.ptr = rdr;
3142126258Smlaier		if (s->nat_rule.ptr != NULL)
3143126258Smlaier			s->nat_rule.ptr->states++;
3144126258Smlaier		s->anchor.ptr = a;
3145126258Smlaier		s->allow_opts = r->allow_opts;
3146126258Smlaier		s->log = r->log & 2;
3147126258Smlaier		s->proto = pd->proto;
3148126258Smlaier		s->direction = direction;
3149126258Smlaier		s->af = af;
3150126258Smlaier		if (direction == PF_OUT) {
3151126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3152126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3153126258Smlaier			if (nat != NULL)
3154126258Smlaier				PF_ACPY(&s->lan.addr, &baddr, af);
3155126258Smlaier			else
3156126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3157126258Smlaier		} else {
3158126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3159126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3160126258Smlaier			if (rdr != NULL)
3161126258Smlaier				PF_ACPY(&s->gwy.addr, &baddr, af);
3162126258Smlaier			else
3163126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3164126258Smlaier		}
3165126258Smlaier		s->src.state = PFOTHERS_SINGLE;
3166126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
3167126258Smlaier		s->creation = time.tv_sec;
3168126258Smlaier		s->expire = time.tv_sec;
3169126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
3170126258Smlaier		s->packets[0] = 1;
3171126258Smlaier		s->bytes[0] = pd->tot_len;
3172126258Smlaier		pf_set_rt_ifp(s, saddr);
3173126258Smlaier		if (pf_insert_state(s)) {
3174126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3175126258Smlaier			if (r->log)
3176126258Smlaier				PFLOG_PACKET(ifp, h, m, af, direction, reason,
3177126258Smlaier				    r, a, ruleset);
3178126258Smlaier			pool_put(&pf_state_pl, s);
3179126258Smlaier			return (PF_DROP);
3180126258Smlaier		} else
3181126258Smlaier			*sm = s;
3182126258Smlaier	}
3183126258Smlaier
3184126258Smlaier	return (PF_PASS);
3185126258Smlaier}
3186126258Smlaier
3187126258Smlaierint
3188126258Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp,
3189126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
3190126258Smlaier    struct pf_ruleset **rsm)
3191126258Smlaier{
3192126258Smlaier	struct pf_rule		*r, *a = NULL;
3193126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3194126258Smlaier	sa_family_t		 af = pd->af;
3195126258Smlaier	u_short			 reason;
3196126258Smlaier	struct pf_tag		*pftag = NULL;
3197126258Smlaier	int			 tag = -1;
3198126258Smlaier
3199126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3200126258Smlaier	while (r != NULL) {
3201126258Smlaier		r->evaluations++;
3202126258Smlaier		if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) ||
3203126258Smlaier		    (r->ifp == ifp && r->ifnot)))
3204126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3205126258Smlaier		else if (r->direction && r->direction != direction)
3206126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3207126258Smlaier		else if (r->af && r->af != af)
3208126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3209126258Smlaier		else if (r->proto && r->proto != pd->proto)
3210126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3211126258Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.not))
3212126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3213126258Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.not))
3214126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3215126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3216126258Smlaier			r = TAILQ_NEXT(r, entries);
3217126258Smlaier		else if (r->src.port_op || r->dst.port_op ||
3218126258Smlaier		    r->flagset || r->type || r->code ||
3219126258Smlaier		    r->os_fingerprint != PF_OSFP_ANY)
3220126258Smlaier			r = TAILQ_NEXT(r, entries);
3221126258Smlaier		else if (r->match_tag &&
3222126258Smlaier		    !pf_match_tag(m, r, NULL, NULL, pftag, &tag))
3223126258Smlaier			r = TAILQ_NEXT(r, entries);
3224126258Smlaier		else if (r->anchorname[0] && r->anchor == NULL)
3225126258Smlaier			r = TAILQ_NEXT(r, entries);
3226126258Smlaier		else {
3227126258Smlaier			if (r->anchor == NULL) {
3228126258Smlaier				*rm = r;
3229126258Smlaier				*am = a;
3230126258Smlaier				*rsm = ruleset;
3231126258Smlaier				if ((*rm)->quick)
3232126258Smlaier					break;
3233126258Smlaier				r = TAILQ_NEXT(r, entries);
3234126258Smlaier			} else
3235126258Smlaier				PF_STEP_INTO_ANCHOR(r, a, ruleset,
3236126258Smlaier				    PF_RULESET_FILTER);
3237126258Smlaier		}
3238126258Smlaier		if (r == NULL && a != NULL)
3239126258Smlaier			PF_STEP_OUT_OF_ANCHOR(r, a, ruleset,
3240126258Smlaier			    PF_RULESET_FILTER);
3241126258Smlaier	}
3242126258Smlaier	r = *rm;
3243126258Smlaier	a = *am;
3244126258Smlaier	ruleset = *rsm;
3245126258Smlaier
3246126258Smlaier	r->packets++;
3247126258Smlaier	r->bytes += pd->tot_len;
3248126258Smlaier	if (a != NULL) {
3249126258Smlaier		a->packets++;
3250126258Smlaier		a->bytes += pd->tot_len;
3251126258Smlaier	}
3252126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3253126258Smlaier	if (r->log)
3254126258Smlaier		PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
3255126258Smlaier
3256126258Smlaier	if (r->action != PF_PASS)
3257126258Smlaier		return (PF_DROP);
3258126258Smlaier
3259126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3260126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3261126258Smlaier		return (PF_DROP);
3262126258Smlaier	}
3263126258Smlaier
3264126258Smlaier	return (PF_PASS);
3265126258Smlaier}
3266126258Smlaier
3267126258Smlaierint
3268126258Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
3269126258Smlaier    struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd,
3270126258Smlaier    u_short *reason)
3271126258Smlaier{
3272126258Smlaier	struct pf_tree_node	 key;
3273126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3274126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
3275126258Smlaier	u_int32_t		 ack, end, seq;
3276126258Smlaier	u_int8_t		 sws, dws;
3277126258Smlaier	int			 ackskew, dirndx;
3278126258Smlaier	int			 copyback = 0;
3279126258Smlaier	struct pf_state_peer	*src, *dst;
3280126258Smlaier
3281126258Smlaier	key.af = pd->af;
3282126258Smlaier	key.proto = IPPROTO_TCP;
3283126258Smlaier	PF_ACPY(&key.addr[0], pd->src, key.af);
3284126258Smlaier	PF_ACPY(&key.addr[1], pd->dst, key.af);
3285126258Smlaier	key.port[0] = th->th_sport;
3286126258Smlaier	key.port[1] = th->th_dport;
3287126258Smlaier
3288126258Smlaier	STATE_LOOKUP();
3289126258Smlaier
3290126258Smlaier	if (direction == (*state)->direction) {
3291126258Smlaier		src = &(*state)->src;
3292126258Smlaier		dst = &(*state)->dst;
3293126258Smlaier		dirndx = 0;
3294126258Smlaier	} else {
3295126258Smlaier		src = &(*state)->dst;
3296126258Smlaier		dst = &(*state)->src;
3297126258Smlaier		dirndx = 1;
3298126258Smlaier	}
3299126258Smlaier
3300126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
3301126258Smlaier		if (direction != (*state)->direction)
3302126258Smlaier			return (PF_SYNPROXY_DROP);
3303126258Smlaier		if (th->th_flags & TH_SYN) {
3304126258Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo)
3305126258Smlaier				return (PF_DROP);
3306126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
3307126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3308126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
3309126258Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0);
3310126258Smlaier			return (PF_SYNPROXY_DROP);
3311126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
3312126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
3313126258Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
3314126258Smlaier			return (PF_DROP);
3315126258Smlaier		else
3316126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
3317126258Smlaier	}
3318126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
3319126258Smlaier		struct pf_state_host *src, *dst;
3320126258Smlaier
3321126258Smlaier		if (direction == PF_OUT) {
3322126258Smlaier			src = &(*state)->gwy;
3323126258Smlaier			dst = &(*state)->ext;
3324126258Smlaier		} else {
3325126258Smlaier			src = &(*state)->ext;
3326126258Smlaier			dst = &(*state)->lan;
3327126258Smlaier		}
3328126258Smlaier		if (direction == (*state)->direction) {
3329126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
3330126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
3331126258Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1))
3332126258Smlaier				return (PF_DROP);
3333126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
3334126258Smlaier			if ((*state)->dst.seqhi == 1)
3335126258Smlaier				(*state)->dst.seqhi = arc4random();
3336126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
3337126258Smlaier			    &dst->addr, src->port, dst->port,
3338126258Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0);
3339126258Smlaier			return (PF_SYNPROXY_DROP);
3340126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
3341126258Smlaier		    (TH_SYN|TH_ACK)) ||
3342126258Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1))
3343126258Smlaier			return (PF_DROP);
3344126258Smlaier		else {
3345126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
3346126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
3347126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
3348126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3349126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
3350126258Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0);
3351126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
3352126258Smlaier			    &dst->addr, src->port, dst->port,
3353126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
3354126258Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0);
3355126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
3356126258Smlaier			    (*state)->src.seqlo;
3357126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
3358126258Smlaier			    (*state)->dst.seqlo;
3359126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
3360126258Smlaier			    (*state)->src.max_win;
3361126258Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
3362126258Smlaier			    (*state)->dst.max_win;
3363126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
3364126258Smlaier			(*state)->src.state = (*state)->dst.state =
3365126258Smlaier			    TCPS_ESTABLISHED;
3366126258Smlaier			return (PF_SYNPROXY_DROP);
3367126258Smlaier		}
3368126258Smlaier	}
3369126258Smlaier
3370126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
3371126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
3372126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
3373126258Smlaier	} else
3374126258Smlaier		sws = dws = 0;
3375126258Smlaier
3376126258Smlaier	/*
3377126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
3378126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
3379126258Smlaier	 *	tcp_filtering.ps
3380126258Smlaier	 */
3381126258Smlaier
3382126258Smlaier	seq = ntohl(th->th_seq);
3383126258Smlaier	if (src->seqlo == 0) {
3384126258Smlaier		/* First packet from this end. Set its state */
3385126258Smlaier
3386126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
3387126258Smlaier		    src->scrub == NULL) {
3388126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
3389126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
3390126258Smlaier				return (PF_DROP);
3391126258Smlaier			}
3392126258Smlaier		}
3393126258Smlaier
3394126258Smlaier		/* Deferred generation of sequence number modulator */
3395126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
3396126258Smlaier			while ((src->seqdiff = arc4random()) == 0)
3397126258Smlaier				;
3398126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
3399126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
3400126258Smlaier			    src->seqdiff), 0);
3401126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
3402126258Smlaier			copyback = 1;
3403126258Smlaier		} else {
3404126258Smlaier			ack = ntohl(th->th_ack);
3405126258Smlaier		}
3406126258Smlaier
3407126258Smlaier		end = seq + pd->p_len;
3408126258Smlaier		if (th->th_flags & TH_SYN) {
3409126258Smlaier			end++;
3410126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
3411126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
3412126258Smlaier				    pd->af);
3413126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
3414126258Smlaier					/* Remove scale factor from initial
3415126258Smlaier					 * window */
3416126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
3417126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
3418126258Smlaier					    >> sws;
3419126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
3420126258Smlaier				} else {
3421126258Smlaier					/* fixup other window */
3422126258Smlaier					dst->max_win <<= dst->wscale &
3423126258Smlaier					    PF_WSCALE_MASK;
3424126258Smlaier					/* in case of a retrans SYN|ACK */
3425126258Smlaier					dst->wscale = 0;
3426126258Smlaier				}
3427126258Smlaier			}
3428126258Smlaier		}
3429126258Smlaier		if (th->th_flags & TH_FIN)
3430126258Smlaier			end++;
3431126258Smlaier
3432126258Smlaier		src->seqlo = seq;
3433126258Smlaier		if (src->state < TCPS_SYN_SENT)
3434126258Smlaier			src->state = TCPS_SYN_SENT;
3435126258Smlaier
3436126258Smlaier		/*
3437126258Smlaier		 * May need to slide the window (seqhi may have been set by
3438126258Smlaier		 * the crappy stack check or if we picked up the connection
3439126258Smlaier		 * after establishment)
3440126258Smlaier		 */
3441126258Smlaier		if (src->seqhi == 1 ||
3442126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
3443126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
3444126258Smlaier		if (win > src->max_win)
3445126258Smlaier			src->max_win = win;
3446126258Smlaier
3447126258Smlaier	} else {
3448126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
3449126258Smlaier		if (src->seqdiff) {
3450126258Smlaier			/* Modulate sequence numbers */
3451126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
3452126258Smlaier			    src->seqdiff), 0);
3453126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
3454126258Smlaier			copyback = 1;
3455126258Smlaier		}
3456126258Smlaier		end = seq + pd->p_len;
3457126258Smlaier		if (th->th_flags & TH_SYN)
3458126258Smlaier			end++;
3459126258Smlaier		if (th->th_flags & TH_FIN)
3460126258Smlaier			end++;
3461126258Smlaier	}
3462126258Smlaier
3463126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
3464126258Smlaier		/* Let it pass through the ack skew check */
3465126258Smlaier		ack = dst->seqlo;
3466126258Smlaier	} else if ((ack == 0 &&
3467126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
3468126258Smlaier	    /* broken tcp stacks do not set ack */
3469126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
3470126258Smlaier		/*
3471126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
3472126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
3473126258Smlaier		 */
3474126258Smlaier		ack = dst->seqlo;
3475126258Smlaier	}
3476126258Smlaier
3477126258Smlaier	if (seq == end) {
3478126258Smlaier		/* Ease sequencing restrictions on no data packets */
3479126258Smlaier		seq = src->seqlo;
3480126258Smlaier		end = seq;
3481126258Smlaier	}
3482126258Smlaier
3483126258Smlaier	ackskew = dst->seqlo - ack;
3484126258Smlaier
3485126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
3486126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
3487126258Smlaier	    /* Last octet inside other's window space */
3488126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
3489126258Smlaier	    /* Retrans: not more than one window back */
3490126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
3491126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
3492126258Smlaier	    (ackskew <= (MAXACKWINDOW << sws))) {
3493126258Smlaier	    /* Acking not more than one window forward */
3494126258Smlaier
3495126258Smlaier		(*state)->packets[dirndx]++;
3496126258Smlaier		(*state)->bytes[dirndx] += pd->tot_len;
3497126258Smlaier
3498126258Smlaier		/* update max window */
3499126258Smlaier		if (src->max_win < win)
3500126258Smlaier			src->max_win = win;
3501126258Smlaier		/* synchronize sequencing */
3502126258Smlaier		if (SEQ_GT(end, src->seqlo))
3503126258Smlaier			src->seqlo = end;
3504126258Smlaier		/* slide the window of what the other end can send */
3505126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
3506126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
3507126258Smlaier
3508126258Smlaier
3509126258Smlaier		/* update states */
3510126258Smlaier		if (th->th_flags & TH_SYN)
3511126258Smlaier			if (src->state < TCPS_SYN_SENT)
3512126258Smlaier				src->state = TCPS_SYN_SENT;
3513126258Smlaier		if (th->th_flags & TH_FIN)
3514126258Smlaier			if (src->state < TCPS_CLOSING)
3515126258Smlaier				src->state = TCPS_CLOSING;
3516126258Smlaier		if (th->th_flags & TH_ACK) {
3517126258Smlaier			if (dst->state == TCPS_SYN_SENT)
3518126258Smlaier				dst->state = TCPS_ESTABLISHED;
3519126258Smlaier			else if (dst->state == TCPS_CLOSING)
3520126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
3521126258Smlaier		}
3522126258Smlaier		if (th->th_flags & TH_RST)
3523126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
3524126258Smlaier
3525126258Smlaier		/* update expire time */
3526126258Smlaier		(*state)->expire = time.tv_sec;
3527126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
3528126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
3529126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
3530126258Smlaier		else if (src->state >= TCPS_FIN_WAIT_2 ||
3531126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
3532126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
3533126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
3534126258Smlaier		    dst->state < TCPS_ESTABLISHED)
3535126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
3536126258Smlaier		else if (src->state >= TCPS_CLOSING ||
3537126258Smlaier		    dst->state >= TCPS_CLOSING)
3538126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
3539126258Smlaier		else
3540126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
3541126258Smlaier
3542126258Smlaier		/* Fall through to PASS packet */
3543126258Smlaier
3544126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
3545126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
3546126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
3547126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
3548126258Smlaier	    /* Within a window forward of the originating packet */
3549126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
3550126258Smlaier	    /* Within a window backward of the originating packet */
3551126258Smlaier
3552126258Smlaier		/*
3553126258Smlaier		 * This currently handles three situations:
3554126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
3555126258Smlaier		 *     replies.
3556126258Smlaier		 *  2) When PF catches an already established stream (the
3557126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
3558126258Smlaier		 *     changed...)
3559126258Smlaier		 *  3) Packets get funky immediately after the connection
3560126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
3561126258Smlaier		 *     that web servers like to spew after a close)
3562126258Smlaier		 *
3563126258Smlaier		 * This must be a little more careful than the above code
3564126258Smlaier		 * since packet floods will also be caught here. We don't
3565126258Smlaier		 * update the TTL here to mitigate the damage of a packet
3566126258Smlaier		 * flood and so the same code can handle awkward establishment
3567126258Smlaier		 * and a loosened connection close.
3568126258Smlaier		 * In the establishment case, a correct peer response will
3569126258Smlaier		 * validate the connection, go through the normal state code
3570126258Smlaier		 * and keep updating the state TTL.
3571126258Smlaier		 */
3572126258Smlaier
3573126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
3574126258Smlaier			printf("pf: loose state match: ");
3575126258Smlaier			pf_print_state(*state);
3576126258Smlaier			pf_print_flags(th->th_flags);
3577126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
3578126258Smlaier			    seq, ack, pd->p_len, ackskew,
3579126258Smlaier			    (*state)->packets[0], (*state)->packets[1]);
3580126258Smlaier		}
3581126258Smlaier
3582126258Smlaier		(*state)->packets[dirndx]++;
3583126258Smlaier		(*state)->bytes[dirndx] += pd->tot_len;
3584126258Smlaier
3585126258Smlaier		/* update max window */
3586126258Smlaier		if (src->max_win < win)
3587126258Smlaier			src->max_win = win;
3588126258Smlaier		/* synchronize sequencing */
3589126258Smlaier		if (SEQ_GT(end, src->seqlo))
3590126258Smlaier			src->seqlo = end;
3591126258Smlaier		/* slide the window of what the other end can send */
3592126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
3593126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
3594126258Smlaier
3595126258Smlaier		/*
3596126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
3597126258Smlaier		 * SYN and not an already established connection.
3598126258Smlaier		 */
3599126258Smlaier
3600126258Smlaier		if (th->th_flags & TH_FIN)
3601126258Smlaier			if (src->state < TCPS_CLOSING)
3602126258Smlaier				src->state = TCPS_CLOSING;
3603126258Smlaier		if (th->th_flags & TH_RST)
3604126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
3605126258Smlaier
3606126258Smlaier		/* Fall through to PASS packet */
3607126258Smlaier
3608126258Smlaier	} else {
3609126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
3610126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
3611126258Smlaier			/* Send RST for state mismatches during handshake */
3612126258Smlaier			if (!(th->th_flags & TH_RST)) {
3613126258Smlaier				u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3614126258Smlaier
3615126258Smlaier				if (th->th_flags & TH_SYN)
3616126258Smlaier					ack++;
3617126258Smlaier				if (th->th_flags & TH_FIN)
3618126258Smlaier					ack++;
3619126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
3620126258Smlaier				    pd->dst, pd->src, th->th_dport,
3621126258Smlaier				    th->th_sport, ntohl(th->th_ack), ack,
3622126258Smlaier				    TH_RST|TH_ACK, 0, 0,
3623126258Smlaier				    (*state)->rule.ptr->return_ttl);
3624126258Smlaier			}
3625126258Smlaier			src->seqlo = 0;
3626126258Smlaier			src->seqhi = 1;
3627126258Smlaier			src->max_win = 1;
3628126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
3629126258Smlaier			printf("pf: BAD state: ");
3630126258Smlaier			pf_print_state(*state);
3631126258Smlaier			pf_print_flags(th->th_flags);
3632126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
3633126258Smlaier			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
3634126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
3635126258Smlaier			    direction == PF_IN ? "in" : "out",
3636126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
3637126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
3638126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
3639126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
3640126258Smlaier			    ' ': '2',
3641126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
3642126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
3643126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
3644126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
3645126258Smlaier		}
3646126258Smlaier		return (PF_DROP);
3647126258Smlaier	}
3648126258Smlaier
3649126258Smlaier	if (dst->scrub || src->scrub) {
3650126258Smlaier		if (pf_normalize_tcp_stateful(m, off, pd, reason, th, src, dst,
3651126258Smlaier		    &copyback))
3652126258Smlaier			return (PF_DROP);
3653126258Smlaier	}
3654126258Smlaier
3655126258Smlaier	/* Any packets which have gotten here are to be passed */
3656126258Smlaier
3657126258Smlaier	/* translate source/destination address, if necessary */
3658126258Smlaier	if (STATE_TRANSLATE(*state)) {
3659126258Smlaier		if (direction == PF_OUT)
3660126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
3661126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
3662126258Smlaier			    (*state)->gwy.port, 0, pd->af);
3663126258Smlaier		else
3664126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
3665126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
3666126258Smlaier			    (*state)->lan.port, 0, pd->af);
3667126258Smlaier		m_copyback(m, off, sizeof(*th), th);
3668126258Smlaier	} else if (copyback) {
3669126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
3670126258Smlaier		m_copyback(m, off, sizeof(*th), th);
3671126258Smlaier	}
3672126258Smlaier
3673126258Smlaier	(*state)->rule.ptr->packets++;
3674126258Smlaier	(*state)->rule.ptr->bytes += pd->tot_len;
3675126258Smlaier	if ((*state)->nat_rule.ptr != NULL) {
3676126258Smlaier		(*state)->nat_rule.ptr->packets++;
3677126258Smlaier		(*state)->nat_rule.ptr->bytes += pd->tot_len;
3678126258Smlaier	}
3679126258Smlaier	if ((*state)->anchor.ptr != NULL) {
3680126258Smlaier		(*state)->anchor.ptr->packets++;
3681126258Smlaier		(*state)->anchor.ptr->bytes += pd->tot_len;
3682126258Smlaier	}
3683126258Smlaier	return (PF_PASS);
3684126258Smlaier}
3685126258Smlaier
3686126258Smlaierint
3687126258Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp,
3688126258Smlaier    struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd)
3689126258Smlaier{
3690126258Smlaier	struct pf_state_peer	*src, *dst;
3691126258Smlaier	struct pf_tree_node	 key;
3692126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3693126258Smlaier	int			dirndx;
3694126258Smlaier
3695126258Smlaier	key.af = pd->af;
3696126258Smlaier	key.proto = IPPROTO_UDP;
3697126258Smlaier	PF_ACPY(&key.addr[0], pd->src, key.af);
3698126258Smlaier	PF_ACPY(&key.addr[1], pd->dst, key.af);
3699126258Smlaier	key.port[0] = uh->uh_sport;
3700126258Smlaier	key.port[1] = uh->uh_dport;
3701126258Smlaier
3702126258Smlaier	STATE_LOOKUP();
3703126258Smlaier
3704126258Smlaier	if (direction == (*state)->direction) {
3705126258Smlaier		src = &(*state)->src;
3706126258Smlaier		dst = &(*state)->dst;
3707126258Smlaier		dirndx = 0;
3708126258Smlaier	} else {
3709126258Smlaier		src = &(*state)->dst;
3710126258Smlaier		dst = &(*state)->src;
3711126258Smlaier		dirndx = 1;
3712126258Smlaier	}
3713126258Smlaier
3714126258Smlaier	(*state)->packets[dirndx]++;
3715126258Smlaier	(*state)->bytes[dirndx] += pd->tot_len;
3716126258Smlaier
3717126258Smlaier	/* update states */
3718126258Smlaier	if (src->state < PFUDPS_SINGLE)
3719126258Smlaier		src->state = PFUDPS_SINGLE;
3720126258Smlaier	if (dst->state == PFUDPS_SINGLE)
3721126258Smlaier		dst->state = PFUDPS_MULTIPLE;
3722126258Smlaier
3723126258Smlaier	/* update expire time */
3724126258Smlaier	(*state)->expire = time.tv_sec;
3725126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
3726126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
3727126258Smlaier	else
3728126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
3729126258Smlaier
3730126258Smlaier	/* translate source/destination address, if necessary */
3731126258Smlaier	if (STATE_TRANSLATE(*state)) {
3732126258Smlaier		if (direction == PF_OUT)
3733126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
3734126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
3735126258Smlaier			    (*state)->gwy.port, 1, pd->af);
3736126258Smlaier		else
3737126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
3738126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
3739126258Smlaier			    (*state)->lan.port, 1, pd->af);
3740126258Smlaier		m_copyback(m, off, sizeof(*uh), uh);
3741126258Smlaier	}
3742126258Smlaier
3743126258Smlaier	(*state)->rule.ptr->packets++;
3744126258Smlaier	(*state)->rule.ptr->bytes += pd->tot_len;
3745126258Smlaier	if ((*state)->nat_rule.ptr != NULL) {
3746126258Smlaier		(*state)->nat_rule.ptr->packets++;
3747126258Smlaier		(*state)->nat_rule.ptr->bytes += pd->tot_len;
3748126258Smlaier	}
3749126258Smlaier	if ((*state)->anchor.ptr != NULL) {
3750126258Smlaier		(*state)->anchor.ptr->packets++;
3751126258Smlaier		(*state)->anchor.ptr->bytes += pd->tot_len;
3752126258Smlaier	}
3753126258Smlaier	return (PF_PASS);
3754126258Smlaier}
3755126258Smlaier
3756126258Smlaierint
3757126258Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
3758126258Smlaier    struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd)
3759126258Smlaier{
3760126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
3761126258Smlaier	u_int16_t	 icmpid, *icmpsum;
3762126258Smlaier	u_int8_t	 icmptype;
3763126258Smlaier	int		 state_icmp = 0, dirndx;
3764126258Smlaier
3765126258Smlaier	switch (pd->proto) {
3766126258Smlaier#ifdef INET
3767126258Smlaier	case IPPROTO_ICMP:
3768126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3769126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
3770126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
3771126258Smlaier
3772126258Smlaier		if (icmptype == ICMP_UNREACH ||
3773126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
3774126258Smlaier		    icmptype == ICMP_REDIRECT ||
3775126258Smlaier		    icmptype == ICMP_TIMXCEED ||
3776126258Smlaier		    icmptype == ICMP_PARAMPROB)
3777126258Smlaier			state_icmp++;
3778126258Smlaier		break;
3779126258Smlaier#endif /* INET */
3780126258Smlaier#ifdef INET6
3781126258Smlaier	case IPPROTO_ICMPV6:
3782126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
3783126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
3784126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
3785126258Smlaier
3786126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
3787126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
3788126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
3789126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
3790126258Smlaier			state_icmp++;
3791126258Smlaier		break;
3792126258Smlaier#endif /* INET6 */
3793126258Smlaier	}
3794126258Smlaier
3795126258Smlaier	if (!state_icmp) {
3796126258Smlaier
3797126258Smlaier		/*
3798126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
3799126258Smlaier		 * Search for an ICMP state.
3800126258Smlaier		 */
3801126258Smlaier		struct pf_tree_node	key;
3802126258Smlaier
3803126258Smlaier		key.af = pd->af;
3804126258Smlaier		key.proto = pd->proto;
3805126258Smlaier		PF_ACPY(&key.addr[0], saddr, key.af);
3806126258Smlaier		PF_ACPY(&key.addr[1], daddr, key.af);
3807126258Smlaier		key.port[0] = icmpid;
3808126258Smlaier		key.port[1] = icmpid;
3809126258Smlaier
3810126258Smlaier		STATE_LOOKUP();
3811126258Smlaier
3812126258Smlaier		dirndx = (direction == (*state)->direction) ? 0 : 1;
3813126258Smlaier		(*state)->packets[dirndx]++;
3814126258Smlaier		(*state)->bytes[dirndx] += pd->tot_len;
3815126258Smlaier		(*state)->expire = time.tv_sec;
3816126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
3817126258Smlaier
3818126258Smlaier		/* translate source/destination address, if necessary */
3819126258Smlaier		if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) {
3820126258Smlaier			if (direction == PF_OUT) {
3821126258Smlaier				switch (pd->af) {
3822126258Smlaier#ifdef INET
3823126258Smlaier				case AF_INET:
3824126258Smlaier					pf_change_a(&saddr->v4.s_addr,
3825126258Smlaier					    pd->ip_sum,
3826126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
3827126258Smlaier					break;
3828126258Smlaier#endif /* INET */
3829126258Smlaier#ifdef INET6
3830126258Smlaier				case AF_INET6:
3831126258Smlaier					pf_change_a6(saddr,
3832126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
3833126258Smlaier					    &(*state)->gwy.addr, 0);
3834126258Smlaier					m_copyback(m, off,
3835126258Smlaier					    sizeof(struct icmp6_hdr),
3836126258Smlaier					    pd->hdr.icmp6);
3837126258Smlaier					break;
3838126258Smlaier#endif /* INET6 */
3839126258Smlaier				}
3840126258Smlaier			} else {
3841126258Smlaier				switch (pd->af) {
3842126258Smlaier#ifdef INET
3843126258Smlaier				case AF_INET:
3844126258Smlaier					pf_change_a(&daddr->v4.s_addr,
3845126258Smlaier					    pd->ip_sum,
3846126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
3847126258Smlaier					break;
3848126258Smlaier#endif /* INET */
3849126258Smlaier#ifdef INET6
3850126258Smlaier				case AF_INET6:
3851126258Smlaier					pf_change_a6(daddr,
3852126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
3853126258Smlaier					    &(*state)->lan.addr, 0);
3854126258Smlaier					m_copyback(m, off,
3855126258Smlaier					    sizeof(struct icmp6_hdr),
3856126258Smlaier					    pd->hdr.icmp6);
3857126258Smlaier					break;
3858126258Smlaier#endif /* INET6 */
3859126258Smlaier				}
3860126258Smlaier			}
3861126258Smlaier		}
3862126258Smlaier
3863126258Smlaier		return (PF_PASS);
3864126258Smlaier
3865126258Smlaier	} else {
3866126258Smlaier		/*
3867126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
3868126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
3869126258Smlaier		 */
3870126258Smlaier
3871126258Smlaier		struct pf_pdesc	pd2;
3872126258Smlaier#ifdef INET
3873126258Smlaier		struct ip	h2;
3874126258Smlaier#endif /* INET */
3875126258Smlaier#ifdef INET6
3876126258Smlaier		struct ip6_hdr	h2_6;
3877126258Smlaier		int		terminal = 0;
3878126258Smlaier#endif /* INET6 */
3879126258Smlaier		int		ipoff2;
3880126258Smlaier		int		off2;
3881126258Smlaier
3882126258Smlaier		pd2.af = pd->af;
3883126258Smlaier		switch (pd->af) {
3884126258Smlaier#ifdef INET
3885126258Smlaier		case AF_INET:
3886126258Smlaier			/* offset of h2 in mbuf chain */
3887126258Smlaier			ipoff2 = off + ICMP_MINLEN;
3888126258Smlaier
3889126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
3890126258Smlaier			    NULL, NULL, pd2.af)) {
3891126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
3892126258Smlaier				    ("pf: ICMP error message too short "
3893126258Smlaier				    "(ip)\n"));
3894126258Smlaier				return (PF_DROP);
3895126258Smlaier			}
3896126258Smlaier			/*
3897126258Smlaier			 * ICMP error messages don't refer to non-first
3898126258Smlaier			 * fragments
3899126258Smlaier			 */
3900126258Smlaier			if (h2.ip_off & htons(IP_OFFMASK))
3901126258Smlaier				return (PF_DROP);
3902126258Smlaier
3903126258Smlaier			/* offset of protocol header that follows h2 */
3904126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
3905126258Smlaier
3906126258Smlaier			pd2.proto = h2.ip_p;
3907126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
3908126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
3909126258Smlaier			pd2.ip_sum = &h2.ip_sum;
3910126258Smlaier			break;
3911126258Smlaier#endif /* INET */
3912126258Smlaier#ifdef INET6
3913126258Smlaier		case AF_INET6:
3914126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
3915126258Smlaier
3916126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
3917126258Smlaier			    NULL, NULL, pd2.af)) {
3918126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
3919126258Smlaier				    ("pf: ICMP error message too short "
3920126258Smlaier				    "(ip6)\n"));
3921126258Smlaier				return (PF_DROP);
3922126258Smlaier			}
3923126258Smlaier			pd2.proto = h2_6.ip6_nxt;
3924126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
3925126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
3926126258Smlaier			pd2.ip_sum = NULL;
3927126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
3928126258Smlaier			do {
3929126258Smlaier				switch (pd2.proto) {
3930126258Smlaier				case IPPROTO_FRAGMENT:
3931126258Smlaier					/*
3932126258Smlaier					 * ICMPv6 error messages for
3933126258Smlaier					 * non-first fragments
3934126258Smlaier					 */
3935126258Smlaier					return (PF_DROP);
3936126258Smlaier				case IPPROTO_AH:
3937126258Smlaier				case IPPROTO_HOPOPTS:
3938126258Smlaier				case IPPROTO_ROUTING:
3939126258Smlaier				case IPPROTO_DSTOPTS: {
3940126258Smlaier					/* get next header and header length */
3941126258Smlaier					struct ip6_ext opt6;
3942126258Smlaier
3943126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
3944126258Smlaier					    sizeof(opt6), NULL, NULL, pd2.af)) {
3945126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
3946126258Smlaier						    ("pf: ICMPv6 short opt\n"));
3947126258Smlaier						return (PF_DROP);
3948126258Smlaier					}
3949126258Smlaier					if (pd2.proto == IPPROTO_AH)
3950126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
3951126258Smlaier					else
3952126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
3953126258Smlaier					pd2.proto = opt6.ip6e_nxt;
3954126258Smlaier					/* goto the next header */
3955126258Smlaier					break;
3956126258Smlaier				}
3957126258Smlaier				default:
3958126258Smlaier					terminal++;
3959126258Smlaier					break;
3960126258Smlaier				}
3961126258Smlaier			} while (!terminal);
3962126258Smlaier			break;
3963126258Smlaier#endif /* INET6 */
3964126258Smlaier		}
3965126258Smlaier
3966126258Smlaier		switch (pd2.proto) {
3967126258Smlaier		case IPPROTO_TCP: {
3968126258Smlaier			struct tcphdr		 th;
3969126258Smlaier			u_int32_t		 seq;
3970126258Smlaier			struct pf_tree_node	 key;
3971126258Smlaier			struct pf_state_peer	*src, *dst;
3972126258Smlaier			u_int8_t		 dws;
3973126258Smlaier
3974126258Smlaier			/*
3975126258Smlaier			 * Only the first 8 bytes of the TCP header can be
3976126258Smlaier			 * expected. Don't access any TCP header fields after
3977126258Smlaier			 * th_seq, an ackskew test is not possible.
3978126258Smlaier			 */
3979126258Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) {
3980126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
3981126258Smlaier				    ("pf: ICMP error message too short "
3982126258Smlaier				    "(tcp)\n"));
3983126258Smlaier				return (PF_DROP);
3984126258Smlaier			}
3985126258Smlaier
3986126258Smlaier			key.af = pd2.af;
3987126258Smlaier			key.proto = IPPROTO_TCP;
3988126258Smlaier			PF_ACPY(&key.addr[0], pd2.dst, pd2.af);
3989126258Smlaier			key.port[0] = th.th_dport;
3990126258Smlaier			PF_ACPY(&key.addr[1], pd2.src, pd2.af);
3991126258Smlaier			key.port[1] = th.th_sport;
3992126258Smlaier
3993126258Smlaier			STATE_LOOKUP();
3994126258Smlaier
3995126258Smlaier			if (direction == (*state)->direction) {
3996126258Smlaier				src = &(*state)->dst;
3997126258Smlaier				dst = &(*state)->src;
3998126258Smlaier			} else {
3999126258Smlaier				src = &(*state)->src;
4000126258Smlaier				dst = &(*state)->dst;
4001126258Smlaier			}
4002126258Smlaier
4003126258Smlaier			if (src->wscale && dst->wscale && !(th.th_flags & TH_SYN))
4004126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
4005126258Smlaier			else
4006126258Smlaier				dws = 0;
4007126258Smlaier
4008126258Smlaier			/* Demodulate sequence number */
4009126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
4010126258Smlaier			if (src->seqdiff)
4011126258Smlaier				pf_change_a(&th.th_seq, &th.th_sum,
4012126258Smlaier				    htonl(seq), 0);
4013126258Smlaier
4014126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
4015126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
4016126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
4017126258Smlaier					printf("pf: BAD ICMP %d:%d ",
4018126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
4019126258Smlaier					pf_print_host(pd->src, 0, pd->af);
4020126258Smlaier					printf(" -> ");
4021126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
4022126258Smlaier					printf(" state: ");
4023126258Smlaier					pf_print_state(*state);
4024126258Smlaier					printf(" seq=%u\n", seq);
4025126258Smlaier				}
4026126258Smlaier				return (PF_DROP);
4027126258Smlaier			}
4028126258Smlaier
4029126258Smlaier			if (STATE_TRANSLATE(*state)) {
4030126258Smlaier				if (direction == PF_IN) {
4031126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
4032126258Smlaier					    saddr, &(*state)->lan.addr,
4033126258Smlaier					    (*state)->lan.port, NULL,
4034126258Smlaier					    pd2.ip_sum, icmpsum,
4035126258Smlaier					    pd->ip_sum, 0, pd2.af);
4036126258Smlaier				} else {
4037126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
4038126258Smlaier					    saddr, &(*state)->gwy.addr,
4039126258Smlaier					    (*state)->gwy.port, NULL,
4040126258Smlaier					    pd2.ip_sum, icmpsum,
4041126258Smlaier					    pd->ip_sum, 0, pd2.af);
4042126258Smlaier				}
4043126258Smlaier				switch (pd2.af) {
4044126258Smlaier#ifdef INET
4045126258Smlaier				case AF_INET:
4046126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4047126258Smlaier					    pd->hdr.icmp);
4048126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
4049126258Smlaier					    &h2);
4050126258Smlaier					break;
4051126258Smlaier#endif /* INET */
4052126258Smlaier#ifdef INET6
4053126258Smlaier				case AF_INET6:
4054126258Smlaier					m_copyback(m, off,
4055126258Smlaier					    sizeof(struct icmp6_hdr),
4056126258Smlaier					    pd->hdr.icmp6);
4057126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
4058126258Smlaier					    &h2_6);
4059126258Smlaier					break;
4060126258Smlaier#endif /* INET6 */
4061126258Smlaier				}
4062126258Smlaier				m_copyback(m, off2, 8, &th);
4063126258Smlaier			} else if (src->seqdiff) {
4064126258Smlaier				m_copyback(m, off2, 8, &th);
4065126258Smlaier			}
4066126258Smlaier
4067126258Smlaier			return (PF_PASS);
4068126258Smlaier			break;
4069126258Smlaier		}
4070126258Smlaier		case IPPROTO_UDP: {
4071126258Smlaier			struct udphdr		uh;
4072126258Smlaier			struct pf_tree_node	key;
4073126258Smlaier
4074126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
4075126258Smlaier			    NULL, NULL, pd2.af)) {
4076126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4077126258Smlaier				    ("pf: ICMP error message too short "
4078126258Smlaier				    "(udp)\n"));
4079126258Smlaier				return (PF_DROP);
4080126258Smlaier			}
4081126258Smlaier
4082126258Smlaier			key.af = pd2.af;
4083126258Smlaier			key.proto = IPPROTO_UDP;
4084126258Smlaier			PF_ACPY(&key.addr[0], pd2.dst, pd2.af);
4085126258Smlaier			key.port[0] = uh.uh_dport;
4086126258Smlaier			PF_ACPY(&key.addr[1], pd2.src, pd2.af);
4087126258Smlaier			key.port[1] = uh.uh_sport;
4088126258Smlaier
4089126258Smlaier			STATE_LOOKUP();
4090126258Smlaier
4091126258Smlaier			if (STATE_TRANSLATE(*state)) {
4092126258Smlaier				if (direction == PF_IN) {
4093126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
4094126258Smlaier					    daddr, &(*state)->lan.addr,
4095126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
4096126258Smlaier					    pd2.ip_sum, icmpsum,
4097126258Smlaier					    pd->ip_sum, 1, pd2.af);
4098126258Smlaier				} else {
4099126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
4100126258Smlaier					    saddr, &(*state)->gwy.addr,
4101126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
4102126258Smlaier					    pd2.ip_sum, icmpsum,
4103126258Smlaier					    pd->ip_sum, 1, pd2.af);
4104126258Smlaier				}
4105126258Smlaier				switch (pd2.af) {
4106126258Smlaier#ifdef INET
4107126258Smlaier				case AF_INET:
4108126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4109126258Smlaier					    pd->hdr.icmp);
4110126258Smlaier					m_copyback(m, ipoff2, sizeof(h2), &h2);
4111126258Smlaier					break;
4112126258Smlaier#endif /* INET */
4113126258Smlaier#ifdef INET6
4114126258Smlaier				case AF_INET6:
4115126258Smlaier					m_copyback(m, off,
4116126258Smlaier					    sizeof(struct icmp6_hdr),
4117126258Smlaier					    pd->hdr.icmp6);
4118126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
4119126258Smlaier					    &h2_6);
4120126258Smlaier					break;
4121126258Smlaier#endif /* INET6 */
4122126258Smlaier				}
4123126258Smlaier				m_copyback(m, off2, sizeof(uh), &uh);
4124126258Smlaier			}
4125126258Smlaier
4126126258Smlaier			return (PF_PASS);
4127126258Smlaier			break;
4128126258Smlaier		}
4129126258Smlaier#ifdef INET
4130126258Smlaier		case IPPROTO_ICMP: {
4131126258Smlaier			struct icmp		iih;
4132126258Smlaier			struct pf_tree_node	key;
4133126258Smlaier
4134126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
4135126258Smlaier			    NULL, NULL, pd2.af)) {
4136126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4137126258Smlaier				    ("pf: ICMP error message too short i"
4138126258Smlaier				    "(icmp)\n"));
4139126258Smlaier				return (PF_DROP);
4140126258Smlaier			}
4141126258Smlaier
4142126258Smlaier			key.af = pd2.af;
4143126258Smlaier			key.proto = IPPROTO_ICMP;
4144126258Smlaier			PF_ACPY(&key.addr[0], pd2.dst, pd2.af);
4145126258Smlaier			key.port[0] = iih.icmp_id;
4146126258Smlaier			PF_ACPY(&key.addr[1], pd2.src, pd2.af);
4147126258Smlaier			key.port[1] = iih.icmp_id;
4148126258Smlaier
4149126258Smlaier			STATE_LOOKUP();
4150126258Smlaier
4151126258Smlaier			if (STATE_TRANSLATE(*state)) {
4152126258Smlaier				if (direction == PF_IN) {
4153126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
4154126258Smlaier					    daddr, &(*state)->lan.addr,
4155126258Smlaier					    (*state)->lan.port, NULL,
4156126258Smlaier					    pd2.ip_sum, icmpsum,
4157126258Smlaier					    pd->ip_sum, 0, AF_INET);
4158126258Smlaier				} else {
4159126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
4160126258Smlaier					    saddr, &(*state)->gwy.addr,
4161126258Smlaier					    (*state)->gwy.port, NULL,
4162126258Smlaier					    pd2.ip_sum, icmpsum,
4163126258Smlaier					    pd->ip_sum, 0, AF_INET);
4164126258Smlaier				}
4165126258Smlaier				m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
4166126258Smlaier				m_copyback(m, ipoff2, sizeof(h2), &h2);
4167126258Smlaier				m_copyback(m, off2, ICMP_MINLEN, &iih);
4168126258Smlaier			}
4169126258Smlaier
4170126258Smlaier			return (PF_PASS);
4171126258Smlaier			break;
4172126258Smlaier		}
4173126258Smlaier#endif /* INET */
4174126258Smlaier#ifdef INET6
4175126258Smlaier		case IPPROTO_ICMPV6: {
4176126258Smlaier			struct icmp6_hdr	iih;
4177126258Smlaier			struct pf_tree_node	key;
4178126258Smlaier
4179126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
4180126258Smlaier			    sizeof(struct icmp6_hdr), NULL, NULL, pd2.af)) {
4181126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4182126258Smlaier				    ("pf: ICMP error message too short "
4183126258Smlaier				    "(icmp6)\n"));
4184126258Smlaier				return (PF_DROP);
4185126258Smlaier			}
4186126258Smlaier
4187126258Smlaier			key.af = pd2.af;
4188126258Smlaier			key.proto = IPPROTO_ICMPV6;
4189126258Smlaier			PF_ACPY(&key.addr[0], pd2.dst, pd2.af);
4190126258Smlaier			key.port[0] = iih.icmp6_id;
4191126258Smlaier			PF_ACPY(&key.addr[1], pd2.src, pd2.af);
4192126258Smlaier			key.port[1] = iih.icmp6_id;
4193126258Smlaier
4194126258Smlaier			STATE_LOOKUP();
4195126258Smlaier
4196126258Smlaier			if (STATE_TRANSLATE(*state)) {
4197126258Smlaier				if (direction == PF_IN) {
4198126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
4199126258Smlaier					    daddr, &(*state)->lan.addr,
4200126258Smlaier					    (*state)->lan.port, NULL,
4201126258Smlaier					    pd2.ip_sum, icmpsum,
4202126258Smlaier					    pd->ip_sum, 0, AF_INET6);
4203126258Smlaier				} else {
4204126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
4205126258Smlaier					    saddr, &(*state)->gwy.addr,
4206126258Smlaier					    (*state)->gwy.port, NULL,
4207126258Smlaier					    pd2.ip_sum, icmpsum,
4208126258Smlaier					    pd->ip_sum, 0, AF_INET6);
4209126258Smlaier				}
4210126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
4211126258Smlaier				    pd->hdr.icmp6);
4212126258Smlaier				m_copyback(m, ipoff2, sizeof(h2_6), &h2_6);
4213126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
4214126258Smlaier				    &iih);
4215126258Smlaier			}
4216126258Smlaier
4217126258Smlaier			return (PF_PASS);
4218126258Smlaier			break;
4219126258Smlaier		}
4220126258Smlaier#endif /* INET6 */
4221126258Smlaier		default: {
4222126258Smlaier			struct pf_tree_node	key;
4223126258Smlaier
4224126258Smlaier			key.af = pd2.af;
4225126258Smlaier			key.proto = pd2.proto;
4226126258Smlaier			PF_ACPY(&key.addr[0], pd2.dst, pd2.af);
4227126258Smlaier			key.port[0] = 0;
4228126258Smlaier			PF_ACPY(&key.addr[1], pd2.src, pd2.af);
4229126258Smlaier			key.port[1] = 0;
4230126258Smlaier
4231126258Smlaier			STATE_LOOKUP();
4232126258Smlaier
4233126258Smlaier			if (STATE_TRANSLATE(*state)) {
4234126258Smlaier				if (direction == PF_IN) {
4235126258Smlaier					pf_change_icmp(pd2.src, NULL,
4236126258Smlaier					    daddr, &(*state)->lan.addr,
4237126258Smlaier					    0, NULL,
4238126258Smlaier					    pd2.ip_sum, icmpsum,
4239126258Smlaier					    pd->ip_sum, 0, pd2.af);
4240126258Smlaier				} else {
4241126258Smlaier					pf_change_icmp(pd2.dst, NULL,
4242126258Smlaier					    saddr, &(*state)->gwy.addr,
4243126258Smlaier					    0, NULL,
4244126258Smlaier					    pd2.ip_sum, icmpsum,
4245126258Smlaier					    pd->ip_sum, 0, pd2.af);
4246126258Smlaier				}
4247126258Smlaier				switch (pd2.af) {
4248126258Smlaier#ifdef INET
4249126258Smlaier				case AF_INET:
4250126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
4251126258Smlaier					    pd->hdr.icmp);
4252126258Smlaier					m_copyback(m, ipoff2, sizeof(h2), &h2);
4253126258Smlaier					break;
4254126258Smlaier#endif /* INET */
4255126258Smlaier#ifdef INET6
4256126258Smlaier				case AF_INET6:
4257126258Smlaier					m_copyback(m, off,
4258126258Smlaier					    sizeof(struct icmp6_hdr),
4259126258Smlaier					    pd->hdr.icmp6);
4260126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
4261126258Smlaier					    &h2_6);
4262126258Smlaier					break;
4263126258Smlaier#endif /* INET6 */
4264126258Smlaier				}
4265126258Smlaier			}
4266126258Smlaier
4267126258Smlaier			return (PF_PASS);
4268126258Smlaier			break;
4269126258Smlaier		}
4270126258Smlaier		}
4271126258Smlaier	}
4272126258Smlaier}
4273126258Smlaier
4274126258Smlaierint
4275126258Smlaierpf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp,
4276126258Smlaier    struct pf_pdesc *pd)
4277126258Smlaier{
4278126258Smlaier	struct pf_state_peer	*src, *dst;
4279126258Smlaier	struct pf_tree_node	 key;
4280126258Smlaier	int			dirndx;
4281126258Smlaier
4282126258Smlaier	key.af = pd->af;
4283126258Smlaier	key.proto = pd->proto;
4284126258Smlaier	PF_ACPY(&key.addr[0], pd->src, key.af);
4285126258Smlaier	PF_ACPY(&key.addr[1], pd->dst, key.af);
4286126258Smlaier	key.port[0] = 0;
4287126258Smlaier	key.port[1] = 0;
4288126258Smlaier
4289126258Smlaier	STATE_LOOKUP();
4290126258Smlaier
4291126258Smlaier	if (direction == (*state)->direction) {
4292126258Smlaier		src = &(*state)->src;
4293126258Smlaier		dst = &(*state)->dst;
4294126258Smlaier		dirndx = 0;
4295126258Smlaier	} else {
4296126258Smlaier		src = &(*state)->dst;
4297126258Smlaier		dst = &(*state)->src;
4298126258Smlaier		dirndx = 1;
4299126258Smlaier	}
4300126258Smlaier
4301126258Smlaier	(*state)->packets[dirndx]++;
4302126258Smlaier	(*state)->bytes[dirndx] += pd->tot_len;
4303126258Smlaier
4304126258Smlaier	/* update states */
4305126258Smlaier	if (src->state < PFOTHERS_SINGLE)
4306126258Smlaier		src->state = PFOTHERS_SINGLE;
4307126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
4308126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
4309126258Smlaier
4310126258Smlaier	/* update expire time */
4311126258Smlaier	(*state)->expire = time.tv_sec;
4312126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
4313126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
4314126258Smlaier	else
4315126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
4316126258Smlaier
4317126258Smlaier	/* translate source/destination address, if necessary */
4318126258Smlaier	if (STATE_TRANSLATE(*state)) {
4319126258Smlaier		if (direction == PF_OUT)
4320126258Smlaier			switch (pd->af) {
4321126258Smlaier#ifdef INET
4322126258Smlaier			case AF_INET:
4323126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
4324126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
4325126258Smlaier				    0);
4326126258Smlaier				break;
4327126258Smlaier#endif /* INET */
4328126258Smlaier#ifdef INET6
4329126258Smlaier			case AF_INET6:
4330126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
4331126258Smlaier				break;
4332126258Smlaier#endif /* INET6 */
4333126258Smlaier			}
4334126258Smlaier		else
4335126258Smlaier			switch (pd->af) {
4336126258Smlaier#ifdef INET
4337126258Smlaier			case AF_INET:
4338126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
4339126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
4340126258Smlaier				    0);
4341126258Smlaier				break;
4342126258Smlaier#endif /* INET */
4343126258Smlaier#ifdef INET6
4344126258Smlaier			case AF_INET6:
4345126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
4346126258Smlaier				break;
4347126258Smlaier#endif /* INET6 */
4348126258Smlaier			}
4349126258Smlaier	}
4350126258Smlaier
4351126258Smlaier	(*state)->rule.ptr->packets++;
4352126258Smlaier	(*state)->rule.ptr->bytes += pd->tot_len;
4353126258Smlaier	if ((*state)->nat_rule.ptr != NULL) {
4354126258Smlaier		(*state)->nat_rule.ptr->packets++;
4355126258Smlaier		(*state)->nat_rule.ptr->bytes += pd->tot_len;
4356126258Smlaier	}
4357126258Smlaier	if ((*state)->anchor.ptr != NULL) {
4358126258Smlaier		(*state)->anchor.ptr->packets++;
4359126258Smlaier		(*state)->anchor.ptr->bytes += pd->tot_len;
4360126258Smlaier	}
4361126258Smlaier	return (PF_PASS);
4362126258Smlaier}
4363126258Smlaier
4364126258Smlaier/*
4365126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
4366126258Smlaier * h must be at "ipoff" on the mbuf chain.
4367126258Smlaier */
4368126258Smlaiervoid *
4369126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
4370126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
4371126258Smlaier{
4372126258Smlaier	switch (af) {
4373126258Smlaier#ifdef INET
4374126258Smlaier	case AF_INET: {
4375126258Smlaier		struct ip	*h = mtod(m, struct ip *);
4376126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
4377126258Smlaier
4378126258Smlaier		if (fragoff) {
4379126258Smlaier			if (fragoff >= len)
4380126258Smlaier				ACTION_SET(actionp, PF_PASS);
4381126258Smlaier			else {
4382126258Smlaier				ACTION_SET(actionp, PF_DROP);
4383126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
4384126258Smlaier			}
4385126258Smlaier			return (NULL);
4386126258Smlaier		}
4387126258Smlaier		if (m->m_pkthdr.len < off + len || ntohs(h->ip_len) < off + len) {
4388126258Smlaier			ACTION_SET(actionp, PF_DROP);
4389126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
4390126258Smlaier			return (NULL);
4391126258Smlaier		}
4392126258Smlaier		break;
4393126258Smlaier	}
4394126258Smlaier#endif /* INET */
4395126258Smlaier#ifdef INET6
4396126258Smlaier	case AF_INET6: {
4397126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
4398126258Smlaier
4399126258Smlaier		if (m->m_pkthdr.len < off + len ||
4400126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
4401126258Smlaier		    (unsigned)(off + len)) {
4402126258Smlaier			ACTION_SET(actionp, PF_DROP);
4403126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
4404126258Smlaier			return (NULL);
4405126258Smlaier		}
4406126258Smlaier		break;
4407126258Smlaier	}
4408126258Smlaier#endif /* INET6 */
4409126258Smlaier	}
4410126258Smlaier	m_copydata(m, off, len, p);
4411126258Smlaier	return (p);
4412126258Smlaier}
4413126258Smlaier
4414126258Smlaierint
4415126258Smlaierpf_routable(struct pf_addr *addr, sa_family_t af)
4416126258Smlaier{
4417126258Smlaier	struct sockaddr_in	*dst;
4418126258Smlaier	struct route		 ro;
4419126258Smlaier	int			 ret = 0;
4420126258Smlaier
4421126258Smlaier	bzero(&ro, sizeof(ro));
4422126258Smlaier	dst = satosin(&ro.ro_dst);
4423126258Smlaier	dst->sin_family = af;
4424126258Smlaier	dst->sin_len = sizeof(*dst);
4425126258Smlaier	dst->sin_addr = addr->v4;
4426126258Smlaier	rtalloc_noclone(&ro, NO_CLONING);
4427126258Smlaier
4428126258Smlaier	if (ro.ro_rt != NULL) {
4429126258Smlaier		ret = 1;
4430126258Smlaier		RTFREE(ro.ro_rt);
4431126258Smlaier	}
4432126258Smlaier
4433126258Smlaier	return (ret);
4434126258Smlaier}
4435126258Smlaier
4436126258Smlaier#ifdef INET
4437126258Smlaiervoid
4438126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
4439126258Smlaier    struct pf_state *s)
4440126258Smlaier{
4441126258Smlaier	struct mbuf		*m0, *m1;
4442126258Smlaier	struct route		 iproute;
4443126258Smlaier	struct route		*ro;
4444126258Smlaier	struct sockaddr_in	*dst;
4445126258Smlaier	struct ip		*ip;
4446126258Smlaier	struct ifnet		*ifp = NULL;
4447126258Smlaier	struct m_tag		*mtag;
4448126258Smlaier	struct pf_addr		 naddr;
4449126258Smlaier	int			 error = 0;
4450126258Smlaier
4451126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
4452126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
4453126258Smlaier		panic("pf_route: invalid parameters");
4454126258Smlaier
4455126258Smlaier	if (r->rt == PF_DUPTO) {
4456126258Smlaier		m0 = *m;
4457126258Smlaier		mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
4458126258Smlaier		if (mtag == NULL) {
4459126258Smlaier			mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
4460126258Smlaier			if (mtag == NULL)
4461126258Smlaier				goto bad;
4462126258Smlaier			m_tag_prepend(m0, mtag);
4463126258Smlaier		}
4464126258Smlaier		m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
4465126258Smlaier		if (m0 == NULL)
4466126258Smlaier			return;
4467126258Smlaier	} else {
4468126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
4469126258Smlaier			return;
4470126258Smlaier		m0 = *m;
4471126258Smlaier	}
4472126258Smlaier
4473126258Smlaier	if (m0->m_len < sizeof(struct ip))
4474126258Smlaier		panic("pf_route: m0->m_len < sizeof(struct ip)");
4475126258Smlaier	ip = mtod(m0, struct ip *);
4476126258Smlaier
4477126258Smlaier	ro = &iproute;
4478126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
4479126258Smlaier	dst = satosin(&ro->ro_dst);
4480126258Smlaier	dst->sin_family = AF_INET;
4481126258Smlaier	dst->sin_len = sizeof(*dst);
4482126258Smlaier	dst->sin_addr = ip->ip_dst;
4483126258Smlaier
4484126258Smlaier	if (r->rt == PF_FASTROUTE) {
4485126258Smlaier		rtalloc(ro);
4486126258Smlaier		if (ro->ro_rt == 0) {
4487126258Smlaier			ipstat.ips_noroute++;
4488126258Smlaier			goto bad;
4489126258Smlaier		}
4490126258Smlaier
4491126258Smlaier		ifp = ro->ro_rt->rt_ifp;
4492126258Smlaier		ro->ro_rt->rt_use++;
4493126258Smlaier
4494126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
4495126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
4496126258Smlaier	} else {
4497126258Smlaier		if (TAILQ_EMPTY(&r->rpool.list))
4498126258Smlaier			panic("pf_route: TAILQ_EMPTY(&r->rpool.list)");
4499126258Smlaier		if (s == NULL) {
4500126258Smlaier			pf_map_addr(AF_INET, &r->rpool,
4501126258Smlaier			    (struct pf_addr *)&ip->ip_src,
4502126258Smlaier			    &naddr, NULL);
4503126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
4504126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
4505126258Smlaier			ifp = r->rpool.cur->ifp;
4506126258Smlaier		} else {
4507126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
4508126258Smlaier				dst->sin_addr.s_addr =
4509126258Smlaier				    s->rt_addr.v4.s_addr;
4510126258Smlaier			ifp = s->rt_ifp;
4511126258Smlaier		}
4512126258Smlaier	}
4513126258Smlaier
4514126258Smlaier	if (ifp == NULL)
4515126258Smlaier		goto bad;
4516126258Smlaier
4517126258Smlaier	mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
4518126258Smlaier	if (mtag == NULL) {
4519126258Smlaier		struct m_tag *mtag;
4520126258Smlaier
4521126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
4522126258Smlaier		if (mtag == NULL)
4523126258Smlaier			goto bad;
4524126258Smlaier		m_tag_prepend(m0, mtag);
4525126258Smlaier	}
4526126258Smlaier
4527126258Smlaier	if (oifp != ifp && mtag == NULL) {
4528126258Smlaier		if (pf_test(PF_OUT, ifp, &m0) != PF_PASS)
4529126258Smlaier			goto bad;
4530126258Smlaier		else if (m0 == NULL)
4531126258Smlaier			goto done;
4532126258Smlaier		if (m0->m_len < sizeof(struct ip))
4533126258Smlaier			panic("pf_route: m0->m_len < sizeof(struct ip)");
4534126258Smlaier		ip = mtod(m0, struct ip *);
4535126258Smlaier	}
4536126258Smlaier
4537126258Smlaier	/* Copied from ip_output. */
4538126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
4539126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
4540126258Smlaier		    ifp->if_bridge == NULL) {
4541126258Smlaier			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
4542126258Smlaier			ipstat.ips_outhwcsum++;
4543126258Smlaier		} else {
4544126258Smlaier			ip->ip_sum = 0;
4545126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
4546126258Smlaier		}
4547126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
4548126258Smlaier		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
4549126258Smlaier			tcpstat.tcps_outhwcsum++;
4550126258Smlaier		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
4551126258Smlaier			udpstat.udps_outhwcsum++;
4552126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
4553126258Smlaier		goto done;
4554126258Smlaier	}
4555126258Smlaier
4556126258Smlaier	/*
4557126258Smlaier	 * Too large for interface; fragment if possible.
4558126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
4559126258Smlaier	 */
4560126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
4561126258Smlaier		ipstat.ips_cantfrag++;
4562126258Smlaier		if (r->rt != PF_DUPTO) {
4563126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
4564126258Smlaier			    ifp);
4565126258Smlaier			goto done;
4566126258Smlaier		} else
4567126258Smlaier			goto bad;
4568126258Smlaier	}
4569126258Smlaier
4570126258Smlaier	m1 = m0;
4571126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
4572126258Smlaier	if (error == EMSGSIZE)
4573126258Smlaier		goto bad;
4574126258Smlaier
4575126258Smlaier	for (m0 = m1; m0; m0 = m1) {
4576126258Smlaier		m1 = m0->m_nextpkt;
4577126258Smlaier		m0->m_nextpkt = 0;
4578126258Smlaier		if (error == 0)
4579126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
4580126258Smlaier			    NULL);
4581126258Smlaier		else
4582126258Smlaier			m_freem(m0);
4583126258Smlaier	}
4584126258Smlaier
4585126258Smlaier	if (error == 0)
4586126258Smlaier		ipstat.ips_fragmented++;
4587126258Smlaier
4588126258Smlaierdone:
4589126258Smlaier	if (r->rt != PF_DUPTO)
4590126258Smlaier		*m = NULL;
4591126258Smlaier	if (ro == &iproute && ro->ro_rt)
4592126258Smlaier		RTFREE(ro->ro_rt);
4593126258Smlaier	return;
4594126258Smlaier
4595126258Smlaierbad:
4596126258Smlaier	m_freem(m0);
4597126258Smlaier	goto done;
4598126258Smlaier}
4599126258Smlaier#endif /* INET */
4600126258Smlaier
4601126258Smlaier#ifdef INET6
4602126258Smlaiervoid
4603126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
4604126258Smlaier    struct pf_state *s)
4605126258Smlaier{
4606126258Smlaier	struct mbuf		*m0;
4607126258Smlaier	struct m_tag		*mtag;
4608126258Smlaier	struct route_in6	 ip6route;
4609126258Smlaier	struct route_in6	*ro;
4610126258Smlaier	struct sockaddr_in6	*dst;
4611126258Smlaier	struct ip6_hdr		*ip6;
4612126258Smlaier	struct ifnet		*ifp = NULL;
4613126258Smlaier	struct pf_addr		 naddr;
4614126258Smlaier	int			 error = 0;
4615126258Smlaier
4616126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
4617126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
4618126258Smlaier		panic("pf_route6: invalid parameters");
4619126258Smlaier
4620126258Smlaier	if (r->rt == PF_DUPTO) {
4621126258Smlaier		m0 = *m;
4622126258Smlaier		mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
4623126258Smlaier		if (mtag == NULL) {
4624126258Smlaier			mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
4625126258Smlaier			if (mtag == NULL)
4626126258Smlaier				goto bad;
4627126258Smlaier			m_tag_prepend(m0, mtag);
4628126258Smlaier		}
4629126258Smlaier		m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
4630126258Smlaier		if (m0 == NULL)
4631126258Smlaier			return;
4632126258Smlaier	} else {
4633126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
4634126258Smlaier			return;
4635126258Smlaier		m0 = *m;
4636126258Smlaier	}
4637126258Smlaier
4638126258Smlaier	if (m0->m_len < sizeof(struct ip6_hdr))
4639126258Smlaier		panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
4640126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
4641126258Smlaier
4642126258Smlaier	ro = &ip6route;
4643126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
4644126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
4645126258Smlaier	dst->sin6_family = AF_INET6;
4646126258Smlaier	dst->sin6_len = sizeof(*dst);
4647126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
4648126258Smlaier
4649126258Smlaier	/* Cheat. */
4650126258Smlaier	if (r->rt == PF_FASTROUTE) {
4651126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
4652126258Smlaier		if (mtag == NULL)
4653126258Smlaier			goto bad;
4654126258Smlaier		m_tag_prepend(m0, mtag);
4655126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
4656126258Smlaier		return;
4657126258Smlaier	}
4658126258Smlaier
4659126258Smlaier	if (TAILQ_EMPTY(&r->rpool.list))
4660126258Smlaier		panic("pf_route6: TAILQ_EMPTY(&r->rpool.list)");
4661126258Smlaier	if (s == NULL) {
4662126258Smlaier		pf_map_addr(AF_INET6, &r->rpool,
4663126258Smlaier		    (struct pf_addr *)&ip6->ip6_src, &naddr, NULL);
4664126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
4665126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
4666126258Smlaier			    &naddr, AF_INET6);
4667126258Smlaier		ifp = r->rpool.cur->ifp;
4668126258Smlaier	} else {
4669126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
4670126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
4671126258Smlaier			    &s->rt_addr, AF_INET6);
4672126258Smlaier		ifp = s->rt_ifp;
4673126258Smlaier	}
4674126258Smlaier
4675126258Smlaier	if (ifp == NULL)
4676126258Smlaier		goto bad;
4677126258Smlaier
4678126258Smlaier	if (oifp != ifp) {
4679126258Smlaier		mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
4680126258Smlaier		if (mtag == NULL) {
4681126258Smlaier			mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
4682126258Smlaier			if (mtag == NULL)
4683126258Smlaier				goto bad;
4684126258Smlaier			m_tag_prepend(m0, mtag);
4685126258Smlaier			if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
4686126258Smlaier				goto bad;
4687126258Smlaier			else if (m0 == NULL)
4688126258Smlaier				goto done;
4689126258Smlaier		}
4690126258Smlaier	}
4691126258Smlaier
4692126258Smlaier	/*
4693126258Smlaier	 * If the packet is too large for the outgoing interface,
4694126258Smlaier	 * send back an icmp6 error.
4695126258Smlaier	 */
4696126258Smlaier	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
4697126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
4698126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
4699126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
4700126258Smlaier	} else {
4701126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
4702126258Smlaier		if (r->rt != PF_DUPTO)
4703126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
4704126258Smlaier		else
4705126258Smlaier			goto bad;
4706126258Smlaier	}
4707126258Smlaier
4708126258Smlaierdone:
4709126258Smlaier	if (r->rt != PF_DUPTO)
4710126258Smlaier		*m = NULL;
4711126258Smlaier	return;
4712126258Smlaier
4713126258Smlaierbad:
4714126258Smlaier	m_freem(m0);
4715126258Smlaier	goto done;
4716126258Smlaier}
4717126258Smlaier#endif /* INET6 */
4718126258Smlaier
4719126258Smlaier
4720126258Smlaier/*
4721126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
4722126258Smlaier *   off is the offset where the protocol header starts
4723126258Smlaier *   len is the total length of protocol header plus payload
4724126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
4725126258Smlaier */
4726126258Smlaierint
4727126258Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
4728126258Smlaier{
4729126258Smlaier	u_int16_t flag_ok, flag_bad;
4730126258Smlaier	u_int16_t sum;
4731126258Smlaier
4732126258Smlaier	switch (p) {
4733126258Smlaier	case IPPROTO_TCP:
4734126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
4735126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
4736126258Smlaier		break;
4737126258Smlaier	case IPPROTO_UDP:
4738126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
4739126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
4740126258Smlaier		break;
4741126258Smlaier	case IPPROTO_ICMP:
4742126258Smlaier#ifdef INET6
4743126258Smlaier	case IPPROTO_ICMPV6:
4744126258Smlaier#endif /* INET6 */
4745126258Smlaier		flag_ok = flag_bad = 0;
4746126258Smlaier		break;
4747126258Smlaier	default:
4748126258Smlaier		return (1);
4749126258Smlaier	}
4750126258Smlaier	if (m->m_pkthdr.csum & flag_ok)
4751126258Smlaier		return (0);
4752126258Smlaier	if (m->m_pkthdr.csum & flag_bad)
4753126258Smlaier		return (1);
4754126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
4755126258Smlaier		return (1);
4756126258Smlaier	if (m->m_pkthdr.len < off + len)
4757126258Smlaier		return (1);
4758126258Smlaier		switch (af) {
4759126258Smlaier	case AF_INET:
4760126258Smlaier		if (p == IPPROTO_ICMP) {
4761126258Smlaier			if (m->m_len < off)
4762126258Smlaier				return (1);
4763126258Smlaier			m->m_data += off;
4764126258Smlaier			m->m_len -= off;
4765126258Smlaier			sum = in_cksum(m, len);
4766126258Smlaier			m->m_data -= off;
4767126258Smlaier			m->m_len += off;
4768126258Smlaier		} else {
4769126258Smlaier			if (m->m_len < sizeof(struct ip))
4770126258Smlaier				return (1);
4771126258Smlaier			sum = in4_cksum(m, p, off, len);
4772126258Smlaier		}
4773126258Smlaier		break;
4774126258Smlaier#ifdef INET6
4775126258Smlaier	case AF_INET6:
4776126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
4777126258Smlaier			return (1);
4778126258Smlaier		sum = in6_cksum(m, p, off, len);
4779126258Smlaier		break;
4780126258Smlaier#endif /* INET6 */
4781126258Smlaier	default:
4782126258Smlaier		return (1);
4783126258Smlaier	}
4784126258Smlaier	if (sum) {
4785126258Smlaier		m->m_pkthdr.csum |= flag_bad;
4786126258Smlaier		switch (p) {
4787126258Smlaier		case IPPROTO_TCP:
4788126258Smlaier			tcpstat.tcps_rcvbadsum++;
4789126258Smlaier			break;
4790126258Smlaier		case IPPROTO_UDP:
4791126258Smlaier			udpstat.udps_badsum++;
4792126258Smlaier			break;
4793126258Smlaier		case IPPROTO_ICMP:
4794126258Smlaier			icmpstat.icps_checksum++;
4795126258Smlaier			break;
4796126258Smlaier#ifdef INET6
4797126258Smlaier		case IPPROTO_ICMPV6:
4798126258Smlaier			icmp6stat.icp6s_checksum++;
4799126258Smlaier			break;
4800126258Smlaier#endif /* INET6 */
4801126258Smlaier		}
4802126258Smlaier		return (1);
4803126258Smlaier	}
4804126258Smlaier	m->m_pkthdr.csum |= flag_ok;
4805126258Smlaier	return (0);
4806126258Smlaier}
4807126258Smlaier
4808126258Smlaier#ifdef INET
4809126258Smlaierint
4810126258Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
4811126258Smlaier{
4812126258Smlaier	u_short		   action, reason = 0, log = 0;
4813126258Smlaier	struct mbuf	  *m = *m0;
4814126258Smlaier	struct ip	  *h;
4815126258Smlaier	struct pf_rule	  *a = NULL, *r = &pf_default_rule, *tr;
4816126258Smlaier	struct pf_state	  *s = NULL;
4817126258Smlaier	struct pf_ruleset *ruleset = NULL;
4818126258Smlaier	struct pf_pdesc	   pd;
4819126258Smlaier	int		   off;
4820126258Smlaier	int		   pqid = 0;
4821126258Smlaier
4822126258Smlaier	if (!pf_status.running ||
4823126258Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
4824126258Smlaier		return (PF_PASS);
4825126258Smlaier
4826126258Smlaier#ifdef DIAGNOSTIC
4827126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
4828126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
4829126258Smlaier#endif
4830126258Smlaier
4831126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
4832126258Smlaier		action = PF_DROP;
4833126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
4834126258Smlaier		log = 1;
4835126258Smlaier		goto done;
4836126258Smlaier	}
4837126258Smlaier
4838126258Smlaier	/* We do IP header normalization and packet reassembly here */
4839126258Smlaier	if (pf_normalize_ip(m0, dir, ifp, &reason) != PF_PASS) {
4840126258Smlaier		action = PF_DROP;
4841126258Smlaier		goto done;
4842126258Smlaier	}
4843126258Smlaier	m = *m0;
4844126258Smlaier	h = mtod(m, struct ip *);
4845126258Smlaier
4846126258Smlaier	off = h->ip_hl << 2;
4847126258Smlaier	if (off < (int)sizeof(*h)) {
4848126258Smlaier		action = PF_DROP;
4849126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
4850126258Smlaier		log = 1;
4851126258Smlaier		goto done;
4852126258Smlaier	}
4853126258Smlaier
4854126258Smlaier	memset(&pd, 0, sizeof(pd));
4855126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
4856126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
4857126258Smlaier	pd.ip_sum = &h->ip_sum;
4858126258Smlaier	pd.proto = h->ip_p;
4859126258Smlaier	pd.af = AF_INET;
4860126258Smlaier	pd.tos = h->ip_tos;
4861126258Smlaier	pd.tot_len = ntohs(h->ip_len);
4862126258Smlaier
4863126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
4864126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
4865126258Smlaier		action = pf_test_fragment(&r, dir, ifp, m, h,
4866126258Smlaier		    &pd, &a, &ruleset);
4867126258Smlaier		goto done;
4868126258Smlaier	}
4869126258Smlaier
4870126258Smlaier	switch (h->ip_p) {
4871126258Smlaier
4872126258Smlaier	case IPPROTO_TCP: {
4873126258Smlaier		struct tcphdr	th;
4874126258Smlaier
4875126258Smlaier		pd.hdr.tcp = &th;
4876126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
4877126258Smlaier		    &action, &reason, AF_INET)) {
4878126258Smlaier			log = action != PF_PASS;
4879126258Smlaier			goto done;
4880126258Smlaier		}
4881126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
4882126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
4883126258Smlaier			action = PF_DROP;
4884126258Smlaier			goto done;
4885126258Smlaier		}
4886126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
4887126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
4888126258Smlaier			pqid = 1;
4889126258Smlaier		action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd);
4890126258Smlaier		if (action == PF_DROP)
4891126258Smlaier			break;
4892126258Smlaier		action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd,
4893126258Smlaier		    &reason);
4894126258Smlaier		if (action == PF_PASS) {
4895126258Smlaier			r = s->rule.ptr;
4896126258Smlaier			log = s->log;
4897126258Smlaier		} else if (s == NULL)
4898126258Smlaier			action = pf_test_tcp(&r, &s, dir, ifp,
4899126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
4900126258Smlaier		break;
4901126258Smlaier	}
4902126258Smlaier
4903126258Smlaier	case IPPROTO_UDP: {
4904126258Smlaier		struct udphdr	uh;
4905126258Smlaier
4906126258Smlaier		pd.hdr.udp = &uh;
4907126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
4908126258Smlaier		    &action, &reason, AF_INET)) {
4909126258Smlaier			log = action != PF_PASS;
4910126258Smlaier			goto done;
4911126258Smlaier		}
4912126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
4913126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
4914126258Smlaier			action = PF_DROP;
4915126258Smlaier			goto done;
4916126258Smlaier		}
4917126258Smlaier		action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd);
4918126258Smlaier		if (action == PF_PASS) {
4919126258Smlaier			r = s->rule.ptr;
4920126258Smlaier			a = s->anchor.ptr;
4921126258Smlaier			log = s->log;
4922126258Smlaier		} else if (s == NULL)
4923126258Smlaier			action = pf_test_udp(&r, &s, dir, ifp,
4924126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
4925126258Smlaier		break;
4926126258Smlaier	}
4927126258Smlaier
4928126258Smlaier	case IPPROTO_ICMP: {
4929126258Smlaier		struct icmp	ih;
4930126258Smlaier
4931126258Smlaier		pd.hdr.icmp = &ih;
4932126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
4933126258Smlaier		    &action, &reason, AF_INET)) {
4934126258Smlaier			log = action != PF_PASS;
4935126258Smlaier			goto done;
4936126258Smlaier		}
4937126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
4938126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
4939126258Smlaier			action = PF_DROP;
4940126258Smlaier			goto done;
4941126258Smlaier		}
4942126258Smlaier		action = pf_test_state_icmp(&s, dir, ifp, m, 0, off, h, &pd);
4943126258Smlaier		if (action == PF_PASS) {
4944126258Smlaier			r = s->rule.ptr;
4945126258Smlaier			r->packets++;
4946126258Smlaier			r->bytes += ntohs(h->ip_len);
4947126258Smlaier			a = s->anchor.ptr;
4948126258Smlaier			if (a != NULL) {
4949126258Smlaier				a->packets++;
4950126258Smlaier				a->bytes += ntohs(h->ip_len);
4951126258Smlaier			}
4952126258Smlaier			log = s->log;
4953126258Smlaier		} else if (s == NULL)
4954126258Smlaier			action = pf_test_icmp(&r, &s, dir, ifp,
4955126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
4956126258Smlaier		break;
4957126258Smlaier	}
4958126258Smlaier
4959126258Smlaier	default:
4960126258Smlaier		action = pf_test_state_other(&s, dir, ifp, &pd);
4961126258Smlaier		if (action == PF_PASS) {
4962126258Smlaier			r = s->rule.ptr;
4963126258Smlaier			a = s->anchor.ptr;
4964126258Smlaier			log = s->log;
4965126258Smlaier		} else if (s == NULL)
4966126258Smlaier			action = pf_test_other(&r, &s, dir, ifp, m, off, h,
4967126258Smlaier			    &pd, &a, &ruleset);
4968126258Smlaier		break;
4969126258Smlaier	}
4970126258Smlaier
4971126258Smlaier	if (ifp == status_ifp) {
4972126258Smlaier		pf_status.bcounters[0][dir == PF_OUT] += pd.tot_len;
4973126258Smlaier		pf_status.pcounters[0][dir == PF_OUT][action != PF_PASS]++;
4974126258Smlaier	}
4975126258Smlaier
4976126258Smlaierdone:
4977126258Smlaier	tr = r;
4978126258Smlaier	if (r == &pf_default_rule && s != NULL && s->nat_rule.ptr != NULL)
4979126258Smlaier		tr = s->nat_rule.ptr;
4980126258Smlaier	if (tr->src.addr.type == PF_ADDR_TABLE)
4981126258Smlaier		pfr_update_stats(tr->src.addr.p.tbl,
4982126258Smlaier		    (s == NULL || s->direction == dir) ? pd.src : pd.dst, pd.af,
4983126258Smlaier		    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
4984126258Smlaier		    tr->src.not);
4985126258Smlaier	if (tr->dst.addr.type == PF_ADDR_TABLE)
4986126258Smlaier		pfr_update_stats(tr->dst.addr.p.tbl,
4987126258Smlaier		    (s == NULL || s->direction == dir) ? pd.dst : pd.src, pd.af,
4988126258Smlaier		    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
4989126258Smlaier		    tr->dst.not);
4990126258Smlaier
4991126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
4992126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
4993126258Smlaier		action = PF_DROP;
4994126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
4995126258Smlaier		log = 1;
4996126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
4997126258Smlaier		    ("pf: dropping packet with ip options\n"));
4998126258Smlaier	}
4999126258Smlaier
5000126258Smlaier#ifdef ALTQ
5001126258Smlaier	if (action == PF_PASS && r->qid) {
5002126258Smlaier		struct m_tag	*mtag;
5003126258Smlaier		struct altq_tag	*atag;
5004126258Smlaier
5005126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
5006126258Smlaier		if (mtag != NULL) {
5007126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
5008126258Smlaier			if (pqid || pd.tos == IPTOS_LOWDELAY)
5009126258Smlaier				atag->qid = r->pqid;
5010126258Smlaier			else
5011126258Smlaier				atag->qid = r->qid;
5012126258Smlaier			/* add hints for ecn */
5013126258Smlaier			atag->af = AF_INET;
5014126258Smlaier			atag->hdr = h;
5015126258Smlaier			m_tag_prepend(m, mtag);
5016126258Smlaier		}
5017126258Smlaier	}
5018126258Smlaier#endif
5019126258Smlaier
5020126258Smlaier	if (log)
5021126258Smlaier		PFLOG_PACKET(ifp, h, m, AF_INET, dir, reason, r, a, ruleset);
5022126258Smlaier
5023126258Smlaier	if (action == PF_SYNPROXY_DROP) {
5024126258Smlaier		m_freem(*m0);
5025126258Smlaier		*m0 = NULL;
5026126258Smlaier		action = PF_PASS;
5027126258Smlaier	} else if (r->rt)
5028126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
5029126258Smlaier		pf_route(m0, r, dir, ifp, s);
5030126258Smlaier
5031126258Smlaier	return (action);
5032126258Smlaier}
5033126258Smlaier#endif /* INET */
5034126258Smlaier
5035126258Smlaier#ifdef INET6
5036126258Smlaierint
5037126258Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
5038126258Smlaier{
5039126258Smlaier	u_short		   action, reason = 0, log = 0;
5040126258Smlaier	struct mbuf	  *m = *m0;
5041126258Smlaier	struct ip6_hdr	  *h;
5042126258Smlaier	struct pf_rule	  *a = NULL, *r = &pf_default_rule, *tr;
5043126258Smlaier	struct pf_state	  *s = NULL;
5044126258Smlaier	struct pf_ruleset *ruleset = NULL;
5045126258Smlaier	struct pf_pdesc    pd;
5046126258Smlaier	int		   off, terminal = 0;
5047126258Smlaier
5048126258Smlaier	if (!pf_status.running ||
5049126258Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
5050126258Smlaier		return (PF_PASS);
5051126258Smlaier
5052126258Smlaier#ifdef DIAGNOSTIC
5053126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
5054126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
5055126258Smlaier#endif
5056126258Smlaier
5057126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
5058126258Smlaier		action = PF_DROP;
5059126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
5060126258Smlaier		log = 1;
5061126258Smlaier		goto done;
5062126258Smlaier	}
5063126258Smlaier
5064126258Smlaier	/* We do IP header normalization and packet reassembly here */
5065126258Smlaier	if (pf_normalize_ip6(m0, dir, ifp, &reason) != PF_PASS) {
5066126258Smlaier		action = PF_DROP;
5067126258Smlaier		goto done;
5068126258Smlaier	}
5069126258Smlaier	m = *m0;
5070126258Smlaier	h = mtod(m, struct ip6_hdr *);
5071126258Smlaier
5072126258Smlaier	memset(&pd, 0, sizeof(pd));
5073126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
5074126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
5075126258Smlaier	pd.ip_sum = NULL;
5076126258Smlaier	pd.af = AF_INET6;
5077126258Smlaier	pd.tos = 0;
5078126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
5079126258Smlaier
5080126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
5081126258Smlaier	pd.proto = h->ip6_nxt;
5082126258Smlaier	do {
5083126258Smlaier		switch (pd.proto) {
5084126258Smlaier		case IPPROTO_FRAGMENT:
5085126258Smlaier			action = pf_test_fragment(&r, dir, ifp, m, h,
5086126258Smlaier			    &pd, &a, &ruleset);
5087126258Smlaier			if (action == PF_DROP)
5088126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
5089126258Smlaier			goto done;
5090126258Smlaier		case IPPROTO_AH:
5091126258Smlaier		case IPPROTO_HOPOPTS:
5092126258Smlaier		case IPPROTO_ROUTING:
5093126258Smlaier		case IPPROTO_DSTOPTS: {
5094126258Smlaier			/* get next header and header length */
5095126258Smlaier			struct ip6_ext	opt6;
5096126258Smlaier
5097126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
5098126258Smlaier			    NULL, NULL, pd.af)) {
5099126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5100126258Smlaier				    ("pf: IPv6 short opt\n"));
5101126258Smlaier				action = PF_DROP;
5102126258Smlaier				REASON_SET(&reason, PFRES_SHORT);
5103126258Smlaier				log = 1;
5104126258Smlaier				goto done;
5105126258Smlaier			}
5106126258Smlaier			if (pd.proto == IPPROTO_AH)
5107126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
5108126258Smlaier			else
5109126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
5110126258Smlaier			pd.proto = opt6.ip6e_nxt;
5111126258Smlaier			/* goto the next header */
5112126258Smlaier			break;
5113126258Smlaier		}
5114126258Smlaier		default:
5115126258Smlaier			terminal++;
5116126258Smlaier			break;
5117126258Smlaier		}
5118126258Smlaier	} while (!terminal);
5119126258Smlaier
5120126258Smlaier	switch (pd.proto) {
5121126258Smlaier
5122126258Smlaier	case IPPROTO_TCP: {
5123126258Smlaier		struct tcphdr	th;
5124126258Smlaier
5125126258Smlaier		pd.hdr.tcp = &th;
5126126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
5127126258Smlaier		    &action, &reason, AF_INET6)) {
5128126258Smlaier			log = action != PF_PASS;
5129126258Smlaier			goto done;
5130126258Smlaier		}
5131126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
5132126258Smlaier		    ntohs(h->ip6_plen), IPPROTO_TCP, AF_INET6)) {
5133126258Smlaier			action = PF_DROP;
5134126258Smlaier			goto done;
5135126258Smlaier		}
5136126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
5137126258Smlaier		action = pf_normalize_tcp(dir, ifp, m, 0, off, h, &pd);
5138126258Smlaier		if (action == PF_DROP)
5139126258Smlaier			break;
5140126258Smlaier		action = pf_test_state_tcp(&s, dir, ifp, m, 0, off, h, &pd,
5141126258Smlaier		    &reason);
5142126258Smlaier		if (action == PF_PASS) {
5143126258Smlaier			r = s->rule.ptr;
5144126258Smlaier			log = s->log;
5145126258Smlaier		} else if (s == NULL)
5146126258Smlaier			action = pf_test_tcp(&r, &s, dir, ifp,
5147126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
5148126258Smlaier		break;
5149126258Smlaier	}
5150126258Smlaier
5151126258Smlaier	case IPPROTO_UDP: {
5152126258Smlaier		struct udphdr	uh;
5153126258Smlaier
5154126258Smlaier		pd.hdr.udp = &uh;
5155126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
5156126258Smlaier		    &action, &reason, AF_INET6)) {
5157126258Smlaier			log = action != PF_PASS;
5158126258Smlaier			goto done;
5159126258Smlaier		}
5160126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
5161126258Smlaier		    off, ntohs(h->ip6_plen), IPPROTO_UDP, AF_INET6)) {
5162126258Smlaier			action = PF_DROP;
5163126258Smlaier			goto done;
5164126258Smlaier		}
5165126258Smlaier		action = pf_test_state_udp(&s, dir, ifp, m, 0, off, h, &pd);
5166126258Smlaier		if (action == PF_PASS) {
5167126258Smlaier			r = s->rule.ptr;
5168126258Smlaier			log = s->log;
5169126258Smlaier		} else if (s == NULL)
5170126258Smlaier			action = pf_test_udp(&r, &s, dir, ifp,
5171126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
5172126258Smlaier		break;
5173126258Smlaier	}
5174126258Smlaier
5175126258Smlaier	case IPPROTO_ICMPV6: {
5176126258Smlaier		struct icmp6_hdr	ih;
5177126258Smlaier
5178126258Smlaier		pd.hdr.icmp6 = &ih;
5179126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
5180126258Smlaier		    &action, &reason, AF_INET6)) {
5181126258Smlaier			log = action != PF_PASS;
5182126258Smlaier			goto done;
5183126258Smlaier		}
5184126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
5185126258Smlaier		    ntohs(h->ip6_plen), IPPROTO_ICMPV6, AF_INET6)) {
5186126258Smlaier			action = PF_DROP;
5187126258Smlaier			goto done;
5188126258Smlaier		}
5189126258Smlaier		action = pf_test_state_icmp(&s, dir, ifp,
5190126258Smlaier		    m, 0, off, h, &pd);
5191126258Smlaier		if (action == PF_PASS) {
5192126258Smlaier			r = s->rule.ptr;
5193126258Smlaier			r->packets++;
5194126258Smlaier			r->bytes += h->ip6_plen;
5195126258Smlaier			log = s->log;
5196126258Smlaier		} else if (s == NULL)
5197126258Smlaier			action = pf_test_icmp(&r, &s, dir, ifp,
5198126258Smlaier			    m, 0, off, h, &pd, &a, &ruleset);
5199126258Smlaier		break;
5200126258Smlaier	}
5201126258Smlaier
5202126258Smlaier	default:
5203126258Smlaier		action = pf_test_other(&r, &s, dir, ifp, m, off, h,
5204126258Smlaier		    &pd, &a, &ruleset);
5205126258Smlaier		break;
5206126258Smlaier	}
5207126258Smlaier
5208126258Smlaier	if (ifp == status_ifp) {
5209126258Smlaier		pf_status.bcounters[1][dir == PF_OUT] += pd.tot_len;
5210126258Smlaier		pf_status.pcounters[1][dir == PF_OUT][action != PF_PASS]++;
5211126258Smlaier	}
5212126258Smlaier
5213126258Smlaierdone:
5214126258Smlaier	tr = r;
5215126258Smlaier	if (r == &pf_default_rule && s != NULL && s->nat_rule.ptr != NULL)
5216126258Smlaier		tr = s->nat_rule.ptr;
5217126258Smlaier	if (tr->src.addr.type == PF_ADDR_TABLE)
5218126258Smlaier		pfr_update_stats(tr->src.addr.p.tbl,
5219126258Smlaier		    (s == NULL || s->direction == dir) ? pd.src : pd.dst, pd.af,
5220126258Smlaier		    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
5221126258Smlaier		    tr->src.not);
5222126258Smlaier	if (tr->dst.addr.type == PF_ADDR_TABLE)
5223126258Smlaier		pfr_update_stats(tr->dst.addr.p.tbl,
5224126258Smlaier		    (s == NULL || s->direction == dir) ? pd.dst : pd.src, pd.af,
5225126258Smlaier		    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
5226126258Smlaier		    tr->dst.not);
5227126258Smlaier
5228126258Smlaier	/* XXX handle IPv6 options, if not allowed. not implemented. */
5229126258Smlaier
5230126258Smlaier#ifdef ALTQ
5231126258Smlaier	if (action == PF_PASS && r->qid) {
5232126258Smlaier		struct m_tag	*mtag;
5233126258Smlaier		struct altq_tag	*atag;
5234126258Smlaier
5235126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
5236126258Smlaier		if (mtag != NULL) {
5237126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
5238126258Smlaier			if (pd.tos == IPTOS_LOWDELAY)
5239126258Smlaier				atag->qid = r->pqid;
5240126258Smlaier			else
5241126258Smlaier				atag->qid = r->qid;
5242126258Smlaier			/* add hints for ecn */
5243126258Smlaier			atag->af = AF_INET6;
5244126258Smlaier			atag->hdr = h;
5245126258Smlaier			m_tag_prepend(m, mtag);
5246126258Smlaier		}
5247126258Smlaier	}
5248126258Smlaier#endif
5249126258Smlaier
5250126258Smlaier	if (log)
5251126258Smlaier		PFLOG_PACKET(ifp, h, m, AF_INET6, dir, reason, r, a, ruleset);
5252126258Smlaier
5253126258Smlaier	if (action == PF_SYNPROXY_DROP) {
5254126258Smlaier		m_freem(*m0);
5255126258Smlaier		*m0 = NULL;
5256126258Smlaier		action = PF_PASS;
5257126258Smlaier	} else if (r->rt)
5258126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
5259126258Smlaier		pf_route6(m0, r, dir, ifp, s);
5260126258Smlaier
5261126258Smlaier	return (action);
5262126258Smlaier}
5263126258Smlaier#endif /* INET6 */
5264