pf.c revision 231852
1223637Sbz/* $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $ */ 2126258Smlaier 3126258Smlaier/* 4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier 5223637Sbz * Copyright (c) 2002 - 2008 Henning Brauer 6126258Smlaier * All rights reserved. 7126258Smlaier * 8126258Smlaier * Redistribution and use in source and binary forms, with or without 9126258Smlaier * modification, are permitted provided that the following conditions 10126258Smlaier * are met: 11126258Smlaier * 12126258Smlaier * - Redistributions of source code must retain the above copyright 13126258Smlaier * notice, this list of conditions and the following disclaimer. 14126258Smlaier * - Redistributions in binary form must reproduce the above 15126258Smlaier * copyright notice, this list of conditions and the following 16126258Smlaier * disclaimer in the documentation and/or other materials provided 17126258Smlaier * with the distribution. 18126258Smlaier * 19126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30126258Smlaier * POSSIBILITY OF SUCH DAMAGE. 31126258Smlaier * 32126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects 33126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force 34126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537. 35126258Smlaier * 36126258Smlaier */ 37126258Smlaier 38127145Smlaier#ifdef __FreeBSD__ 39126261Smlaier#include "opt_inet.h" 40126261Smlaier#include "opt_inet6.h" 41171168Smlaier 42171168Smlaier#include <sys/cdefs.h> 43171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf.c 231852 2012-02-17 02:39:58Z bz $"); 44126261Smlaier#endif 45126261Smlaier 46127145Smlaier#ifdef __FreeBSD__ 47126261Smlaier#include "opt_bpf.h" 48126261Smlaier#include "opt_pf.h" 49153110Sru 50229851Sglebius#define NPFSYNC 1 51153110Sru 52223637Sbz#ifdef DEV_PFLOW 53223637Sbz#define NPFLOW DEV_PFLOW 54153110Sru#else 55223637Sbz#define NPFLOW 0 56223637Sbz#endif 57223637Sbz 58223637Sbz#else 59126258Smlaier#include "bpfilter.h" 60126258Smlaier#include "pflog.h" 61126258Smlaier#include "pfsync.h" 62223637Sbz#include "pflow.h" 63126261Smlaier#endif 64126258Smlaier 65126258Smlaier#include <sys/param.h> 66126258Smlaier#include <sys/systm.h> 67126258Smlaier#include <sys/mbuf.h> 68126258Smlaier#include <sys/filio.h> 69126258Smlaier#include <sys/socket.h> 70126258Smlaier#include <sys/socketvar.h> 71126258Smlaier#include <sys/kernel.h> 72126258Smlaier#include <sys/time.h> 73127145Smlaier#ifdef __FreeBSD__ 74223637Sbz#include <sys/random.h> 75126261Smlaier#include <sys/sysctl.h> 76130613Smlaier#include <sys/endian.h> 77223637Sbz#define betoh64 be64toh 78126261Smlaier#else 79126258Smlaier#include <sys/pool.h> 80126261Smlaier#endif 81171168Smlaier#include <sys/proc.h> 82171168Smlaier#ifdef __FreeBSD__ 83171168Smlaier#include <sys/kthread.h> 84171168Smlaier#include <sys/lock.h> 85171168Smlaier#include <sys/sx.h> 86171168Smlaier#else 87171168Smlaier#include <sys/rwlock.h> 88171168Smlaier#endif 89126258Smlaier 90223637Sbz#ifdef __FreeBSD__ 91223637Sbz#include <sys/md5.h> 92223637Sbz#else 93223637Sbz#include <crypto/md5.h> 94223637Sbz#endif 95223637Sbz 96126258Smlaier#include <net/if.h> 97126258Smlaier#include <net/if_types.h> 98126258Smlaier#include <net/bpf.h> 99126258Smlaier#include <net/route.h> 100223637Sbz#ifdef __FreeBSD__ 101223637Sbz#ifdef RADIX_MPATH 102171168Smlaier#include <net/radix_mpath.h> 103171168Smlaier#endif 104223637Sbz#else 105223637Sbz#include <net/radix_mpath.h> 106223637Sbz#endif 107126258Smlaier 108126258Smlaier#include <netinet/in.h> 109126258Smlaier#include <netinet/in_var.h> 110126258Smlaier#include <netinet/in_systm.h> 111126258Smlaier#include <netinet/ip.h> 112126258Smlaier#include <netinet/ip_var.h> 113126258Smlaier#include <netinet/tcp.h> 114126258Smlaier#include <netinet/tcp_seq.h> 115126258Smlaier#include <netinet/udp.h> 116126258Smlaier#include <netinet/ip_icmp.h> 117126258Smlaier#include <netinet/in_pcb.h> 118126258Smlaier#include <netinet/tcp_timer.h> 119126258Smlaier#include <netinet/tcp_var.h> 120126258Smlaier#include <netinet/udp_var.h> 121126258Smlaier#include <netinet/icmp_var.h> 122145836Smlaier#include <netinet/if_ether.h> 123223637Sbz#ifdef __FreeBSD__ 124223637Sbz#include <netinet/ip_fw.h> 125223637Sbz#include <netinet/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */ 126223637Sbz#endif 127126258Smlaier 128127145Smlaier#ifndef __FreeBSD__ 129126258Smlaier#include <dev/rndvar.h> 130126261Smlaier#endif 131126258Smlaier#include <net/pfvar.h> 132126258Smlaier#include <net/if_pflog.h> 133223637Sbz#include <net/if_pflow.h> 134126258Smlaier#include <net/if_pfsync.h> 135126258Smlaier 136126258Smlaier#ifdef INET6 137126258Smlaier#include <netinet/ip6.h> 138126258Smlaier#include <netinet/in_pcb.h> 139126258Smlaier#include <netinet/icmp6.h> 140126258Smlaier#include <netinet6/nd6.h> 141127145Smlaier#ifdef __FreeBSD__ 142126261Smlaier#include <netinet6/ip6_var.h> 143126261Smlaier#include <netinet6/in6_pcb.h> 144126261Smlaier#endif 145126258Smlaier#endif /* INET6 */ 146126258Smlaier 147127145Smlaier#ifdef __FreeBSD__ 148126261Smlaier#include <machine/in_cksum.h> 149126261Smlaier#include <sys/limits.h> 150126261Smlaier#include <sys/ucred.h> 151163606Srwatson#include <security/mac/mac_framework.h> 152126258Smlaier 153126261Smlaierextern int ip_optcopy(struct ip *, struct ip *); 154126261Smlaier#endif 155126261Smlaier 156223637Sbz#ifdef __FreeBSD__ 157223637Sbz#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 158223637Sbz#else 159223637Sbz#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x 160223637Sbz#endif 161126258Smlaier 162126258Smlaier/* 163126258Smlaier * Global variables 164126258Smlaier */ 165126258Smlaier 166223637Sbz/* state tables */ 167223637Sbz#ifdef __FreeBSD__ 168223637SbzVNET_DEFINE(struct pf_state_tree, pf_statetbl); 169223637Sbz 170223637SbzVNET_DEFINE(struct pf_altqqueue, pf_altqs[2]); 171223637SbzVNET_DEFINE(struct pf_palist, pf_pabuf); 172223637SbzVNET_DEFINE(struct pf_altqqueue *, pf_altqs_active); 173223637SbzVNET_DEFINE(struct pf_altqqueue *, pf_altqs_inactive); 174223637SbzVNET_DEFINE(struct pf_status, pf_status); 175223637Sbz 176223637SbzVNET_DEFINE(u_int32_t, ticket_altqs_active); 177223637SbzVNET_DEFINE(u_int32_t, ticket_altqs_inactive); 178223637SbzVNET_DEFINE(int, altqs_inactive_open); 179223637SbzVNET_DEFINE(u_int32_t, ticket_pabuf); 180223637Sbz 181223637SbzVNET_DEFINE(MD5_CTX, pf_tcp_secret_ctx); 182223637Sbz#define V_pf_tcp_secret_ctx VNET(pf_tcp_secret_ctx) 183223637SbzVNET_DEFINE(u_char, pf_tcp_secret[16]); 184223637Sbz#define V_pf_tcp_secret VNET(pf_tcp_secret) 185223637SbzVNET_DEFINE(int, pf_tcp_secret_init); 186223637Sbz#define V_pf_tcp_secret_init VNET(pf_tcp_secret_init) 187223637SbzVNET_DEFINE(int, pf_tcp_iss_off); 188223637Sbz#define V_pf_tcp_iss_off VNET(pf_tcp_iss_off) 189223637Sbz 190223637Sbzstruct pf_anchor_stackframe { 191223637Sbz struct pf_ruleset *rs; 192223637Sbz struct pf_rule *r; 193223637Sbz struct pf_anchor_node *parent; 194223637Sbz struct pf_anchor *child; 195223637Sbz}; 196223637SbzVNET_DEFINE(struct pf_anchor_stackframe, pf_anchor_stack[64]); 197223637Sbz#define V_pf_anchor_stack VNET(pf_anchor_stack) 198223637Sbz 199223637SbzVNET_DEFINE(uma_zone_t, pf_src_tree_pl); 200223637SbzVNET_DEFINE(uma_zone_t, pf_rule_pl); 201223637SbzVNET_DEFINE(uma_zone_t, pf_pooladdr_pl); 202223637SbzVNET_DEFINE(uma_zone_t, pf_state_pl); 203223637SbzVNET_DEFINE(uma_zone_t, pf_state_key_pl); 204223637SbzVNET_DEFINE(uma_zone_t, pf_state_item_pl); 205223637SbzVNET_DEFINE(uma_zone_t, pf_altq_pl); 206223637Sbz#else 207223637Sbzstruct pf_state_tree pf_statetbl; 208223637Sbz 209126258Smlaierstruct pf_altqqueue pf_altqs[2]; 210126258Smlaierstruct pf_palist pf_pabuf; 211126258Smlaierstruct pf_altqqueue *pf_altqs_active; 212126258Smlaierstruct pf_altqqueue *pf_altqs_inactive; 213126258Smlaierstruct pf_status pf_status; 214126258Smlaier 215126258Smlaieru_int32_t ticket_altqs_active; 216126258Smlaieru_int32_t ticket_altqs_inactive; 217130613Smlaierint altqs_inactive_open; 218126258Smlaieru_int32_t ticket_pabuf; 219126258Smlaier 220223637SbzMD5_CTX pf_tcp_secret_ctx; 221223637Sbzu_char pf_tcp_secret[16]; 222223637Sbzint pf_tcp_secret_init; 223223637Sbzint pf_tcp_iss_off; 224223637Sbz 225145836Smlaierstruct pf_anchor_stackframe { 226145836Smlaier struct pf_ruleset *rs; 227145836Smlaier struct pf_rule *r; 228145836Smlaier struct pf_anchor_node *parent; 229145836Smlaier struct pf_anchor *child; 230145836Smlaier} pf_anchor_stack[64]; 231126261Smlaier 232223637Sbzstruct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl; 233223637Sbzstruct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl; 234223637Sbzstruct pool pf_altq_pl; 235126261Smlaier#endif 236126258Smlaier 237145836Smlaiervoid pf_init_threshold(struct pf_threshold *, u_int32_t, 238145836Smlaier u_int32_t); 239145836Smlaiervoid pf_add_threshold(struct pf_threshold *); 240145836Smlaierint pf_check_threshold(struct pf_threshold *); 241145836Smlaier 242126258Smlaiervoid pf_change_ap(struct pf_addr *, u_int16_t *, 243126258Smlaier u_int16_t *, u_int16_t *, struct pf_addr *, 244126258Smlaier u_int16_t, u_int8_t, sa_family_t); 245171168Smlaierint pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, 246171168Smlaier struct tcphdr *, struct pf_state_peer *); 247126258Smlaier#ifdef INET6 248126258Smlaiervoid pf_change_a6(struct pf_addr *, u_int16_t *, 249126258Smlaier struct pf_addr *, u_int8_t); 250126258Smlaier#endif /* INET6 */ 251126258Smlaiervoid pf_change_icmp(struct pf_addr *, u_int16_t *, 252126258Smlaier struct pf_addr *, struct pf_addr *, u_int16_t, 253126258Smlaier u_int16_t *, u_int16_t *, u_int16_t *, 254126258Smlaier u_int16_t *, u_int8_t, sa_family_t); 255162238Scsjp#ifdef __FreeBSD__ 256162238Scsjpvoid pf_send_tcp(struct mbuf *, 257162238Scsjp const struct pf_rule *, sa_family_t, 258162238Scsjp#else 259126258Smlaiervoid pf_send_tcp(const struct pf_rule *, sa_family_t, 260162238Scsjp#endif 261126258Smlaier const struct pf_addr *, const struct pf_addr *, 262126258Smlaier u_int16_t, u_int16_t, u_int32_t, u_int32_t, 263145836Smlaier u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, 264171168Smlaier u_int16_t, struct ether_header *, struct ifnet *); 265223637Sbzstatic void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, 266126258Smlaier sa_family_t, struct pf_rule *); 267223637Sbzvoid pf_detach_state(struct pf_state *); 268223637Sbzvoid pf_state_key_detach(struct pf_state *, int); 269223637Sbzu_int32_t pf_tcp_iss(struct pf_pdesc *); 270223637Sbzint pf_test_rule(struct pf_rule **, struct pf_state **, 271130613Smlaier int, struct pfi_kif *, struct mbuf *, int, 272126258Smlaier void *, struct pf_pdesc *, struct pf_rule **, 273135920Smlaier#ifdef __FreeBSD__ 274145836Smlaier struct pf_ruleset **, struct ifqueue *, 275145836Smlaier struct inpcb *); 276135920Smlaier#else 277145836Smlaier struct pf_ruleset **, struct ifqueue *); 278135920Smlaier#endif 279223637Sbzstatic __inline int pf_create_state(struct pf_rule *, struct pf_rule *, 280223637Sbz struct pf_rule *, struct pf_pdesc *, 281223637Sbz struct pf_src_node *, struct pf_state_key *, 282223637Sbz struct pf_state_key *, struct pf_state_key *, 283223637Sbz struct pf_state_key *, struct mbuf *, int, 284223637Sbz u_int16_t, u_int16_t, int *, struct pfi_kif *, 285223637Sbz struct pf_state **, int, u_int16_t, u_int16_t, 286223637Sbz int); 287126258Smlaierint pf_test_fragment(struct pf_rule **, int, 288130613Smlaier struct pfi_kif *, struct mbuf *, void *, 289126258Smlaier struct pf_pdesc *, struct pf_rule **, 290126258Smlaier struct pf_ruleset **); 291200930Sdelphijint pf_tcp_track_full(struct pf_state_peer *, 292200930Sdelphij struct pf_state_peer *, struct pf_state **, 293200930Sdelphij struct pfi_kif *, struct mbuf *, int, 294200930Sdelphij struct pf_pdesc *, u_short *, int *); 295223637Sbzint pf_tcp_track_sloppy(struct pf_state_peer *, 296200930Sdelphij struct pf_state_peer *, struct pf_state **, 297200930Sdelphij struct pf_pdesc *, u_short *); 298126258Smlaierint pf_test_state_tcp(struct pf_state **, int, 299130613Smlaier struct pfi_kif *, struct mbuf *, int, 300126258Smlaier void *, struct pf_pdesc *, u_short *); 301126258Smlaierint pf_test_state_udp(struct pf_state **, int, 302130613Smlaier struct pfi_kif *, struct mbuf *, int, 303126258Smlaier void *, struct pf_pdesc *); 304126258Smlaierint pf_test_state_icmp(struct pf_state **, int, 305130613Smlaier struct pfi_kif *, struct mbuf *, int, 306145836Smlaier void *, struct pf_pdesc *, u_short *); 307126258Smlaierint pf_test_state_other(struct pf_state **, int, 308223637Sbz struct pfi_kif *, struct mbuf *, struct pf_pdesc *); 309126258Smlaiervoid pf_route(struct mbuf **, struct pf_rule *, int, 310171168Smlaier struct ifnet *, struct pf_state *, 311171168Smlaier struct pf_pdesc *); 312126258Smlaiervoid pf_route6(struct mbuf **, struct pf_rule *, int, 313171168Smlaier struct ifnet *, struct pf_state *, 314171168Smlaier struct pf_pdesc *); 315223637Sbz#ifndef __FreeBSD__ 316171168Smlaierint pf_socket_lookup(int, struct pf_pdesc *); 317135920Smlaier#endif 318126258Smlaieru_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, 319126258Smlaier sa_family_t); 320126258Smlaieru_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, 321126258Smlaier sa_family_t); 322126258Smlaieru_int16_t pf_calc_mss(struct pf_addr *, sa_family_t, 323231852Sbz int, u_int16_t); 324126258Smlaiervoid pf_set_rt_ifp(struct pf_state *, 325126258Smlaier struct pf_addr *); 326126258Smlaierint pf_check_proto_cksum(struct mbuf *, int, int, 327126258Smlaier u_int8_t, sa_family_t); 328223637Sbz#ifndef __FreeBSD__ 329223637Sbzstruct pf_divert *pf_get_divert(struct mbuf *); 330223637Sbz#endif 331223637Sbzvoid pf_print_state_parts(struct pf_state *, 332223637Sbz struct pf_state_key *, struct pf_state_key *); 333126258Smlaierint pf_addr_wrap_neq(struct pf_addr_wrap *, 334126258Smlaier struct pf_addr_wrap *); 335223637Sbzint pf_compare_state_keys(struct pf_state_key *, 336223637Sbz struct pf_state_key *, struct pfi_kif *, u_int); 337223637Sbz#ifdef __FreeBSD__ 338223637Sbzstruct pf_state *pf_find_state(struct pfi_kif *, 339223637Sbz struct pf_state_key_cmp *, u_int, struct mbuf *, 340223637Sbz struct pf_mtag *); 341223637Sbz#else 342223637Sbzstruct pf_state *pf_find_state(struct pfi_kif *, 343223637Sbz struct pf_state_key_cmp *, u_int, struct mbuf *); 344223637Sbz#endif 345145836Smlaierint pf_src_connlimit(struct pf_state **); 346145836Smlaierint pf_check_congestion(struct ifqueue *); 347126258Smlaier 348127145Smlaier#ifdef __FreeBSD__ 349126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); 350126258Smlaier 351223637SbzVNET_DECLARE(int, pf_end_threads); 352171168Smlaier 353223637SbzVNET_DEFINE(struct pf_pool_limit, pf_pool_limits[PF_LIMIT_MAX]); 354171168Smlaier#else 355171168Smlaierextern struct pool pfr_ktable_pl; 356171168Smlaierextern struct pool pfr_kentry_pl; 357145836Smlaier 358130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { 359130613Smlaier { &pf_state_pl, PFSTATE_HIWAT }, 360130613Smlaier { &pf_src_tree_pl, PFSNODE_HIWAT }, 361171168Smlaier { &pf_frent_pl, PFFRAG_FRENT_HIWAT }, 362171168Smlaier { &pfr_ktable_pl, PFR_KTABLE_HIWAT }, 363171168Smlaier { &pfr_kentry_pl, PFR_KENTRY_HIWAT } 364130613Smlaier}; 365126261Smlaier#endif 366126258Smlaier 367223637Sbz#ifdef __FreeBSD__ 368223637Sbz#define PPACKET_LOOPED() \ 369223637Sbz (pd->pf_mtag->flags & PF_PACKET_LOOPED) 370223637Sbz 371223637Sbz#define PACKET_LOOPED() \ 372223637Sbz (pd.pf_mtag->flags & PF_PACKET_LOOPED) 373223637Sbz 374223637Sbz#define STATE_LOOKUP(i, k, d, s, m, pt) \ 375126258Smlaier do { \ 376223637Sbz s = pf_find_state(i, k, d, m, pt); \ 377223637Sbz if (s == NULL || (s)->timeout == PFTM_PURGE) \ 378126258Smlaier return (PF_DROP); \ 379223637Sbz if (PPACKET_LOOPED()) \ 380126258Smlaier return (PF_PASS); \ 381223637Sbz if (d == PF_OUT && \ 382223637Sbz (((s)->rule.ptr->rt == PF_ROUTETO && \ 383223637Sbz (s)->rule.ptr->direction == PF_OUT) || \ 384223637Sbz ((s)->rule.ptr->rt == PF_REPLYTO && \ 385223637Sbz (s)->rule.ptr->direction == PF_IN)) && \ 386223637Sbz (s)->rt_kif != NULL && \ 387223637Sbz (s)->rt_kif != i) \ 388223637Sbz return (PF_PASS); \ 389126258Smlaier } while (0) 390223637Sbz#else 391223637Sbz#define STATE_LOOKUP(i, k, d, s, m) \ 392223637Sbz do { \ 393223637Sbz s = pf_find_state(i, k, d, m); \ 394223637Sbz if (s == NULL || (s)->timeout == PFTM_PURGE) \ 395223637Sbz return (PF_DROP); \ 396223637Sbz if (d == PF_OUT && \ 397223637Sbz (((s)->rule.ptr->rt == PF_ROUTETO && \ 398223637Sbz (s)->rule.ptr->direction == PF_OUT) || \ 399223637Sbz ((s)->rule.ptr->rt == PF_REPLYTO && \ 400223637Sbz (s)->rule.ptr->direction == PF_IN)) && \ 401223637Sbz (s)->rt_kif != NULL && \ 402223637Sbz (s)->rt_kif != i) \ 403223637Sbz return (PF_PASS); \ 404223637Sbz } while (0) 405223637Sbz#endif 406126258Smlaier 407223637Sbz#ifdef __FreeBSD__ 408223637Sbz#define BOUND_IFACE(r, k) \ 409223637Sbz ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all 410223637Sbz#else 411223637Sbz#define BOUND_IFACE(r, k) \ 412171168Smlaier ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all 413223637Sbz#endif 414126258Smlaier 415223637Sbz#define STATE_INC_COUNTERS(s) \ 416145836Smlaier do { \ 417223637Sbz s->rule.ptr->states_cur++; \ 418223637Sbz s->rule.ptr->states_tot++; \ 419223637Sbz if (s->anchor.ptr != NULL) { \ 420223637Sbz s->anchor.ptr->states_cur++; \ 421223637Sbz s->anchor.ptr->states_tot++; \ 422223637Sbz } \ 423223637Sbz if (s->nat_rule.ptr != NULL) { \ 424223637Sbz s->nat_rule.ptr->states_cur++; \ 425223637Sbz s->nat_rule.ptr->states_tot++; \ 426223637Sbz } \ 427145836Smlaier } while (0) 428145836Smlaier 429223637Sbz#define STATE_DEC_COUNTERS(s) \ 430145836Smlaier do { \ 431145836Smlaier if (s->nat_rule.ptr != NULL) \ 432223637Sbz s->nat_rule.ptr->states_cur--; \ 433145836Smlaier if (s->anchor.ptr != NULL) \ 434223637Sbz s->anchor.ptr->states_cur--; \ 435223637Sbz s->rule.ptr->states_cur--; \ 436145836Smlaier } while (0) 437145836Smlaier 438223637Sbzstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *); 439223637Sbzstatic __inline int pf_state_compare_key(struct pf_state_key *, 440223637Sbz struct pf_state_key *); 441223637Sbzstatic __inline int pf_state_compare_id(struct pf_state *, 442223637Sbz struct pf_state *); 443223637Sbz 444223637Sbz#ifdef __FreeBSD__ 445223637SbzVNET_DEFINE(struct pf_src_tree, tree_src_tracking); 446223637Sbz 447223637SbzVNET_DEFINE(struct pf_state_tree_id, tree_id); 448223637SbzVNET_DEFINE(struct pf_state_queue, state_list); 449223637Sbz#else 450130613Smlaierstruct pf_src_tree tree_src_tracking; 451130613Smlaier 452130613Smlaierstruct pf_state_tree_id tree_id; 453171168Smlaierstruct pf_state_queue state_list; 454171168Smlaier#endif 455171168Smlaier 456130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare); 457223637SbzRB_GENERATE(pf_state_tree, pf_state_key, entry, pf_state_compare_key); 458130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state, 459223637Sbz entry_id, pf_state_compare_id); 460130613Smlaier 461126258Smlaierstatic __inline int 462130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b) 463126258Smlaier{ 464126258Smlaier int diff; 465126258Smlaier 466130613Smlaier if (a->rule.ptr > b->rule.ptr) 467130613Smlaier return (1); 468130613Smlaier if (a->rule.ptr < b->rule.ptr) 469130613Smlaier return (-1); 470130613Smlaier if ((diff = a->af - b->af) != 0) 471130613Smlaier return (diff); 472130613Smlaier switch (a->af) { 473130613Smlaier#ifdef INET 474130613Smlaier case AF_INET: 475130613Smlaier if (a->addr.addr32[0] > b->addr.addr32[0]) 476130613Smlaier return (1); 477130613Smlaier if (a->addr.addr32[0] < b->addr.addr32[0]) 478130613Smlaier return (-1); 479130613Smlaier break; 480130613Smlaier#endif /* INET */ 481130613Smlaier#ifdef INET6 482130613Smlaier case AF_INET6: 483130613Smlaier if (a->addr.addr32[3] > b->addr.addr32[3]) 484130613Smlaier return (1); 485130613Smlaier if (a->addr.addr32[3] < b->addr.addr32[3]) 486130613Smlaier return (-1); 487130613Smlaier if (a->addr.addr32[2] > b->addr.addr32[2]) 488130613Smlaier return (1); 489130613Smlaier if (a->addr.addr32[2] < b->addr.addr32[2]) 490130613Smlaier return (-1); 491130613Smlaier if (a->addr.addr32[1] > b->addr.addr32[1]) 492130613Smlaier return (1); 493130613Smlaier if (a->addr.addr32[1] < b->addr.addr32[1]) 494130613Smlaier return (-1); 495130613Smlaier if (a->addr.addr32[0] > b->addr.addr32[0]) 496130613Smlaier return (1); 497130613Smlaier if (a->addr.addr32[0] < b->addr.addr32[0]) 498130613Smlaier return (-1); 499130613Smlaier break; 500130613Smlaier#endif /* INET6 */ 501130613Smlaier } 502130613Smlaier return (0); 503130613Smlaier} 504130613Smlaier 505126258Smlaier#ifdef INET6 506126258Smlaiervoid 507126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) 508126258Smlaier{ 509126258Smlaier switch (af) { 510126258Smlaier#ifdef INET 511126258Smlaier case AF_INET: 512126258Smlaier dst->addr32[0] = src->addr32[0]; 513126258Smlaier break; 514126258Smlaier#endif /* INET */ 515126258Smlaier case AF_INET6: 516126258Smlaier dst->addr32[0] = src->addr32[0]; 517126258Smlaier dst->addr32[1] = src->addr32[1]; 518126258Smlaier dst->addr32[2] = src->addr32[2]; 519126258Smlaier dst->addr32[3] = src->addr32[3]; 520126258Smlaier break; 521126258Smlaier } 522126258Smlaier} 523145836Smlaier#endif /* INET6 */ 524126258Smlaier 525145836Smlaiervoid 526145836Smlaierpf_init_threshold(struct pf_threshold *threshold, 527145836Smlaier u_int32_t limit, u_int32_t seconds) 528145836Smlaier{ 529145836Smlaier threshold->limit = limit * PF_THRESHOLD_MULT; 530145836Smlaier threshold->seconds = seconds; 531145836Smlaier threshold->count = 0; 532145836Smlaier threshold->last = time_second; 533145836Smlaier} 534145836Smlaier 535145836Smlaiervoid 536145836Smlaierpf_add_threshold(struct pf_threshold *threshold) 537145836Smlaier{ 538145836Smlaier u_int32_t t = time_second, diff = t - threshold->last; 539145836Smlaier 540145836Smlaier if (diff >= threshold->seconds) 541145836Smlaier threshold->count = 0; 542145836Smlaier else 543145836Smlaier threshold->count -= threshold->count * diff / 544145836Smlaier threshold->seconds; 545145836Smlaier threshold->count += PF_THRESHOLD_MULT; 546145836Smlaier threshold->last = t; 547145836Smlaier} 548145836Smlaier 549126258Smlaierint 550145836Smlaierpf_check_threshold(struct pf_threshold *threshold) 551145836Smlaier{ 552145836Smlaier return (threshold->count > threshold->limit); 553145836Smlaier} 554145836Smlaier 555145836Smlaierint 556145836Smlaierpf_src_connlimit(struct pf_state **state) 557145836Smlaier{ 558145836Smlaier int bad = 0; 559145836Smlaier 560145836Smlaier (*state)->src_node->conn++; 561171168Smlaier (*state)->src.tcp_est = 1; 562145836Smlaier pf_add_threshold(&(*state)->src_node->conn_rate); 563145836Smlaier 564145836Smlaier if ((*state)->rule.ptr->max_src_conn && 565145836Smlaier (*state)->rule.ptr->max_src_conn < 566145836Smlaier (*state)->src_node->conn) { 567223637Sbz#ifdef __FreeBSD__ 568223637Sbz V_pf_status.lcounters[LCNT_SRCCONN]++; 569223637Sbz#else 570145836Smlaier pf_status.lcounters[LCNT_SRCCONN]++; 571223637Sbz#endif 572145836Smlaier bad++; 573145836Smlaier } 574145836Smlaier 575145836Smlaier if ((*state)->rule.ptr->max_src_conn_rate.limit && 576145836Smlaier pf_check_threshold(&(*state)->src_node->conn_rate)) { 577223637Sbz#ifdef __FreeBSD__ 578223637Sbz V_pf_status.lcounters[LCNT_SRCCONNRATE]++; 579223637Sbz#else 580145836Smlaier pf_status.lcounters[LCNT_SRCCONNRATE]++; 581223637Sbz#endif 582145836Smlaier bad++; 583145836Smlaier } 584145836Smlaier 585145836Smlaier if (!bad) 586145836Smlaier return (0); 587145836Smlaier 588145836Smlaier if ((*state)->rule.ptr->overload_tbl) { 589145836Smlaier struct pfr_addr p; 590145836Smlaier u_int32_t killed = 0; 591145836Smlaier 592223637Sbz#ifdef __FreeBSD__ 593223637Sbz V_pf_status.lcounters[LCNT_OVERLOAD_TABLE]++; 594223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 595223637Sbz#else 596145836Smlaier pf_status.lcounters[LCNT_OVERLOAD_TABLE]++; 597145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 598223637Sbz#endif 599145836Smlaier printf("pf_src_connlimit: blocking address "); 600145836Smlaier pf_print_host(&(*state)->src_node->addr, 0, 601223637Sbz (*state)->key[PF_SK_WIRE]->af); 602145836Smlaier } 603145836Smlaier 604145836Smlaier bzero(&p, sizeof(p)); 605223637Sbz p.pfra_af = (*state)->key[PF_SK_WIRE]->af; 606223637Sbz switch ((*state)->key[PF_SK_WIRE]->af) { 607145836Smlaier#ifdef INET 608145836Smlaier case AF_INET: 609145836Smlaier p.pfra_net = 32; 610145836Smlaier p.pfra_ip4addr = (*state)->src_node->addr.v4; 611145836Smlaier break; 612145836Smlaier#endif /* INET */ 613145836Smlaier#ifdef INET6 614145836Smlaier case AF_INET6: 615145836Smlaier p.pfra_net = 128; 616145836Smlaier p.pfra_ip6addr = (*state)->src_node->addr.v6; 617145836Smlaier break; 618145836Smlaier#endif /* INET6 */ 619145836Smlaier } 620145836Smlaier 621145836Smlaier pfr_insert_kentry((*state)->rule.ptr->overload_tbl, 622145836Smlaier &p, time_second); 623145836Smlaier 624145836Smlaier /* kill existing states if that's required. */ 625145836Smlaier if ((*state)->rule.ptr->flush) { 626223637Sbz struct pf_state_key *sk; 627223637Sbz struct pf_state *st; 628223637Sbz 629223637Sbz#ifdef __FreeBSD__ 630223637Sbz V_pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; 631223637Sbz RB_FOREACH(st, pf_state_tree_id, &V_tree_id) { 632223637Sbz#else 633145836Smlaier pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; 634223637Sbz RB_FOREACH(st, pf_state_tree_id, &tree_id) { 635223637Sbz#endif 636223637Sbz sk = st->key[PF_SK_WIRE]; 637145836Smlaier /* 638145836Smlaier * Kill states from this source. (Only those 639145836Smlaier * from the same rule if PF_FLUSH_GLOBAL is not 640145836Smlaier * set) 641145836Smlaier */ 642223637Sbz if (sk->af == 643223637Sbz (*state)->key[PF_SK_WIRE]->af && 644145836Smlaier (((*state)->direction == PF_OUT && 645145836Smlaier PF_AEQ(&(*state)->src_node->addr, 646223637Sbz &sk->addr[0], sk->af)) || 647145836Smlaier ((*state)->direction == PF_IN && 648145836Smlaier PF_AEQ(&(*state)->src_node->addr, 649223637Sbz &sk->addr[1], sk->af))) && 650145836Smlaier ((*state)->rule.ptr->flush & 651145836Smlaier PF_FLUSH_GLOBAL || 652223637Sbz (*state)->rule.ptr == st->rule.ptr)) { 653223637Sbz st->timeout = PFTM_PURGE; 654223637Sbz st->src.state = st->dst.state = 655145836Smlaier TCPS_CLOSED; 656145836Smlaier killed++; 657145836Smlaier } 658145836Smlaier } 659223637Sbz#ifdef __FreeBSD__ 660223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 661223637Sbz#else 662145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 663223637Sbz#endif 664145836Smlaier printf(", %u states killed", killed); 665145836Smlaier } 666223637Sbz#ifdef __FreeBSD__ 667223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 668223637Sbz#else 669145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 670223637Sbz#endif 671145836Smlaier printf("\n"); 672145836Smlaier } 673145836Smlaier 674145836Smlaier /* kill this state */ 675145836Smlaier (*state)->timeout = PFTM_PURGE; 676145836Smlaier (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; 677145836Smlaier return (1); 678145836Smlaier} 679145836Smlaier 680145836Smlaierint 681130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, 682130613Smlaier struct pf_addr *src, sa_family_t af) 683126258Smlaier{ 684130613Smlaier struct pf_src_node k; 685126258Smlaier 686130613Smlaier if (*sn == NULL) { 687130613Smlaier k.af = af; 688130613Smlaier PF_ACPY(&k.addr, src, af); 689130613Smlaier if (rule->rule_flag & PFRULE_RULESRCTRACK || 690130613Smlaier rule->rpool.opts & PF_POOL_STICKYADDR) 691130613Smlaier k.rule.ptr = rule; 692130613Smlaier else 693130613Smlaier k.rule.ptr = NULL; 694223637Sbz#ifdef __FreeBSD__ 695223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; 696223637Sbz *sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k); 697223637Sbz#else 698130613Smlaier pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; 699130613Smlaier *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); 700223637Sbz#endif 701130613Smlaier } 702130613Smlaier if (*sn == NULL) { 703130613Smlaier if (!rule->max_src_nodes || 704130613Smlaier rule->src_nodes < rule->max_src_nodes) 705223637Sbz#ifdef __FreeBSD__ 706223637Sbz (*sn) = pool_get(&V_pf_src_tree_pl, PR_NOWAIT | PR_ZERO); 707223637Sbz#else 708223637Sbz (*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT | PR_ZERO); 709223637Sbz#endif 710145836Smlaier else 711223637Sbz#ifdef __FreeBSD__ 712223637Sbz V_pf_status.lcounters[LCNT_SRCNODES]++; 713223637Sbz#else 714145836Smlaier pf_status.lcounters[LCNT_SRCNODES]++; 715223637Sbz#endif 716130613Smlaier if ((*sn) == NULL) 717130613Smlaier return (-1); 718145836Smlaier 719145836Smlaier pf_init_threshold(&(*sn)->conn_rate, 720145836Smlaier rule->max_src_conn_rate.limit, 721145836Smlaier rule->max_src_conn_rate.seconds); 722145836Smlaier 723130613Smlaier (*sn)->af = af; 724130613Smlaier if (rule->rule_flag & PFRULE_RULESRCTRACK || 725130613Smlaier rule->rpool.opts & PF_POOL_STICKYADDR) 726130613Smlaier (*sn)->rule.ptr = rule; 727130613Smlaier else 728130613Smlaier (*sn)->rule.ptr = NULL; 729130613Smlaier PF_ACPY(&(*sn)->addr, src, af); 730130613Smlaier if (RB_INSERT(pf_src_tree, 731223637Sbz#ifdef __FreeBSD__ 732223637Sbz &V_tree_src_tracking, *sn) != NULL) { 733223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 734223637Sbz#else 735130613Smlaier &tree_src_tracking, *sn) != NULL) { 736130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 737223637Sbz#endif 738130613Smlaier printf("pf: src_tree insert failed: "); 739130613Smlaier pf_print_host(&(*sn)->addr, 0, af); 740130613Smlaier printf("\n"); 741130613Smlaier } 742223637Sbz#ifdef __FreeBSD__ 743223637Sbz pool_put(&V_pf_src_tree_pl, *sn); 744223637Sbz#else 745130613Smlaier pool_put(&pf_src_tree_pl, *sn); 746223637Sbz#endif 747130613Smlaier return (-1); 748130613Smlaier } 749130613Smlaier (*sn)->creation = time_second; 750130613Smlaier (*sn)->ruletype = rule->action; 751130613Smlaier if ((*sn)->rule.ptr != NULL) 752130613Smlaier (*sn)->rule.ptr->src_nodes++; 753223637Sbz#ifdef __FreeBSD__ 754223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_INSERT]++; 755223637Sbz V_pf_status.src_nodes++; 756223637Sbz#else 757130613Smlaier pf_status.scounters[SCNT_SRC_NODE_INSERT]++; 758130613Smlaier pf_status.src_nodes++; 759223637Sbz#endif 760130613Smlaier } else { 761130613Smlaier if (rule->max_src_states && 762145836Smlaier (*sn)->states >= rule->max_src_states) { 763223637Sbz#ifdef __FreeBSD__ 764223637Sbz V_pf_status.lcounters[LCNT_SRCSTATES]++; 765223637Sbz#else 766145836Smlaier pf_status.lcounters[LCNT_SRCSTATES]++; 767223637Sbz#endif 768130613Smlaier return (-1); 769145836Smlaier } 770130613Smlaier } 771130613Smlaier return (0); 772130613Smlaier} 773126258Smlaier 774223637Sbz/* state table stuff */ 775223637Sbz 776223637Sbzstatic __inline int 777223637Sbzpf_state_compare_key(struct pf_state_key *a, struct pf_state_key *b) 778223637Sbz{ 779223637Sbz int diff; 780223637Sbz 781223637Sbz if ((diff = a->proto - b->proto) != 0) 782223637Sbz return (diff); 783223637Sbz if ((diff = a->af - b->af) != 0) 784223637Sbz return (diff); 785223637Sbz switch (a->af) { 786223637Sbz#ifdef INET 787223637Sbz case AF_INET: 788223637Sbz if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) 789223637Sbz return (1); 790223637Sbz if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) 791223637Sbz return (-1); 792223637Sbz if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) 793223637Sbz return (1); 794223637Sbz if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) 795223637Sbz return (-1); 796223637Sbz break; 797223637Sbz#endif /* INET */ 798223637Sbz#ifdef INET6 799223637Sbz case AF_INET6: 800223637Sbz if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) 801223637Sbz return (1); 802223637Sbz if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) 803223637Sbz return (-1); 804223637Sbz if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) 805223637Sbz return (1); 806223637Sbz if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) 807223637Sbz return (-1); 808223637Sbz if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) 809223637Sbz return (1); 810223637Sbz if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) 811223637Sbz return (-1); 812223637Sbz if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) 813223637Sbz return (1); 814223637Sbz if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) 815223637Sbz return (-1); 816223637Sbz if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) 817223637Sbz return (1); 818223637Sbz if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) 819223637Sbz return (-1); 820223637Sbz if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) 821223637Sbz return (1); 822223637Sbz if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) 823223637Sbz return (-1); 824223637Sbz if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) 825223637Sbz return (1); 826223637Sbz if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) 827223637Sbz return (-1); 828223637Sbz if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) 829223637Sbz return (1); 830223637Sbz if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) 831223637Sbz return (-1); 832223637Sbz break; 833223637Sbz#endif /* INET6 */ 834223637Sbz } 835223637Sbz 836223637Sbz if ((diff = a->port[0] - b->port[0]) != 0) 837223637Sbz return (diff); 838223637Sbz if ((diff = a->port[1] - b->port[1]) != 0) 839223637Sbz return (diff); 840223637Sbz 841223637Sbz return (0); 842223637Sbz} 843223637Sbz 844223637Sbzstatic __inline int 845223637Sbzpf_state_compare_id(struct pf_state *a, struct pf_state *b) 846223637Sbz{ 847223637Sbz if (a->id > b->id) 848223637Sbz return (1); 849223637Sbz if (a->id < b->id) 850223637Sbz return (-1); 851223637Sbz if (a->creatorid > b->creatorid) 852223637Sbz return (1); 853223637Sbz if (a->creatorid < b->creatorid) 854223637Sbz return (-1); 855223637Sbz 856223637Sbz return (0); 857223637Sbz} 858223637Sbz 859130613Smlaierint 860223637Sbzpf_state_key_attach(struct pf_state_key *sk, struct pf_state *s, int idx) 861130613Smlaier{ 862223637Sbz struct pf_state_item *si; 863223637Sbz struct pf_state_key *cur; 864223637Sbz struct pf_state *olds = NULL; 865223637Sbz 866223637Sbz#ifdef __FreeBSD__ 867223637Sbz KASSERT(s->key[idx] == NULL, ("%s: key is null!", __FUNCTION__)); 868223637Sbz#else 869223637Sbz KASSERT(s->key[idx] == NULL); /* XXX handle this? */ 870223637Sbz#endif 871223637Sbz 872223637Sbz#ifdef __FreeBSD__ 873223637Sbz if ((cur = RB_INSERT(pf_state_tree, &V_pf_statetbl, sk)) != NULL) { 874223637Sbz#else 875223637Sbz if ((cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) { 876223637Sbz#endif 877223637Sbz /* key exists. check for same kif, if none, add to key */ 878223637Sbz TAILQ_FOREACH(si, &cur->states, entry) 879223637Sbz if (si->s->kif == s->kif && 880223637Sbz si->s->direction == s->direction) { 881223637Sbz if (sk->proto == IPPROTO_TCP && 882223637Sbz si->s->src.state >= TCPS_FIN_WAIT_2 && 883223637Sbz si->s->dst.state >= TCPS_FIN_WAIT_2) { 884223637Sbz si->s->src.state = si->s->dst.state = 885223637Sbz TCPS_CLOSED; 886223637Sbz /* unlink late or sks can go away */ 887223637Sbz olds = si->s; 888223637Sbz } else { 889223637Sbz#ifdef __FreeBSD__ 890223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 891223637Sbz#else 892223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 893223637Sbz#endif 894223637Sbz printf("pf: %s key attach " 895223637Sbz "failed on %s: ", 896223637Sbz (idx == PF_SK_WIRE) ? 897223637Sbz "wire" : "stack", 898223637Sbz s->kif->pfik_name); 899223637Sbz pf_print_state_parts(s, 900223637Sbz (idx == PF_SK_WIRE) ? 901223637Sbz sk : NULL, 902223637Sbz (idx == PF_SK_STACK) ? 903223637Sbz sk : NULL); 904223637Sbz printf(", existing: "); 905223637Sbz pf_print_state_parts(si->s, 906223637Sbz (idx == PF_SK_WIRE) ? 907223637Sbz sk : NULL, 908223637Sbz (idx == PF_SK_STACK) ? 909223637Sbz sk : NULL); 910223637Sbz printf("\n"); 911223637Sbz } 912223637Sbz#ifdef __FreeBSD__ 913223637Sbz pool_put(&V_pf_state_key_pl, sk); 914223637Sbz#else 915223637Sbz pool_put(&pf_state_key_pl, sk); 916223637Sbz#endif 917223637Sbz return (-1); /* collision! */ 918223637Sbz } 919223637Sbz } 920223637Sbz#ifdef __FreeBSD__ 921223637Sbz pool_put(&V_pf_state_key_pl, sk); 922223637Sbz#else 923223637Sbz pool_put(&pf_state_key_pl, sk); 924223637Sbz#endif 925223637Sbz s->key[idx] = cur; 926223637Sbz } else 927223637Sbz s->key[idx] = sk; 928223637Sbz 929223637Sbz#ifdef __FreeBSD__ 930223637Sbz if ((si = pool_get(&V_pf_state_item_pl, PR_NOWAIT)) == NULL) { 931223637Sbz#else 932223637Sbz if ((si = pool_get(&pf_state_item_pl, PR_NOWAIT)) == NULL) { 933223637Sbz#endif 934223637Sbz pf_state_key_detach(s, idx); 935126258Smlaier return (-1); 936126258Smlaier } 937223637Sbz si->s = s; 938126258Smlaier 939223637Sbz /* list is sorted, if-bound states before floating */ 940223637Sbz#ifdef __FreeBSD__ 941223637Sbz if (s->kif == V_pfi_all) 942223637Sbz#else 943223637Sbz if (s->kif == pfi_all) 944223637Sbz#endif 945223637Sbz TAILQ_INSERT_TAIL(&s->key[idx]->states, si, entry); 946223637Sbz else 947223637Sbz TAILQ_INSERT_HEAD(&s->key[idx]->states, si, entry); 948223637Sbz 949223637Sbz if (olds) 950223637Sbz pf_unlink_state(olds); 951223637Sbz 952223637Sbz return (0); 953223637Sbz} 954223637Sbz 955223637Sbzvoid 956223637Sbzpf_detach_state(struct pf_state *s) 957223637Sbz{ 958223637Sbz if (s->key[PF_SK_WIRE] == s->key[PF_SK_STACK]) 959223637Sbz s->key[PF_SK_WIRE] = NULL; 960223637Sbz 961223637Sbz if (s->key[PF_SK_STACK] != NULL) 962223637Sbz pf_state_key_detach(s, PF_SK_STACK); 963223637Sbz 964223637Sbz if (s->key[PF_SK_WIRE] != NULL) 965223637Sbz pf_state_key_detach(s, PF_SK_WIRE); 966223637Sbz} 967223637Sbz 968223637Sbzvoid 969223637Sbzpf_state_key_detach(struct pf_state *s, int idx) 970223637Sbz{ 971223637Sbz struct pf_state_item *si; 972223637Sbz 973223637Sbz si = TAILQ_FIRST(&s->key[idx]->states); 974223637Sbz while (si && si->s != s) 975223637Sbz si = TAILQ_NEXT(si, entry); 976223637Sbz 977223637Sbz if (si) { 978223637Sbz TAILQ_REMOVE(&s->key[idx]->states, si, entry); 979223637Sbz#ifdef __FreeBSD__ 980223637Sbz pool_put(&V_pf_state_item_pl, si); 981223637Sbz#else 982223637Sbz pool_put(&pf_state_item_pl, si); 983223637Sbz#endif 984223637Sbz } 985223637Sbz 986223637Sbz if (TAILQ_EMPTY(&s->key[idx]->states)) { 987223637Sbz#ifdef __FreeBSD__ 988223637Sbz RB_REMOVE(pf_state_tree, &V_pf_statetbl, s->key[idx]); 989223637Sbz#else 990223637Sbz RB_REMOVE(pf_state_tree, &pf_statetbl, s->key[idx]); 991223637Sbz#endif 992223637Sbz if (s->key[idx]->reverse) 993223637Sbz s->key[idx]->reverse->reverse = NULL; 994223637Sbz#ifdef __FreeBSD__ 995223637Sbz /* XXX: implement this */ 996223637Sbz#else 997223637Sbz if (s->key[idx]->inp) 998223637Sbz s->key[idx]->inp->inp_pf_sk = NULL; 999223637Sbz#endif 1000223637Sbz#ifdef __FreeBSD__ 1001223637Sbz pool_put(&V_pf_state_key_pl, s->key[idx]); 1002223637Sbz#else 1003223637Sbz pool_put(&pf_state_key_pl, s->key[idx]); 1004223637Sbz#endif 1005223637Sbz } 1006223637Sbz s->key[idx] = NULL; 1007223637Sbz} 1008223637Sbz 1009223637Sbzstruct pf_state_key * 1010223637Sbzpf_alloc_state_key(int pool_flags) 1011223637Sbz{ 1012223637Sbz struct pf_state_key *sk; 1013223637Sbz 1014223637Sbz#ifdef __FreeBSD__ 1015223637Sbz if ((sk = pool_get(&V_pf_state_key_pl, pool_flags)) == NULL) 1016223637Sbz#else 1017223637Sbz if ((sk = pool_get(&pf_state_key_pl, pool_flags)) == NULL) 1018223637Sbz#endif 1019223637Sbz return (NULL); 1020223637Sbz TAILQ_INIT(&sk->states); 1021223637Sbz 1022223637Sbz return (sk); 1023223637Sbz} 1024223637Sbz 1025223637Sbzint 1026223637Sbzpf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, 1027223637Sbz struct pf_state_key **skw, struct pf_state_key **sks, 1028223637Sbz struct pf_state_key **skp, struct pf_state_key **nkp, 1029223637Sbz struct pf_addr *saddr, struct pf_addr *daddr, 1030223637Sbz u_int16_t sport, u_int16_t dport) 1031223637Sbz{ 1032223637Sbz#ifdef __FreeBSD__ 1033223637Sbz KASSERT((*skp == NULL && *nkp == NULL), 1034223637Sbz ("%s: skp == NULL && nkp == NULL", __FUNCTION__)); 1035223637Sbz#else 1036223637Sbz KASSERT((*skp == NULL && *nkp == NULL)); 1037223637Sbz#endif 1038223637Sbz 1039223637Sbz if ((*skp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) 1040223637Sbz return (ENOMEM); 1041223637Sbz 1042223637Sbz PF_ACPY(&(*skp)->addr[pd->sidx], saddr, pd->af); 1043223637Sbz PF_ACPY(&(*skp)->addr[pd->didx], daddr, pd->af); 1044223637Sbz (*skp)->port[pd->sidx] = sport; 1045223637Sbz (*skp)->port[pd->didx] = dport; 1046223637Sbz (*skp)->proto = pd->proto; 1047223637Sbz (*skp)->af = pd->af; 1048223637Sbz 1049223637Sbz if (nr != NULL) { 1050223637Sbz if ((*nkp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) 1051223637Sbz return (ENOMEM); /* caller must handle cleanup */ 1052223637Sbz 1053223637Sbz /* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */ 1054223637Sbz PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af); 1055223637Sbz PF_ACPY(&(*nkp)->addr[1], &(*skp)->addr[1], pd->af); 1056223637Sbz (*nkp)->port[0] = (*skp)->port[0]; 1057223637Sbz (*nkp)->port[1] = (*skp)->port[1]; 1058223637Sbz (*nkp)->proto = pd->proto; 1059223637Sbz (*nkp)->af = pd->af; 1060223637Sbz } else 1061223637Sbz *nkp = *skp; 1062223637Sbz 1063223637Sbz if (pd->dir == PF_IN) { 1064223637Sbz *skw = *skp; 1065223637Sbz *sks = *nkp; 1066223637Sbz } else { 1067223637Sbz *sks = *skp; 1068223637Sbz *skw = *nkp; 1069223637Sbz } 1070223637Sbz return (0); 1071223637Sbz} 1072223637Sbz 1073223637Sbz 1074223637Sbzint 1075223637Sbzpf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw, 1076223637Sbz struct pf_state_key *sks, struct pf_state *s) 1077223637Sbz{ 1078223637Sbz#ifndef __FreeBSD__ 1079223637Sbz splassert(IPL_SOFTNET); 1080223637Sbz#endif 1081223637Sbz 1082223637Sbz s->kif = kif; 1083223637Sbz 1084223637Sbz if (skw == sks) { 1085223637Sbz if (pf_state_key_attach(skw, s, PF_SK_WIRE)) 1086223637Sbz return (-1); 1087223637Sbz s->key[PF_SK_STACK] = s->key[PF_SK_WIRE]; 1088223637Sbz } else { 1089223637Sbz if (pf_state_key_attach(skw, s, PF_SK_WIRE)) { 1090223637Sbz#ifdef __FreeBSD__ 1091223637Sbz pool_put(&V_pf_state_key_pl, sks); 1092223637Sbz#else 1093223637Sbz pool_put(&pf_state_key_pl, sks); 1094223637Sbz#endif 1095223637Sbz return (-1); 1096126258Smlaier } 1097223637Sbz if (pf_state_key_attach(sks, s, PF_SK_STACK)) { 1098223637Sbz pf_state_key_detach(s, PF_SK_WIRE); 1099223637Sbz return (-1); 1100223637Sbz } 1101126258Smlaier } 1102126258Smlaier 1103223637Sbz if (s->id == 0 && s->creatorid == 0) { 1104223637Sbz#ifdef __FreeBSD__ 1105223637Sbz s->id = htobe64(V_pf_status.stateid++); 1106223637Sbz s->creatorid = V_pf_status.hostid; 1107223637Sbz#else 1108223637Sbz s->id = htobe64(pf_status.stateid++); 1109223637Sbz s->creatorid = pf_status.hostid; 1110223637Sbz#endif 1111130613Smlaier } 1112223637Sbz#ifdef __FreeBSD__ 1113223637Sbz if (RB_INSERT(pf_state_tree_id, &V_tree_id, s) != NULL) { 1114223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 1115223637Sbz#else 1116223637Sbz if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) { 1117130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 1118223637Sbz#endif 1119130613Smlaier printf("pf: state insert failed: " 1120130613Smlaier "id: %016llx creatorid: %08x", 1121223637Sbz#ifdef __FreeBSD__ 1122223637Sbz (unsigned long long)betoh64(s->id), ntohl(s->creatorid)); 1123130613Smlaier#else 1124223637Sbz betoh64(s->id), ntohl(s->creatorid)); 1125130613Smlaier#endif 1126130613Smlaier printf("\n"); 1127130613Smlaier } 1128223637Sbz pf_detach_state(s); 1129130613Smlaier return (-1); 1130130613Smlaier } 1131223637Sbz#ifdef __FreeBSD__ 1132223637Sbz TAILQ_INSERT_TAIL(&V_state_list, s, entry_list); 1133223637Sbz V_pf_status.fcounters[FCNT_STATE_INSERT]++; 1134223637Sbz V_pf_status.states++; 1135223637Sbz#else 1136223637Sbz TAILQ_INSERT_TAIL(&state_list, s, entry_list); 1137126258Smlaier pf_status.fcounters[FCNT_STATE_INSERT]++; 1138126258Smlaier pf_status.states++; 1139223637Sbz#endif 1140171168Smlaier pfi_kif_ref(kif, PFI_KIF_REF_STATE); 1141223637Sbz#if NPFSYNC > 0 1142223637Sbz#ifdef __FreeBSD__ 1143223637Sbz if (pfsync_insert_state_ptr != NULL) 1144223637Sbz pfsync_insert_state_ptr(s); 1145223637Sbz#else 1146223637Sbz pfsync_insert_state(s); 1147126258Smlaier#endif 1148223637Sbz#endif 1149126258Smlaier return (0); 1150126258Smlaier} 1151126258Smlaier 1152223637Sbzstruct pf_state * 1153223637Sbzpf_find_state_byid(struct pf_state_cmp *key) 1154223637Sbz{ 1155223637Sbz#ifdef __FreeBSD__ 1156223637Sbz V_pf_status.fcounters[FCNT_STATE_SEARCH]++; 1157223637Sbz 1158223637Sbz return (RB_FIND(pf_state_tree_id, &V_tree_id, (struct pf_state *)key)); 1159223637Sbz#else 1160223637Sbz pf_status.fcounters[FCNT_STATE_SEARCH]++; 1161223637Sbz 1162223637Sbz return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); 1163223637Sbz#endif 1164223637Sbz} 1165223637Sbz 1166223637Sbz/* XXX debug function, intended to be removed one day */ 1167223637Sbzint 1168223637Sbzpf_compare_state_keys(struct pf_state_key *a, struct pf_state_key *b, 1169223637Sbz struct pfi_kif *kif, u_int dir) 1170223637Sbz{ 1171223637Sbz /* a (from hdr) and b (new) must be exact opposites of each other */ 1172223637Sbz if (a->af == b->af && a->proto == b->proto && 1173223637Sbz PF_AEQ(&a->addr[0], &b->addr[1], a->af) && 1174223637Sbz PF_AEQ(&a->addr[1], &b->addr[0], a->af) && 1175223637Sbz a->port[0] == b->port[1] && 1176223637Sbz a->port[1] == b->port[0]) 1177223637Sbz return (0); 1178223637Sbz else { 1179223637Sbz /* mismatch. must not happen. */ 1180223637Sbz printf("pf: state key linking mismatch! dir=%s, " 1181223637Sbz "if=%s, stored af=%u, a0: ", 1182223637Sbz dir == PF_OUT ? "OUT" : "IN", kif->pfik_name, a->af); 1183223637Sbz pf_print_host(&a->addr[0], a->port[0], a->af); 1184223637Sbz printf(", a1: "); 1185223637Sbz pf_print_host(&a->addr[1], a->port[1], a->af); 1186223637Sbz printf(", proto=%u", a->proto); 1187223637Sbz printf(", found af=%u, a0: ", b->af); 1188223637Sbz pf_print_host(&b->addr[0], b->port[0], b->af); 1189223637Sbz printf(", a1: "); 1190223637Sbz pf_print_host(&b->addr[1], b->port[1], b->af); 1191223637Sbz printf(", proto=%u", b->proto); 1192223637Sbz printf(".\n"); 1193223637Sbz return (-1); 1194223637Sbz } 1195223637Sbz} 1196223637Sbz 1197223637Sbzstruct pf_state * 1198223637Sbz#ifdef __FreeBSD__ 1199223637Sbzpf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir, 1200223637Sbz struct mbuf *m, struct pf_mtag *pftag) 1201223637Sbz#else 1202223637Sbzpf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir, 1203223637Sbz struct mbuf *m) 1204223637Sbz#endif 1205223637Sbz{ 1206223637Sbz struct pf_state_key *sk; 1207223637Sbz struct pf_state_item *si; 1208223637Sbz 1209223637Sbz#ifdef __FreeBSD__ 1210223637Sbz V_pf_status.fcounters[FCNT_STATE_SEARCH]++; 1211223637Sbz#else 1212223637Sbz pf_status.fcounters[FCNT_STATE_SEARCH]++; 1213223637Sbz#endif 1214223637Sbz 1215223637Sbz#ifdef __FreeBSD__ 1216223637Sbz if (dir == PF_OUT && pftag->statekey && 1217223637Sbz ((struct pf_state_key *)pftag->statekey)->reverse) 1218223637Sbz sk = ((struct pf_state_key *)pftag->statekey)->reverse; 1219223637Sbz else { 1220223637Sbz#ifdef __FreeBSD__ 1221223637Sbz if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl, 1222223637Sbz#else 1223223637Sbz if ((sk = RB_FIND(pf_state_tree, &pf_statetbl, 1224223637Sbz#endif 1225223637Sbz (struct pf_state_key *)key)) == NULL) 1226223637Sbz return (NULL); 1227223637Sbz if (dir == PF_OUT && pftag->statekey && 1228223637Sbz pf_compare_state_keys(pftag->statekey, sk, 1229223637Sbz kif, dir) == 0) { 1230223637Sbz ((struct pf_state_key *) 1231223637Sbz pftag->statekey)->reverse = sk; 1232223637Sbz sk->reverse = pftag->statekey; 1233223637Sbz } 1234223637Sbz } 1235223637Sbz#else 1236223637Sbz if (dir == PF_OUT && m->m_pkthdr.pf.statekey && 1237223637Sbz ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse) 1238223637Sbz sk = ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse; 1239223637Sbz else { 1240223637Sbz#ifdef __FreeBSD__ 1241223637Sbz if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl, 1242223637Sbz#else 1243223637Sbz if ((sk = RB_FIND(pf_state_tree, &pf_statetbl, 1244223637Sbz#endif 1245223637Sbz (struct pf_state_key *)key)) == NULL) 1246223637Sbz return (NULL); 1247223637Sbz if (dir == PF_OUT && m->m_pkthdr.pf.statekey && 1248223637Sbz pf_compare_state_keys(m->m_pkthdr.pf.statekey, sk, 1249223637Sbz kif, dir) == 0) { 1250223637Sbz ((struct pf_state_key *) 1251223637Sbz m->m_pkthdr.pf.statekey)->reverse = sk; 1252223637Sbz sk->reverse = m->m_pkthdr.pf.statekey; 1253223637Sbz } 1254223637Sbz } 1255223637Sbz#endif 1256223637Sbz 1257223637Sbz if (dir == PF_OUT) 1258223637Sbz#ifdef __FreeBSD__ 1259223637Sbz pftag->statekey = NULL; 1260223637Sbz#else 1261223637Sbz m->m_pkthdr.pf.statekey = NULL; 1262223637Sbz#endif 1263223637Sbz 1264223637Sbz /* list is sorted, if-bound states before floating ones */ 1265223637Sbz TAILQ_FOREACH(si, &sk->states, entry) 1266223637Sbz#ifdef __FreeBSD__ 1267223637Sbz if ((si->s->kif == V_pfi_all || si->s->kif == kif) && 1268223637Sbz#else 1269223637Sbz if ((si->s->kif == pfi_all || si->s->kif == kif) && 1270223637Sbz#endif 1271223637Sbz sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : 1272223637Sbz si->s->key[PF_SK_STACK])) 1273223637Sbz return (si->s); 1274223637Sbz 1275223637Sbz return (NULL); 1276223637Sbz} 1277223637Sbz 1278223637Sbzstruct pf_state * 1279223637Sbzpf_find_state_all(struct pf_state_key_cmp *key, u_int dir, int *more) 1280223637Sbz{ 1281223637Sbz struct pf_state_key *sk; 1282223637Sbz struct pf_state_item *si, *ret = NULL; 1283223637Sbz 1284223637Sbz#ifdef __FreeBSD__ 1285223637Sbz V_pf_status.fcounters[FCNT_STATE_SEARCH]++; 1286223637Sbz#else 1287223637Sbz pf_status.fcounters[FCNT_STATE_SEARCH]++; 1288223637Sbz#endif 1289223637Sbz 1290223637Sbz#ifdef __FreeBSD__ 1291223637Sbz sk = RB_FIND(pf_state_tree, &V_pf_statetbl, (struct pf_state_key *)key); 1292223637Sbz#else 1293223637Sbz sk = RB_FIND(pf_state_tree, &pf_statetbl, (struct pf_state_key *)key); 1294223637Sbz#endif 1295223637Sbz if (sk != NULL) { 1296223637Sbz TAILQ_FOREACH(si, &sk->states, entry) 1297223637Sbz if (dir == PF_INOUT || 1298223637Sbz (sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : 1299223637Sbz si->s->key[PF_SK_STACK]))) { 1300223637Sbz if (more == NULL) 1301223637Sbz return (si->s); 1302223637Sbz 1303223637Sbz if (ret) 1304223637Sbz (*more)++; 1305223637Sbz else 1306223637Sbz ret = si; 1307223637Sbz } 1308223637Sbz } 1309223637Sbz return (ret ? ret->s : NULL); 1310223637Sbz} 1311223637Sbz 1312223637Sbz/* END state table stuff */ 1313223637Sbz 1314223637Sbz 1315126258Smlaiervoid 1316171168Smlaierpf_purge_thread(void *v) 1317126258Smlaier{ 1318171168Smlaier int nloops = 0, s; 1319196372Smlaier#ifdef __FreeBSD__ 1320196372Smlaier int locked; 1321196372Smlaier#endif 1322171168Smlaier 1323223637Sbz CURVNET_SET((struct vnet *)v); 1324223637Sbz 1325171168Smlaier for (;;) { 1326171168Smlaier tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); 1327171168Smlaier 1328127145Smlaier#ifdef __FreeBSD__ 1329226527Sbz sx_slock(&V_pf_consistency_lock); 1330171168Smlaier PF_LOCK(); 1331226527Sbz locked = 0; 1332126258Smlaier 1333226527Sbz if (V_pf_end_threads) { 1334226527Sbz PF_UNLOCK(); 1335226527Sbz sx_sunlock(&V_pf_consistency_lock); 1336226527Sbz sx_xlock(&V_pf_consistency_lock); 1337226527Sbz PF_LOCK(); 1338171168Smlaier 1339226527Sbz pf_purge_expired_states(V_pf_status.states, 1); 1340226527Sbz pf_purge_expired_fragments(); 1341226527Sbz pf_purge_expired_src_nodes(1); 1342226527Sbz V_pf_end_threads++; 1343226527Sbz 1344226527Sbz sx_xunlock(&V_pf_consistency_lock); 1345226527Sbz PF_UNLOCK(); 1346226527Sbz wakeup(pf_purge_thread); 1347226527Sbz kproc_exit(0); 1348226527Sbz } 1349126261Smlaier#endif 1350171168Smlaier s = splsoftnet(); 1351126258Smlaier 1352171168Smlaier /* process a fraction of the state table every second */ 1353196372Smlaier#ifdef __FreeBSD__ 1354226527Sbz if (!pf_purge_expired_states(1 + (V_pf_status.states / 1355226527Sbz V_pf_default_rule.timeout[PFTM_INTERVAL]), 0)) { 1356226527Sbz PF_UNLOCK(); 1357226527Sbz sx_sunlock(&V_pf_consistency_lock); 1358226527Sbz sx_xlock(&V_pf_consistency_lock); 1359226527Sbz PF_LOCK(); 1360226527Sbz locked = 1; 1361196372Smlaier 1362226527Sbz pf_purge_expired_states(1 + (V_pf_status.states / 1363226527Sbz V_pf_default_rule.timeout[PFTM_INTERVAL]), 1); 1364226527Sbz } 1365196372Smlaier#else 1366171168Smlaier pf_purge_expired_states(1 + (pf_status.states 1367171168Smlaier / pf_default_rule.timeout[PFTM_INTERVAL])); 1368196372Smlaier#endif 1369171168Smlaier 1370171168Smlaier /* purge other expired types every PFTM_INTERVAL seconds */ 1371223637Sbz#ifdef __FreeBSD__ 1372223637Sbz if (++nloops >= V_pf_default_rule.timeout[PFTM_INTERVAL]) { 1373223637Sbz#else 1374171168Smlaier if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { 1375223637Sbz#endif 1376171168Smlaier pf_purge_expired_fragments(); 1377223637Sbz pf_purge_expired_src_nodes(0); 1378171168Smlaier nloops = 0; 1379171168Smlaier } 1380171168Smlaier 1381171168Smlaier splx(s); 1382127145Smlaier#ifdef __FreeBSD__ 1383171168Smlaier PF_UNLOCK(); 1384196372Smlaier if (locked) 1385223637Sbz sx_xunlock(&V_pf_consistency_lock); 1386196372Smlaier else 1387223637Sbz sx_sunlock(&V_pf_consistency_lock); 1388126261Smlaier#endif 1389171168Smlaier } 1390223637Sbz CURVNET_RESTORE(); 1391126258Smlaier} 1392126258Smlaier 1393126258Smlaieru_int32_t 1394126258Smlaierpf_state_expires(const struct pf_state *state) 1395126258Smlaier{ 1396126258Smlaier u_int32_t timeout; 1397126258Smlaier u_int32_t start; 1398126258Smlaier u_int32_t end; 1399126258Smlaier u_int32_t states; 1400126258Smlaier 1401126258Smlaier /* handle all PFTM_* > PFTM_MAX here */ 1402126258Smlaier if (state->timeout == PFTM_PURGE) 1403126261Smlaier return (time_second); 1404126258Smlaier if (state->timeout == PFTM_UNTIL_PACKET) 1405126258Smlaier return (0); 1406223637Sbz#ifdef __FreeBSD__ 1407171168Smlaier KASSERT(state->timeout != PFTM_UNLINKED, 1408171168Smlaier ("pf_state_expires: timeout == PFTM_UNLINKED")); 1409126261Smlaier KASSERT((state->timeout < PFTM_MAX), 1410126261Smlaier ("pf_state_expires: timeout > PFTM_MAX")); 1411126261Smlaier#else 1412171168Smlaier KASSERT(state->timeout != PFTM_UNLINKED); 1413126258Smlaier KASSERT(state->timeout < PFTM_MAX); 1414126261Smlaier#endif 1415126258Smlaier timeout = state->rule.ptr->timeout[state->timeout]; 1416126258Smlaier if (!timeout) 1417223637Sbz#ifdef __FreeBSD__ 1418223637Sbz timeout = V_pf_default_rule.timeout[state->timeout]; 1419223637Sbz#else 1420126258Smlaier timeout = pf_default_rule.timeout[state->timeout]; 1421223637Sbz#endif 1422126258Smlaier start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START]; 1423126258Smlaier if (start) { 1424126258Smlaier end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END]; 1425223637Sbz states = state->rule.ptr->states_cur; 1426126258Smlaier } else { 1427223637Sbz#ifdef __FreeBSD__ 1428223637Sbz start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START]; 1429223637Sbz end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END]; 1430223637Sbz states = V_pf_status.states; 1431223637Sbz#else 1432126258Smlaier start = pf_default_rule.timeout[PFTM_ADAPTIVE_START]; 1433126258Smlaier end = pf_default_rule.timeout[PFTM_ADAPTIVE_END]; 1434126258Smlaier states = pf_status.states; 1435223637Sbz#endif 1436126258Smlaier } 1437126258Smlaier if (end && states > start && start < end) { 1438126258Smlaier if (states < end) 1439126258Smlaier return (state->expire + timeout * (end - states) / 1440126258Smlaier (end - start)); 1441126258Smlaier else 1442126261Smlaier return (time_second); 1443126258Smlaier } 1444126258Smlaier return (state->expire + timeout); 1445126258Smlaier} 1446126258Smlaier 1447196372Smlaier#ifdef __FreeBSD__ 1448196372Smlaierint 1449196372Smlaierpf_purge_expired_src_nodes(int waslocked) 1450196372Smlaier#else 1451126258Smlaiervoid 1452171168Smlaierpf_purge_expired_src_nodes(int waslocked) 1453196372Smlaier#endif 1454126258Smlaier{ 1455223637Sbz struct pf_src_node *cur, *next; 1456223637Sbz int locked = waslocked; 1457126258Smlaier 1458171168Smlaier#ifdef __FreeBSD__ 1459223637Sbz for (cur = RB_MIN(pf_src_tree, &V_tree_src_tracking); cur; cur = next) { 1460223637Sbz next = RB_NEXT(pf_src_tree, &V_tree_src_tracking, cur); 1461171168Smlaier#else 1462223637Sbz for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) { 1463223637Sbz next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); 1464171168Smlaier#endif 1465171168Smlaier 1466223637Sbz if (cur->states <= 0 && cur->expire <= time_second) { 1467223637Sbz if (! locked) { 1468171168Smlaier#ifdef __FreeBSD__ 1469223637Sbz if (!sx_try_upgrade(&V_pf_consistency_lock)) 1470223637Sbz return (0); 1471171168Smlaier#else 1472223637Sbz rw_enter_write(&pf_consistency_lock); 1473171168Smlaier#endif 1474223637Sbz next = RB_NEXT(pf_src_tree, 1475223637Sbz#ifdef __FreeBSD__ 1476223637Sbz &V_tree_src_tracking, cur); 1477223637Sbz#else 1478223637Sbz &tree_src_tracking, cur); 1479223637Sbz#endif 1480223637Sbz locked = 1; 1481223637Sbz } 1482223637Sbz if (cur->rule.ptr != NULL) { 1483223637Sbz cur->rule.ptr->src_nodes--; 1484223637Sbz if (cur->rule.ptr->states_cur <= 0 && 1485223637Sbz cur->rule.ptr->max_src_nodes <= 0) 1486223637Sbz pf_rm_rule(NULL, cur->rule.ptr); 1487223637Sbz } 1488223637Sbz#ifdef __FreeBSD__ 1489223637Sbz RB_REMOVE(pf_src_tree, &V_tree_src_tracking, cur); 1490223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 1491223637Sbz V_pf_status.src_nodes--; 1492223637Sbz pool_put(&V_pf_src_tree_pl, cur); 1493223637Sbz#else 1494223637Sbz RB_REMOVE(pf_src_tree, &tree_src_tracking, cur); 1495223637Sbz pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 1496223637Sbz pf_status.src_nodes--; 1497223637Sbz pool_put(&pf_src_tree_pl, cur); 1498223637Sbz#endif 1499223637Sbz } 1500223637Sbz } 1501196372Smlaier 1502223637Sbz if (locked && !waslocked) 1503196372Smlaier#ifdef __FreeBSD__ 1504223637Sbz { 1505223637Sbz sx_downgrade(&V_pf_consistency_lock); 1506223637Sbz } 1507196372Smlaier return (1); 1508223637Sbz#else 1509223637Sbz rw_exit_write(&pf_consistency_lock); 1510196372Smlaier#endif 1511130613Smlaier} 1512126258Smlaier 1513130613Smlaiervoid 1514130613Smlaierpf_src_tree_remove_state(struct pf_state *s) 1515130613Smlaier{ 1516130613Smlaier u_int32_t timeout; 1517126258Smlaier 1518130613Smlaier if (s->src_node != NULL) { 1519223637Sbz if (s->src.tcp_est) 1520223637Sbz --s->src_node->conn; 1521130613Smlaier if (--s->src_node->states <= 0) { 1522130613Smlaier timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; 1523130613Smlaier if (!timeout) 1524130613Smlaier timeout = 1525223637Sbz#ifdef __FreeBSD__ 1526223637Sbz V_pf_default_rule.timeout[PFTM_SRC_NODE]; 1527223637Sbz#else 1528130613Smlaier pf_default_rule.timeout[PFTM_SRC_NODE]; 1529223637Sbz#endif 1530130613Smlaier s->src_node->expire = time_second + timeout; 1531130613Smlaier } 1532130613Smlaier } 1533130613Smlaier if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) { 1534130613Smlaier if (--s->nat_src_node->states <= 0) { 1535130613Smlaier timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; 1536130613Smlaier if (!timeout) 1537130613Smlaier timeout = 1538223637Sbz#ifdef __FreeBSD__ 1539223637Sbz V_pf_default_rule.timeout[PFTM_SRC_NODE]; 1540223637Sbz#else 1541130613Smlaier pf_default_rule.timeout[PFTM_SRC_NODE]; 1542223637Sbz#endif 1543130613Smlaier s->nat_src_node->expire = time_second + timeout; 1544130613Smlaier } 1545130613Smlaier } 1546130613Smlaier s->src_node = s->nat_src_node = NULL; 1547130613Smlaier} 1548126258Smlaier 1549171168Smlaier/* callers should be at splsoftnet */ 1550130613Smlaiervoid 1551171168Smlaierpf_unlink_state(struct pf_state *cur) 1552145836Smlaier{ 1553148196Smlaier#ifdef __FreeBSD__ 1554153545Smlaier if (cur->local_flags & PFSTATE_EXPIRING) 1555148196Smlaier return; 1556153545Smlaier cur->local_flags |= PFSTATE_EXPIRING; 1557223637Sbz#else 1558223637Sbz splassert(IPL_SOFTNET); 1559148196Smlaier#endif 1560223637Sbz 1561171168Smlaier if (cur->src.state == PF_TCPS_PROXY_DST) { 1562223637Sbz /* XXX wire key the right one? */ 1563162238Scsjp#ifdef __FreeBSD__ 1564223637Sbz pf_send_tcp(NULL, cur->rule.ptr, cur->key[PF_SK_WIRE]->af, 1565162238Scsjp#else 1566223637Sbz pf_send_tcp(cur->rule.ptr, cur->key[PF_SK_WIRE]->af, 1567162238Scsjp#endif 1568223637Sbz &cur->key[PF_SK_WIRE]->addr[1], 1569223637Sbz &cur->key[PF_SK_WIRE]->addr[0], 1570223637Sbz cur->key[PF_SK_WIRE]->port[1], 1571223637Sbz cur->key[PF_SK_WIRE]->port[0], 1572145836Smlaier cur->src.seqhi, cur->src.seqlo + 1, 1573171168Smlaier TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); 1574171168Smlaier } 1575223637Sbz#ifdef __FreeBSD__ 1576223637Sbz RB_REMOVE(pf_state_tree_id, &V_tree_id, cur); 1577223637Sbz#else 1578145836Smlaier RB_REMOVE(pf_state_tree_id, &tree_id, cur); 1579145836Smlaier#endif 1580223637Sbz#if NPFLOW > 0 1581223637Sbz if (cur->state_flags & PFSTATE_PFLOW) 1582223637Sbz#ifdef __FreeBSD__ 1583223637Sbz if (export_pflow_ptr != NULL) 1584223637Sbz export_pflow_ptr(cur); 1585223637Sbz#else 1586223637Sbz export_pflow(cur); 1587223637Sbz#endif 1588223637Sbz#endif 1589223637Sbz#if NPFSYNC > 0 1590223637Sbz#ifdef __FreeBSD__ 1591223637Sbz if (pfsync_delete_state_ptr != NULL) 1592223637Sbz pfsync_delete_state_ptr(cur); 1593223637Sbz#else 1594223637Sbz pfsync_delete_state(cur); 1595223637Sbz#endif 1596223637Sbz#endif 1597171168Smlaier cur->timeout = PFTM_UNLINKED; 1598145836Smlaier pf_src_tree_remove_state(cur); 1599223637Sbz pf_detach_state(cur); 1600171168Smlaier} 1601171168Smlaier 1602171168Smlaier/* callers should be at splsoftnet and hold the 1603171168Smlaier * write_lock on pf_consistency_lock */ 1604171168Smlaiervoid 1605171168Smlaierpf_free_state(struct pf_state *cur) 1606171168Smlaier{ 1607223637Sbz#ifndef __FreeBSD__ 1608223637Sbz splassert(IPL_SOFTNET); 1609223637Sbz#endif 1610223637Sbz 1611223637Sbz#if NPFSYNC > 0 1612223637Sbz#ifdef __FreeBSD__ 1613226530Sbz if (pfsync_state_in_use_ptr != NULL && 1614226530Sbz pfsync_state_in_use_ptr(cur)) 1615223637Sbz#else 1616223637Sbz if (pfsync_state_in_use(cur)) 1617223637Sbz#endif 1618171168Smlaier return; 1619171168Smlaier#endif 1620171168Smlaier#ifdef __FreeBSD__ 1621171168Smlaier KASSERT(cur->timeout == PFTM_UNLINKED, 1622171168Smlaier ("pf_free_state: cur->timeout != PFTM_UNLINKED")); 1623171168Smlaier#else 1624171168Smlaier KASSERT(cur->timeout == PFTM_UNLINKED); 1625171168Smlaier#endif 1626223637Sbz if (--cur->rule.ptr->states_cur <= 0 && 1627145836Smlaier cur->rule.ptr->src_nodes <= 0) 1628145836Smlaier pf_rm_rule(NULL, cur->rule.ptr); 1629145836Smlaier if (cur->nat_rule.ptr != NULL) 1630223637Sbz if (--cur->nat_rule.ptr->states_cur <= 0 && 1631145836Smlaier cur->nat_rule.ptr->src_nodes <= 0) 1632145836Smlaier pf_rm_rule(NULL, cur->nat_rule.ptr); 1633145836Smlaier if (cur->anchor.ptr != NULL) 1634223637Sbz if (--cur->anchor.ptr->states_cur <= 0) 1635145836Smlaier pf_rm_rule(NULL, cur->anchor.ptr); 1636145836Smlaier pf_normalize_tcp_cleanup(cur); 1637223637Sbz pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE); 1638223637Sbz#ifdef __FreeBSD__ 1639223637Sbz TAILQ_REMOVE(&V_state_list, cur, entry_list); 1640223637Sbz#else 1641223637Sbz TAILQ_REMOVE(&state_list, cur, entry_list); 1642223637Sbz#endif 1643145836Smlaier if (cur->tag) 1644145836Smlaier pf_tag_unref(cur->tag); 1645223637Sbz#ifdef __FreeBSD__ 1646223637Sbz pool_put(&V_pf_state_pl, cur); 1647223637Sbz V_pf_status.fcounters[FCNT_STATE_REMOVALS]++; 1648223637Sbz V_pf_status.states--; 1649223637Sbz#else 1650145836Smlaier pool_put(&pf_state_pl, cur); 1651145836Smlaier pf_status.fcounters[FCNT_STATE_REMOVALS]++; 1652145836Smlaier pf_status.states--; 1653223637Sbz#endif 1654145836Smlaier} 1655145836Smlaier 1656196372Smlaier#ifdef __FreeBSD__ 1657196372Smlaierint 1658196372Smlaierpf_purge_expired_states(u_int32_t maxcheck, int waslocked) 1659196372Smlaier#else 1660145836Smlaiervoid 1661171168Smlaierpf_purge_expired_states(u_int32_t maxcheck) 1662196372Smlaier#endif 1663130613Smlaier{ 1664171168Smlaier static struct pf_state *cur = NULL; 1665171168Smlaier struct pf_state *next; 1666196372Smlaier#ifdef __FreeBSD__ 1667223637Sbz int locked = waslocked; 1668196372Smlaier#else 1669223637Sbz int locked = 0; 1670196372Smlaier#endif 1671130613Smlaier 1672171168Smlaier while (maxcheck--) { 1673171168Smlaier /* wrap to start of list when we hit the end */ 1674171168Smlaier if (cur == NULL) { 1675223637Sbz#ifdef __FreeBSD__ 1676223637Sbz cur = TAILQ_FIRST(&V_state_list); 1677223637Sbz#else 1678171168Smlaier cur = TAILQ_FIRST(&state_list); 1679223637Sbz#endif 1680171168Smlaier if (cur == NULL) 1681171168Smlaier break; /* list empty */ 1682171168Smlaier } 1683171168Smlaier 1684171168Smlaier /* get next state, as cur may get deleted */ 1685223637Sbz next = TAILQ_NEXT(cur, entry_list); 1686171168Smlaier 1687171168Smlaier if (cur->timeout == PFTM_UNLINKED) { 1688171168Smlaier /* free unlinked state */ 1689171168Smlaier if (! locked) { 1690171168Smlaier#ifdef __FreeBSD__ 1691223637Sbz if (!sx_try_upgrade(&V_pf_consistency_lock)) 1692223637Sbz return (0); 1693171168Smlaier#else 1694171168Smlaier rw_enter_write(&pf_consistency_lock); 1695171168Smlaier#endif 1696171168Smlaier locked = 1; 1697171168Smlaier } 1698171168Smlaier pf_free_state(cur); 1699171168Smlaier } else if (pf_state_expires(cur) <= time_second) { 1700171168Smlaier /* unlink and free expired state */ 1701171168Smlaier pf_unlink_state(cur); 1702171168Smlaier if (! locked) { 1703171168Smlaier#ifdef __FreeBSD__ 1704223637Sbz if (!sx_try_upgrade(&V_pf_consistency_lock)) 1705223637Sbz return (0); 1706171168Smlaier#else 1707171168Smlaier rw_enter_write(&pf_consistency_lock); 1708171168Smlaier#endif 1709171168Smlaier locked = 1; 1710171168Smlaier } 1711171168Smlaier pf_free_state(cur); 1712171168Smlaier } 1713171168Smlaier cur = next; 1714126258Smlaier } 1715171168Smlaier 1716171168Smlaier#ifdef __FreeBSD__ 1717196372Smlaier if (!waslocked && locked) 1718223637Sbz sx_downgrade(&V_pf_consistency_lock); 1719196372Smlaier 1720196372Smlaier return (1); 1721171168Smlaier#else 1722196372Smlaier if (locked) 1723171168Smlaier rw_exit_write(&pf_consistency_lock); 1724171168Smlaier#endif 1725126258Smlaier} 1726126258Smlaier 1727126258Smlaierint 1728126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw) 1729126258Smlaier{ 1730126258Smlaier if (aw->type != PF_ADDR_TABLE) 1731126258Smlaier return (0); 1732223637Sbz if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname, 1)) == NULL) 1733126258Smlaier return (1); 1734126258Smlaier return (0); 1735126258Smlaier} 1736126258Smlaier 1737126258Smlaiervoid 1738126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw) 1739126258Smlaier{ 1740126258Smlaier if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL) 1741126258Smlaier return; 1742126258Smlaier pfr_detach_table(aw->p.tbl); 1743126258Smlaier aw->p.tbl = NULL; 1744126258Smlaier} 1745126258Smlaier 1746126258Smlaiervoid 1747126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw) 1748126258Smlaier{ 1749126258Smlaier struct pfr_ktable *kt = aw->p.tbl; 1750126258Smlaier 1751126258Smlaier if (aw->type != PF_ADDR_TABLE || kt == NULL) 1752126258Smlaier return; 1753126258Smlaier if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) 1754126258Smlaier kt = kt->pfrkt_root; 1755126258Smlaier aw->p.tbl = NULL; 1756126258Smlaier aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ? 1757126258Smlaier kt->pfrkt_cnt : -1; 1758126258Smlaier} 1759126258Smlaier 1760126258Smlaiervoid 1761126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) 1762126258Smlaier{ 1763126258Smlaier switch (af) { 1764126258Smlaier#ifdef INET 1765126258Smlaier case AF_INET: { 1766126258Smlaier u_int32_t a = ntohl(addr->addr32[0]); 1767126258Smlaier printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, 1768126258Smlaier (a>>8)&255, a&255); 1769126258Smlaier if (p) { 1770126258Smlaier p = ntohs(p); 1771126258Smlaier printf(":%u", p); 1772126258Smlaier } 1773126258Smlaier break; 1774126258Smlaier } 1775126258Smlaier#endif /* INET */ 1776126258Smlaier#ifdef INET6 1777126258Smlaier case AF_INET6: { 1778126258Smlaier u_int16_t b; 1779223637Sbz u_int8_t i, curstart, curend, maxstart, maxend; 1780223637Sbz curstart = curend = maxstart = maxend = 255; 1781126258Smlaier for (i = 0; i < 8; i++) { 1782126258Smlaier if (!addr->addr16[i]) { 1783126258Smlaier if (curstart == 255) 1784126258Smlaier curstart = i; 1785223637Sbz curend = i; 1786126258Smlaier } else { 1787223637Sbz if ((curend - curstart) > 1788223637Sbz (maxend - maxstart)) { 1789223637Sbz maxstart = curstart; 1790223637Sbz maxend = curend; 1791126258Smlaier } 1792223637Sbz curstart = curend = 255; 1793126258Smlaier } 1794126258Smlaier } 1795223637Sbz if ((curend - curstart) > 1796223637Sbz (maxend - maxstart)) { 1797223637Sbz maxstart = curstart; 1798223637Sbz maxend = curend; 1799223637Sbz } 1800126258Smlaier for (i = 0; i < 8; i++) { 1801126258Smlaier if (i >= maxstart && i <= maxend) { 1802223637Sbz if (i == 0) 1803223637Sbz printf(":"); 1804223637Sbz if (i == maxend) 1805223637Sbz printf(":"); 1806126258Smlaier } else { 1807126258Smlaier b = ntohs(addr->addr16[i]); 1808126258Smlaier printf("%x", b); 1809126258Smlaier if (i < 7) 1810126258Smlaier printf(":"); 1811126258Smlaier } 1812126258Smlaier } 1813126258Smlaier if (p) { 1814126258Smlaier p = ntohs(p); 1815126258Smlaier printf("[%u]", p); 1816126258Smlaier } 1817126258Smlaier break; 1818126258Smlaier } 1819126258Smlaier#endif /* INET6 */ 1820126258Smlaier } 1821126258Smlaier} 1822126258Smlaier 1823126258Smlaiervoid 1824126258Smlaierpf_print_state(struct pf_state *s) 1825126258Smlaier{ 1826223637Sbz pf_print_state_parts(s, NULL, NULL); 1827223637Sbz} 1828223637Sbz 1829223637Sbzvoid 1830223637Sbzpf_print_state_parts(struct pf_state *s, 1831223637Sbz struct pf_state_key *skwp, struct pf_state_key *sksp) 1832223637Sbz{ 1833223637Sbz struct pf_state_key *skw, *sks; 1834223637Sbz u_int8_t proto, dir; 1835223637Sbz 1836223637Sbz /* Do our best to fill these, but they're skipped if NULL */ 1837223637Sbz skw = skwp ? skwp : (s ? s->key[PF_SK_WIRE] : NULL); 1838223637Sbz sks = sksp ? sksp : (s ? s->key[PF_SK_STACK] : NULL); 1839223637Sbz proto = skw ? skw->proto : (sks ? sks->proto : 0); 1840223637Sbz dir = s ? s->direction : 0; 1841223637Sbz 1842223637Sbz switch (proto) { 1843223637Sbz case IPPROTO_IPV4: 1844223637Sbz printf("IPv4"); 1845223637Sbz break; 1846223637Sbz case IPPROTO_IPV6: 1847223637Sbz printf("IPv6"); 1848223637Sbz break; 1849126258Smlaier case IPPROTO_TCP: 1850223637Sbz printf("TCP"); 1851126258Smlaier break; 1852126258Smlaier case IPPROTO_UDP: 1853223637Sbz printf("UDP"); 1854126258Smlaier break; 1855126258Smlaier case IPPROTO_ICMP: 1856223637Sbz printf("ICMP"); 1857126258Smlaier break; 1858126258Smlaier case IPPROTO_ICMPV6: 1859223637Sbz printf("ICMPv6"); 1860126258Smlaier break; 1861126258Smlaier default: 1862223637Sbz printf("%u", skw->proto); 1863126258Smlaier break; 1864126258Smlaier } 1865223637Sbz switch (dir) { 1866223637Sbz case PF_IN: 1867223637Sbz printf(" in"); 1868223637Sbz break; 1869223637Sbz case PF_OUT: 1870223637Sbz printf(" out"); 1871223637Sbz break; 1872223637Sbz } 1873223637Sbz if (skw) { 1874223637Sbz printf(" wire: "); 1875223637Sbz pf_print_host(&skw->addr[0], skw->port[0], skw->af); 1876223637Sbz printf(" "); 1877223637Sbz pf_print_host(&skw->addr[1], skw->port[1], skw->af); 1878223637Sbz } 1879223637Sbz if (sks) { 1880223637Sbz printf(" stack: "); 1881223637Sbz if (sks != skw) { 1882223637Sbz pf_print_host(&sks->addr[0], sks->port[0], sks->af); 1883223637Sbz printf(" "); 1884223637Sbz pf_print_host(&sks->addr[1], sks->port[1], sks->af); 1885223637Sbz } else 1886223637Sbz printf("-"); 1887223637Sbz } 1888223637Sbz if (s) { 1889223637Sbz if (proto == IPPROTO_TCP) { 1890223637Sbz printf(" [lo=%u high=%u win=%u modulator=%u", 1891223637Sbz s->src.seqlo, s->src.seqhi, 1892223637Sbz s->src.max_win, s->src.seqdiff); 1893223637Sbz if (s->src.wscale && s->dst.wscale) 1894223637Sbz printf(" wscale=%u", 1895223637Sbz s->src.wscale & PF_WSCALE_MASK); 1896223637Sbz printf("]"); 1897223637Sbz printf(" [lo=%u high=%u win=%u modulator=%u", 1898223637Sbz s->dst.seqlo, s->dst.seqhi, 1899223637Sbz s->dst.max_win, s->dst.seqdiff); 1900223637Sbz if (s->src.wscale && s->dst.wscale) 1901223637Sbz printf(" wscale=%u", 1902223637Sbz s->dst.wscale & PF_WSCALE_MASK); 1903223637Sbz printf("]"); 1904223637Sbz } 1905223637Sbz printf(" %u:%u", s->src.state, s->dst.state); 1906223637Sbz } 1907126258Smlaier} 1908126258Smlaier 1909126258Smlaiervoid 1910126258Smlaierpf_print_flags(u_int8_t f) 1911126258Smlaier{ 1912126258Smlaier if (f) 1913126258Smlaier printf(" "); 1914126258Smlaier if (f & TH_FIN) 1915126258Smlaier printf("F"); 1916126258Smlaier if (f & TH_SYN) 1917126258Smlaier printf("S"); 1918126258Smlaier if (f & TH_RST) 1919126258Smlaier printf("R"); 1920126258Smlaier if (f & TH_PUSH) 1921126258Smlaier printf("P"); 1922126258Smlaier if (f & TH_ACK) 1923126258Smlaier printf("A"); 1924126258Smlaier if (f & TH_URG) 1925126258Smlaier printf("U"); 1926126258Smlaier if (f & TH_ECE) 1927126258Smlaier printf("E"); 1928126258Smlaier if (f & TH_CWR) 1929126258Smlaier printf("W"); 1930126258Smlaier} 1931126258Smlaier 1932126258Smlaier#define PF_SET_SKIP_STEPS(i) \ 1933126258Smlaier do { \ 1934126258Smlaier while (head[i] != cur) { \ 1935126258Smlaier head[i]->skip[i].ptr = cur; \ 1936126258Smlaier head[i] = TAILQ_NEXT(head[i], entries); \ 1937126258Smlaier } \ 1938126258Smlaier } while (0) 1939126258Smlaier 1940126258Smlaiervoid 1941126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules) 1942126258Smlaier{ 1943126258Smlaier struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT]; 1944126258Smlaier int i; 1945126258Smlaier 1946126258Smlaier cur = TAILQ_FIRST(rules); 1947126258Smlaier prev = cur; 1948126258Smlaier for (i = 0; i < PF_SKIP_COUNT; ++i) 1949126258Smlaier head[i] = cur; 1950126258Smlaier while (cur != NULL) { 1951126258Smlaier 1952130613Smlaier if (cur->kif != prev->kif || cur->ifnot != prev->ifnot) 1953126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_IFP); 1954126258Smlaier if (cur->direction != prev->direction) 1955126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_DIR); 1956126258Smlaier if (cur->af != prev->af) 1957126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_AF); 1958126258Smlaier if (cur->proto != prev->proto) 1959126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_PROTO); 1960145836Smlaier if (cur->src.neg != prev->src.neg || 1961126258Smlaier pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr)) 1962126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR); 1963126258Smlaier if (cur->src.port[0] != prev->src.port[0] || 1964126258Smlaier cur->src.port[1] != prev->src.port[1] || 1965126258Smlaier cur->src.port_op != prev->src.port_op) 1966126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT); 1967145836Smlaier if (cur->dst.neg != prev->dst.neg || 1968126258Smlaier pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr)) 1969126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR); 1970126258Smlaier if (cur->dst.port[0] != prev->dst.port[0] || 1971126258Smlaier cur->dst.port[1] != prev->dst.port[1] || 1972126258Smlaier cur->dst.port_op != prev->dst.port_op) 1973126258Smlaier PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT); 1974126258Smlaier 1975126258Smlaier prev = cur; 1976126258Smlaier cur = TAILQ_NEXT(cur, entries); 1977126258Smlaier } 1978126258Smlaier for (i = 0; i < PF_SKIP_COUNT; ++i) 1979126258Smlaier PF_SET_SKIP_STEPS(i); 1980126258Smlaier} 1981126258Smlaier 1982126258Smlaierint 1983126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) 1984126258Smlaier{ 1985126258Smlaier if (aw1->type != aw2->type) 1986126258Smlaier return (1); 1987126258Smlaier switch (aw1->type) { 1988126258Smlaier case PF_ADDR_ADDRMASK: 1989223637Sbz case PF_ADDR_RANGE: 1990126258Smlaier if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0)) 1991126258Smlaier return (1); 1992126258Smlaier if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0)) 1993126258Smlaier return (1); 1994126258Smlaier return (0); 1995126258Smlaier case PF_ADDR_DYNIFTL: 1996130613Smlaier return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt); 1997126258Smlaier case PF_ADDR_NOROUTE: 1998171168Smlaier case PF_ADDR_URPFFAILED: 1999126258Smlaier return (0); 2000126258Smlaier case PF_ADDR_TABLE: 2001126258Smlaier return (aw1->p.tbl != aw2->p.tbl); 2002171168Smlaier case PF_ADDR_RTLABEL: 2003171168Smlaier return (aw1->v.rtlabel != aw2->v.rtlabel); 2004126258Smlaier default: 2005126258Smlaier printf("invalid address type: %d\n", aw1->type); 2006126258Smlaier return (1); 2007126258Smlaier } 2008126258Smlaier} 2009126258Smlaier 2010126258Smlaieru_int16_t 2011126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp) 2012126258Smlaier{ 2013126258Smlaier u_int32_t l; 2014126258Smlaier 2015126258Smlaier if (udp && !cksum) 2016126258Smlaier return (0x0000); 2017126258Smlaier l = cksum + old - new; 2018126258Smlaier l = (l >> 16) + (l & 65535); 2019126258Smlaier l = l & 65535; 2020126258Smlaier if (udp && !l) 2021126258Smlaier return (0xFFFF); 2022126258Smlaier return (l); 2023126258Smlaier} 2024126258Smlaier 2025126258Smlaiervoid 2026126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc, 2027126258Smlaier struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af) 2028126258Smlaier{ 2029126258Smlaier struct pf_addr ao; 2030126258Smlaier u_int16_t po = *p; 2031126258Smlaier 2032126258Smlaier PF_ACPY(&ao, a, af); 2033126258Smlaier PF_ACPY(a, an, af); 2034126258Smlaier 2035126258Smlaier *p = pn; 2036126258Smlaier 2037126258Smlaier switch (af) { 2038126258Smlaier#ifdef INET 2039126258Smlaier case AF_INET: 2040126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, 2041126258Smlaier ao.addr16[0], an->addr16[0], 0), 2042126258Smlaier ao.addr16[1], an->addr16[1], 0); 2043126258Smlaier *p = pn; 2044126258Smlaier *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, 2045126258Smlaier ao.addr16[0], an->addr16[0], u), 2046126258Smlaier ao.addr16[1], an->addr16[1], u), 2047126258Smlaier po, pn, u); 2048126258Smlaier break; 2049126258Smlaier#endif /* INET */ 2050126258Smlaier#ifdef INET6 2051126258Smlaier case AF_INET6: 2052126258Smlaier *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2053126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2054126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, 2055126258Smlaier ao.addr16[0], an->addr16[0], u), 2056126258Smlaier ao.addr16[1], an->addr16[1], u), 2057126258Smlaier ao.addr16[2], an->addr16[2], u), 2058126258Smlaier ao.addr16[3], an->addr16[3], u), 2059126258Smlaier ao.addr16[4], an->addr16[4], u), 2060126258Smlaier ao.addr16[5], an->addr16[5], u), 2061126258Smlaier ao.addr16[6], an->addr16[6], u), 2062126258Smlaier ao.addr16[7], an->addr16[7], u), 2063126258Smlaier po, pn, u); 2064126258Smlaier break; 2065126258Smlaier#endif /* INET6 */ 2066126258Smlaier } 2067126258Smlaier} 2068126258Smlaier 2069126258Smlaier 2070126258Smlaier/* Changes a u_int32_t. Uses a void * so there are no align restrictions */ 2071126258Smlaiervoid 2072126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u) 2073126258Smlaier{ 2074126258Smlaier u_int32_t ao; 2075126258Smlaier 2076126258Smlaier memcpy(&ao, a, sizeof(ao)); 2077126258Smlaier memcpy(a, &an, sizeof(u_int32_t)); 2078126258Smlaier *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u), 2079126258Smlaier ao % 65536, an % 65536, u); 2080126258Smlaier} 2081126258Smlaier 2082126258Smlaier#ifdef INET6 2083126258Smlaiervoid 2084126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) 2085126258Smlaier{ 2086126258Smlaier struct pf_addr ao; 2087126258Smlaier 2088126258Smlaier PF_ACPY(&ao, a, AF_INET6); 2089126258Smlaier PF_ACPY(a, an, AF_INET6); 2090126258Smlaier 2091126258Smlaier *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2092126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2093126258Smlaier pf_cksum_fixup(pf_cksum_fixup(*c, 2094126258Smlaier ao.addr16[0], an->addr16[0], u), 2095126258Smlaier ao.addr16[1], an->addr16[1], u), 2096126258Smlaier ao.addr16[2], an->addr16[2], u), 2097126258Smlaier ao.addr16[3], an->addr16[3], u), 2098126258Smlaier ao.addr16[4], an->addr16[4], u), 2099126258Smlaier ao.addr16[5], an->addr16[5], u), 2100126258Smlaier ao.addr16[6], an->addr16[6], u), 2101126258Smlaier ao.addr16[7], an->addr16[7], u); 2102126258Smlaier} 2103126258Smlaier#endif /* INET6 */ 2104126258Smlaier 2105126258Smlaiervoid 2106126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, 2107126258Smlaier struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c, 2108126258Smlaier u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af) 2109126258Smlaier{ 2110126258Smlaier struct pf_addr oia, ooa; 2111126258Smlaier 2112126258Smlaier PF_ACPY(&oia, ia, af); 2113223637Sbz if (oa) 2114223637Sbz PF_ACPY(&ooa, oa, af); 2115126258Smlaier 2116126258Smlaier /* Change inner protocol port, fix inner protocol checksum. */ 2117126258Smlaier if (ip != NULL) { 2118126258Smlaier u_int16_t oip = *ip; 2119223637Sbz u_int32_t opc; 2120126258Smlaier 2121126258Smlaier if (pc != NULL) 2122126258Smlaier opc = *pc; 2123126258Smlaier *ip = np; 2124126258Smlaier if (pc != NULL) 2125126258Smlaier *pc = pf_cksum_fixup(*pc, oip, *ip, u); 2126126258Smlaier *ic = pf_cksum_fixup(*ic, oip, *ip, 0); 2127126258Smlaier if (pc != NULL) 2128126258Smlaier *ic = pf_cksum_fixup(*ic, opc, *pc, 0); 2129126258Smlaier } 2130126258Smlaier /* Change inner ip address, fix inner ip and icmp checksums. */ 2131126258Smlaier PF_ACPY(ia, na, af); 2132126258Smlaier switch (af) { 2133126258Smlaier#ifdef INET 2134126258Smlaier case AF_INET: { 2135126258Smlaier u_int32_t oh2c = *h2c; 2136126258Smlaier 2137126258Smlaier *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c, 2138126258Smlaier oia.addr16[0], ia->addr16[0], 0), 2139126258Smlaier oia.addr16[1], ia->addr16[1], 0); 2140126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, 2141126258Smlaier oia.addr16[0], ia->addr16[0], 0), 2142126258Smlaier oia.addr16[1], ia->addr16[1], 0); 2143126258Smlaier *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0); 2144126258Smlaier break; 2145126258Smlaier } 2146126258Smlaier#endif /* INET */ 2147126258Smlaier#ifdef INET6 2148126258Smlaier case AF_INET6: 2149126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2150126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2151126258Smlaier pf_cksum_fixup(pf_cksum_fixup(*ic, 2152126258Smlaier oia.addr16[0], ia->addr16[0], u), 2153126258Smlaier oia.addr16[1], ia->addr16[1], u), 2154126258Smlaier oia.addr16[2], ia->addr16[2], u), 2155126258Smlaier oia.addr16[3], ia->addr16[3], u), 2156126258Smlaier oia.addr16[4], ia->addr16[4], u), 2157126258Smlaier oia.addr16[5], ia->addr16[5], u), 2158126258Smlaier oia.addr16[6], ia->addr16[6], u), 2159126258Smlaier oia.addr16[7], ia->addr16[7], u); 2160126258Smlaier break; 2161126258Smlaier#endif /* INET6 */ 2162126258Smlaier } 2163223637Sbz /* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */ 2164223637Sbz if (oa) { 2165223637Sbz PF_ACPY(oa, na, af); 2166223637Sbz switch (af) { 2167126258Smlaier#ifdef INET 2168223637Sbz case AF_INET: 2169223637Sbz *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, 2170223637Sbz ooa.addr16[0], oa->addr16[0], 0), 2171223637Sbz ooa.addr16[1], oa->addr16[1], 0); 2172223637Sbz break; 2173126258Smlaier#endif /* INET */ 2174126258Smlaier#ifdef INET6 2175223637Sbz case AF_INET6: 2176223637Sbz *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2177223637Sbz pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2178223637Sbz pf_cksum_fixup(pf_cksum_fixup(*ic, 2179223637Sbz ooa.addr16[0], oa->addr16[0], u), 2180223637Sbz ooa.addr16[1], oa->addr16[1], u), 2181223637Sbz ooa.addr16[2], oa->addr16[2], u), 2182223637Sbz ooa.addr16[3], oa->addr16[3], u), 2183223637Sbz ooa.addr16[4], oa->addr16[4], u), 2184223637Sbz ooa.addr16[5], oa->addr16[5], u), 2185223637Sbz ooa.addr16[6], oa->addr16[6], u), 2186223637Sbz ooa.addr16[7], oa->addr16[7], u); 2187223637Sbz break; 2188126258Smlaier#endif /* INET6 */ 2189223637Sbz } 2190126258Smlaier } 2191126258Smlaier} 2192126258Smlaier 2193171168Smlaier 2194171168Smlaier/* 2195171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option 2196171168Smlaier * (credits to Krzysztof Pfaff for report and patch) 2197171168Smlaier */ 2198171168Smlaierint 2199171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd, 2200171168Smlaier struct tcphdr *th, struct pf_state_peer *dst) 2201171168Smlaier{ 2202171168Smlaier int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen; 2203171168Smlaier#ifdef __FreeBSD__ 2204171168Smlaier u_int8_t opts[TCP_MAXOLEN], *opt = opts; 2205171168Smlaier#else 2206171168Smlaier u_int8_t opts[MAX_TCPOPTLEN], *opt = opts; 2207171168Smlaier#endif 2208171168Smlaier int copyback = 0, i, olen; 2209171168Smlaier struct sackblk sack; 2210171168Smlaier 2211223637Sbz#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) 2212171168Smlaier if (hlen < TCPOLEN_SACKLEN || 2213171168Smlaier !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af)) 2214171168Smlaier return 0; 2215171168Smlaier 2216171168Smlaier while (hlen >= TCPOLEN_SACKLEN) { 2217171168Smlaier olen = opt[1]; 2218171168Smlaier switch (*opt) { 2219171168Smlaier case TCPOPT_EOL: /* FALLTHROUGH */ 2220171168Smlaier case TCPOPT_NOP: 2221171168Smlaier opt++; 2222171168Smlaier hlen--; 2223171168Smlaier break; 2224171168Smlaier case TCPOPT_SACK: 2225171168Smlaier if (olen > hlen) 2226171168Smlaier olen = hlen; 2227171168Smlaier if (olen >= TCPOLEN_SACKLEN) { 2228171168Smlaier for (i = 2; i + TCPOLEN_SACK <= olen; 2229171168Smlaier i += TCPOLEN_SACK) { 2230171168Smlaier memcpy(&sack, &opt[i], sizeof(sack)); 2231171168Smlaier pf_change_a(&sack.start, &th->th_sum, 2232171168Smlaier htonl(ntohl(sack.start) - 2233171168Smlaier dst->seqdiff), 0); 2234171168Smlaier pf_change_a(&sack.end, &th->th_sum, 2235171168Smlaier htonl(ntohl(sack.end) - 2236171168Smlaier dst->seqdiff), 0); 2237171168Smlaier memcpy(&opt[i], &sack, sizeof(sack)); 2238171168Smlaier } 2239171168Smlaier copyback = 1; 2240171168Smlaier } 2241171168Smlaier /* FALLTHROUGH */ 2242171168Smlaier default: 2243171168Smlaier if (olen < 2) 2244171168Smlaier olen = 2; 2245171168Smlaier hlen -= olen; 2246171168Smlaier opt += olen; 2247171168Smlaier } 2248171168Smlaier } 2249171168Smlaier 2250171168Smlaier if (copyback) 2251171168Smlaier#ifdef __FreeBSD__ 2252171168Smlaier m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts); 2253171168Smlaier#else 2254171168Smlaier m_copyback(m, off + sizeof(*th), thoptlen, opts); 2255171168Smlaier#endif 2256171168Smlaier return (copyback); 2257171168Smlaier} 2258171168Smlaier 2259126258Smlaiervoid 2260162238Scsjp#ifdef __FreeBSD__ 2261162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, 2262162238Scsjp#else 2263126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af, 2264162238Scsjp#endif 2265126258Smlaier const struct pf_addr *saddr, const struct pf_addr *daddr, 2266126258Smlaier u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, 2267145836Smlaier u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag, 2268171168Smlaier u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp) 2269126258Smlaier{ 2270126258Smlaier struct mbuf *m; 2271171168Smlaier int len, tlen; 2272126258Smlaier#ifdef INET 2273171168Smlaier struct ip *h; 2274126258Smlaier#endif /* INET */ 2275126258Smlaier#ifdef INET6 2276171168Smlaier struct ip6_hdr *h6; 2277126258Smlaier#endif /* INET6 */ 2278171168Smlaier struct tcphdr *th; 2279171168Smlaier char *opt; 2280223637Sbz#ifdef __FreeBSD__ 2281223637Sbz struct pf_mtag *pf_mtag; 2282126258Smlaier 2283171168Smlaier KASSERT( 2284171168Smlaier#ifdef INET 2285171168Smlaier af == AF_INET 2286171168Smlaier#else 2287171168Smlaier 0 2288171168Smlaier#endif 2289171168Smlaier || 2290171168Smlaier#ifdef INET6 2291171168Smlaier af == AF_INET6 2292171168Smlaier#else 2293171168Smlaier 0 2294171168Smlaier#endif 2295171168Smlaier , ("Unsupported AF %d", af)); 2296171168Smlaier len = 0; 2297171168Smlaier th = NULL; 2298171168Smlaier#ifdef INET 2299171168Smlaier h = NULL; 2300171168Smlaier#endif 2301171168Smlaier#ifdef INET6 2302171168Smlaier h6 = NULL; 2303171168Smlaier#endif 2304223637Sbz#endif /* __FreeBSD__ */ 2305171168Smlaier 2306126258Smlaier /* maximum segment size tcp option */ 2307126258Smlaier tlen = sizeof(struct tcphdr); 2308126258Smlaier if (mss) 2309126258Smlaier tlen += 4; 2310126258Smlaier 2311126258Smlaier switch (af) { 2312126258Smlaier#ifdef INET 2313126258Smlaier case AF_INET: 2314126258Smlaier len = sizeof(struct ip) + tlen; 2315126258Smlaier break; 2316126258Smlaier#endif /* INET */ 2317126258Smlaier#ifdef INET6 2318126258Smlaier case AF_INET6: 2319126258Smlaier len = sizeof(struct ip6_hdr) + tlen; 2320126258Smlaier break; 2321126258Smlaier#endif /* INET6 */ 2322126258Smlaier } 2323126258Smlaier 2324126258Smlaier /* create outgoing mbuf */ 2325132280Smlaier m = m_gethdr(M_DONTWAIT, MT_HEADER); 2326132280Smlaier if (m == NULL) 2327132280Smlaier return; 2328162238Scsjp#ifdef __FreeBSD__ 2329162238Scsjp#ifdef MAC 2330223637Sbz mac_netinet_firewall_send(m); 2331162238Scsjp#endif 2332171168Smlaier if ((pf_mtag = pf_get_mtag(m)) == NULL) { 2333171168Smlaier m_freem(m); 2334171168Smlaier return; 2335171168Smlaier } 2336223637Sbz#endif 2337171168Smlaier if (tag) 2338145836Smlaier#ifdef __FreeBSD__ 2339145836Smlaier m->m_flags |= M_SKIP_FIREWALL; 2340223637Sbz pf_mtag->tag = rtag; 2341132280Smlaier#else 2342223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2343223637Sbz m->m_pkthdr.pf.tag = rtag; 2344171168Smlaier#endif 2345145836Smlaier 2346171168Smlaier if (r != NULL && r->rtableid >= 0) 2347178888Sjulian#ifdef __FreeBSD__ 2348178888Sjulian { 2349178888Sjulian M_SETFIB(m, r->rtableid); 2350223637Sbz pf_mtag->rtableid = r->rtableid; 2351223637Sbz#else 2352223637Sbz m->m_pkthdr.pf.rtableid = r->rtableid; 2353178888Sjulian#endif 2354178888Sjulian#ifdef __FreeBSD__ 2355178888Sjulian } 2356178888Sjulian#endif 2357223637Sbz 2358126258Smlaier#ifdef ALTQ 2359126258Smlaier if (r != NULL && r->qid) { 2360223637Sbz#ifdef __FreeBSD__ 2361171168Smlaier pf_mtag->qid = r->qid; 2362223637Sbz 2363171168Smlaier /* add hints for ecn */ 2364171168Smlaier pf_mtag->hdr = mtod(m, struct ip *); 2365223637Sbz#else 2366223637Sbz m->m_pkthdr.pf.qid = r->qid; 2367223637Sbz /* add hints for ecn */ 2368223637Sbz m->m_pkthdr.pf.hdr = mtod(m, struct ip *); 2369223637Sbz#endif 2370126258Smlaier } 2371145836Smlaier#endif /* ALTQ */ 2372126258Smlaier m->m_data += max_linkhdr; 2373126258Smlaier m->m_pkthdr.len = m->m_len = len; 2374126258Smlaier m->m_pkthdr.rcvif = NULL; 2375126258Smlaier bzero(m->m_data, len); 2376126258Smlaier switch (af) { 2377126258Smlaier#ifdef INET 2378126258Smlaier case AF_INET: 2379126258Smlaier h = mtod(m, struct ip *); 2380126258Smlaier 2381126258Smlaier /* IP header fields included in the TCP checksum */ 2382126258Smlaier h->ip_p = IPPROTO_TCP; 2383126258Smlaier h->ip_len = htons(tlen); 2384126258Smlaier h->ip_src.s_addr = saddr->v4.s_addr; 2385126258Smlaier h->ip_dst.s_addr = daddr->v4.s_addr; 2386126258Smlaier 2387126258Smlaier th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip)); 2388126258Smlaier break; 2389126258Smlaier#endif /* INET */ 2390126258Smlaier#ifdef INET6 2391126258Smlaier case AF_INET6: 2392126258Smlaier h6 = mtod(m, struct ip6_hdr *); 2393126258Smlaier 2394126258Smlaier /* IP header fields included in the TCP checksum */ 2395126258Smlaier h6->ip6_nxt = IPPROTO_TCP; 2396126258Smlaier h6->ip6_plen = htons(tlen); 2397126258Smlaier memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr)); 2398126258Smlaier memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr)); 2399126258Smlaier 2400126258Smlaier th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr)); 2401126258Smlaier break; 2402126258Smlaier#endif /* INET6 */ 2403126258Smlaier } 2404126258Smlaier 2405126258Smlaier /* TCP header */ 2406126258Smlaier th->th_sport = sport; 2407126258Smlaier th->th_dport = dport; 2408126258Smlaier th->th_seq = htonl(seq); 2409126258Smlaier th->th_ack = htonl(ack); 2410126258Smlaier th->th_off = tlen >> 2; 2411126258Smlaier th->th_flags = flags; 2412126258Smlaier th->th_win = htons(win); 2413126258Smlaier 2414126258Smlaier if (mss) { 2415126258Smlaier opt = (char *)(th + 1); 2416126258Smlaier opt[0] = TCPOPT_MAXSEG; 2417126258Smlaier opt[1] = 4; 2418126258Smlaier HTONS(mss); 2419126258Smlaier bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2); 2420126258Smlaier } 2421126258Smlaier 2422126258Smlaier switch (af) { 2423126258Smlaier#ifdef INET 2424126258Smlaier case AF_INET: 2425126258Smlaier /* TCP checksum */ 2426126258Smlaier th->th_sum = in_cksum(m, len); 2427126258Smlaier 2428126258Smlaier /* Finish the IP header */ 2429126258Smlaier h->ip_v = 4; 2430126258Smlaier h->ip_hl = sizeof(*h) >> 2; 2431126258Smlaier h->ip_tos = IPTOS_LOWDELAY; 2432127145Smlaier#ifdef __FreeBSD__ 2433181803Sbz h->ip_off = V_path_mtu_discovery ? IP_DF : 0; 2434130613Smlaier h->ip_len = len; 2435223637Sbz h->ip_ttl = ttl ? ttl : V_ip_defttl; 2436126261Smlaier#else 2437223637Sbz h->ip_len = htons(len); 2438126261Smlaier h->ip_off = htons(ip_mtudisc ? IP_DF : 0); 2439223637Sbz h->ip_ttl = ttl ? ttl : ip_defttl; 2440126261Smlaier#endif 2441126258Smlaier h->ip_sum = 0; 2442145836Smlaier if (eh == NULL) { 2443127145Smlaier#ifdef __FreeBSD__ 2444223637Sbz PF_UNLOCK(); 2445223637Sbz ip_output(m, (void *)NULL, (void *)NULL, 0, 2446223637Sbz (void *)NULL, (void *)NULL); 2447223637Sbz PF_LOCK(); 2448126261Smlaier#else /* ! __FreeBSD__ */ 2449145836Smlaier ip_output(m, (void *)NULL, (void *)NULL, 0, 2450145836Smlaier (void *)NULL, (void *)NULL); 2451126261Smlaier#endif 2452145836Smlaier } else { 2453145836Smlaier struct route ro; 2454145836Smlaier struct rtentry rt; 2455145836Smlaier struct ether_header *e = (void *)ro.ro_dst.sa_data; 2456145836Smlaier 2457145836Smlaier if (ifp == NULL) { 2458145836Smlaier m_freem(m); 2459145836Smlaier return; 2460145836Smlaier } 2461145836Smlaier rt.rt_ifp = ifp; 2462145836Smlaier ro.ro_rt = &rt; 2463145836Smlaier ro.ro_dst.sa_len = sizeof(ro.ro_dst); 2464145836Smlaier ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT; 2465145836Smlaier bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN); 2466145836Smlaier bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN); 2467145836Smlaier e->ether_type = eh->ether_type; 2468145836Smlaier#ifdef __FreeBSD__ 2469145836Smlaier PF_UNLOCK(); 2470145836Smlaier /* XXX_IMPORT: later */ 2471145836Smlaier ip_output(m, (void *)NULL, &ro, 0, 2472145836Smlaier (void *)NULL, (void *)NULL); 2473145836Smlaier PF_LOCK(); 2474145836Smlaier#else /* ! __FreeBSD__ */ 2475145836Smlaier ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER, 2476145836Smlaier (void *)NULL, (void *)NULL); 2477145836Smlaier#endif 2478145836Smlaier } 2479126258Smlaier break; 2480126258Smlaier#endif /* INET */ 2481126258Smlaier#ifdef INET6 2482126258Smlaier case AF_INET6: 2483126258Smlaier /* TCP checksum */ 2484126258Smlaier th->th_sum = in6_cksum(m, IPPROTO_TCP, 2485126258Smlaier sizeof(struct ip6_hdr), tlen); 2486126258Smlaier 2487126258Smlaier h6->ip6_vfc |= IPV6_VERSION; 2488126258Smlaier h6->ip6_hlim = IPV6_DEFHLIM; 2489126258Smlaier 2490127145Smlaier#ifdef __FreeBSD__ 2491126261Smlaier PF_UNLOCK(); 2492126261Smlaier ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 2493126261Smlaier PF_LOCK(); 2494126261Smlaier#else 2495223637Sbz ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 2496126261Smlaier#endif 2497126258Smlaier break; 2498126258Smlaier#endif /* INET6 */ 2499126258Smlaier } 2500126258Smlaier} 2501126258Smlaier 2502223637Sbzstatic void 2503126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, 2504126258Smlaier struct pf_rule *r) 2505126258Smlaier{ 2506126258Smlaier struct mbuf *m0; 2507127145Smlaier#ifdef __FreeBSD__ 2508221132Sbz#ifdef INET 2509126261Smlaier struct ip *ip; 2510126261Smlaier#endif 2511223637Sbz struct pf_mtag *pf_mtag; 2512221132Sbz#endif 2513126258Smlaier 2514132280Smlaier#ifdef __FreeBSD__ 2515132280Smlaier m0 = m_copypacket(m, M_DONTWAIT); 2516132280Smlaier if (m0 == NULL) 2517132280Smlaier return; 2518132280Smlaier#else 2519223637Sbz if ((m0 = m_copy(m, 0, M_COPYALL)) == NULL) 2520223637Sbz return; 2521171168Smlaier#endif 2522223637Sbz 2523223637Sbz#ifdef __FreeBSD__ 2524171168Smlaier if ((pf_mtag = pf_get_mtag(m0)) == NULL) 2525126258Smlaier return; 2526171168Smlaier /* XXX: revisit */ 2527171168Smlaier m0->m_flags |= M_SKIP_FIREWALL; 2528171168Smlaier#else 2529223637Sbz m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2530132280Smlaier#endif 2531126258Smlaier 2532171168Smlaier if (r->rtableid >= 0) 2533178888Sjulian#ifdef __FreeBSD__ 2534178888Sjulian { 2535178888Sjulian M_SETFIB(m0, r->rtableid); 2536223637Sbz pf_mtag->rtableid = r->rtableid; 2537223637Sbz#else 2538223637Sbz m0->m_pkthdr.pf.rtableid = r->rtableid; 2539178888Sjulian#endif 2540178888Sjulian#ifdef __FreeBSD__ 2541178888Sjulian } 2542178888Sjulian#endif 2543171168Smlaier 2544126258Smlaier#ifdef ALTQ 2545126258Smlaier if (r->qid) { 2546223637Sbz#ifdef __FreeBSD__ 2547171168Smlaier pf_mtag->qid = r->qid; 2548171168Smlaier /* add hints for ecn */ 2549171168Smlaier pf_mtag->hdr = mtod(m0, struct ip *); 2550223637Sbz#else 2551223637Sbz m0->m_pkthdr.pf.qid = r->qid; 2552223637Sbz /* add hints for ecn */ 2553223637Sbz m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *); 2554223637Sbz#endif 2555126258Smlaier } 2556145836Smlaier#endif /* ALTQ */ 2557126258Smlaier 2558126258Smlaier switch (af) { 2559126258Smlaier#ifdef INET 2560126258Smlaier case AF_INET: 2561127145Smlaier#ifdef __FreeBSD__ 2562126261Smlaier /* icmp_error() expects host byte ordering */ 2563126261Smlaier ip = mtod(m0, struct ip *); 2564126261Smlaier NTOHS(ip->ip_len); 2565126261Smlaier NTOHS(ip->ip_off); 2566126261Smlaier PF_UNLOCK(); 2567145863Sandre icmp_error(m0, type, code, 0, 0); 2568126261Smlaier PF_LOCK(); 2569145874Smlaier#else 2570171168Smlaier icmp_error(m0, type, code, 0, 0); 2571126261Smlaier#endif 2572126258Smlaier break; 2573126258Smlaier#endif /* INET */ 2574126258Smlaier#ifdef INET6 2575126258Smlaier case AF_INET6: 2576127145Smlaier#ifdef __FreeBSD__ 2577126261Smlaier PF_UNLOCK(); 2578126261Smlaier#endif 2579126258Smlaier icmp6_error(m0, type, code, 0); 2580127145Smlaier#ifdef __FreeBSD__ 2581126261Smlaier PF_LOCK(); 2582126261Smlaier#endif 2583126258Smlaier break; 2584126258Smlaier#endif /* INET6 */ 2585126258Smlaier } 2586126258Smlaier} 2587126258Smlaier 2588126258Smlaier/* 2589126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0. 2590126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they 2591126258Smlaier * are different. 2592126258Smlaier */ 2593126258Smlaierint 2594126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m, 2595126258Smlaier struct pf_addr *b, sa_family_t af) 2596126258Smlaier{ 2597126258Smlaier int match = 0; 2598126258Smlaier 2599126258Smlaier switch (af) { 2600126258Smlaier#ifdef INET 2601126258Smlaier case AF_INET: 2602126258Smlaier if ((a->addr32[0] & m->addr32[0]) == 2603126258Smlaier (b->addr32[0] & m->addr32[0])) 2604126258Smlaier match++; 2605126258Smlaier break; 2606126258Smlaier#endif /* INET */ 2607126258Smlaier#ifdef INET6 2608126258Smlaier case AF_INET6: 2609126258Smlaier if (((a->addr32[0] & m->addr32[0]) == 2610126258Smlaier (b->addr32[0] & m->addr32[0])) && 2611126258Smlaier ((a->addr32[1] & m->addr32[1]) == 2612126258Smlaier (b->addr32[1] & m->addr32[1])) && 2613126258Smlaier ((a->addr32[2] & m->addr32[2]) == 2614126258Smlaier (b->addr32[2] & m->addr32[2])) && 2615126258Smlaier ((a->addr32[3] & m->addr32[3]) == 2616126258Smlaier (b->addr32[3] & m->addr32[3]))) 2617126258Smlaier match++; 2618126258Smlaier break; 2619126258Smlaier#endif /* INET6 */ 2620126258Smlaier } 2621126258Smlaier if (match) { 2622126258Smlaier if (n) 2623126258Smlaier return (0); 2624126258Smlaier else 2625126258Smlaier return (1); 2626126258Smlaier } else { 2627126258Smlaier if (n) 2628126258Smlaier return (1); 2629126258Smlaier else 2630126258Smlaier return (0); 2631126258Smlaier } 2632126258Smlaier} 2633126258Smlaier 2634223637Sbz/* 2635223637Sbz * Return 1 if b <= a <= e, otherwise return 0. 2636223637Sbz */ 2637126258Smlaierint 2638223637Sbzpf_match_addr_range(struct pf_addr *b, struct pf_addr *e, 2639223637Sbz struct pf_addr *a, sa_family_t af) 2640223637Sbz{ 2641223637Sbz switch (af) { 2642223637Sbz#ifdef INET 2643223637Sbz case AF_INET: 2644223637Sbz if ((a->addr32[0] < b->addr32[0]) || 2645223637Sbz (a->addr32[0] > e->addr32[0])) 2646223637Sbz return (0); 2647223637Sbz break; 2648223637Sbz#endif /* INET */ 2649223637Sbz#ifdef INET6 2650223637Sbz case AF_INET6: { 2651223637Sbz int i; 2652223637Sbz 2653223637Sbz /* check a >= b */ 2654223637Sbz for (i = 0; i < 4; ++i) 2655223637Sbz if (a->addr32[i] > b->addr32[i]) 2656223637Sbz break; 2657223637Sbz else if (a->addr32[i] < b->addr32[i]) 2658223637Sbz return (0); 2659223637Sbz /* check a <= e */ 2660223637Sbz for (i = 0; i < 4; ++i) 2661223637Sbz if (a->addr32[i] < e->addr32[i]) 2662223637Sbz break; 2663223637Sbz else if (a->addr32[i] > e->addr32[i]) 2664223637Sbz return (0); 2665223637Sbz break; 2666223637Sbz } 2667223637Sbz#endif /* INET6 */ 2668223637Sbz } 2669223637Sbz return (1); 2670223637Sbz} 2671223637Sbz 2672223637Sbzint 2673126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p) 2674126258Smlaier{ 2675126258Smlaier switch (op) { 2676126258Smlaier case PF_OP_IRG: 2677126258Smlaier return ((p > a1) && (p < a2)); 2678126258Smlaier case PF_OP_XRG: 2679126258Smlaier return ((p < a1) || (p > a2)); 2680126258Smlaier case PF_OP_RRG: 2681126258Smlaier return ((p >= a1) && (p <= a2)); 2682126258Smlaier case PF_OP_EQ: 2683126258Smlaier return (p == a1); 2684126258Smlaier case PF_OP_NE: 2685126258Smlaier return (p != a1); 2686126258Smlaier case PF_OP_LT: 2687126258Smlaier return (p < a1); 2688126258Smlaier case PF_OP_LE: 2689126258Smlaier return (p <= a1); 2690126258Smlaier case PF_OP_GT: 2691126258Smlaier return (p > a1); 2692126258Smlaier case PF_OP_GE: 2693126258Smlaier return (p >= a1); 2694126258Smlaier } 2695126258Smlaier return (0); /* never reached */ 2696126258Smlaier} 2697126258Smlaier 2698126258Smlaierint 2699126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p) 2700126258Smlaier{ 2701126258Smlaier NTOHS(a1); 2702126258Smlaier NTOHS(a2); 2703126258Smlaier NTOHS(p); 2704126258Smlaier return (pf_match(op, a1, a2, p)); 2705126258Smlaier} 2706126258Smlaier 2707126258Smlaierint 2708126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u) 2709126258Smlaier{ 2710126258Smlaier if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE) 2711126258Smlaier return (0); 2712126258Smlaier return (pf_match(op, a1, a2, u)); 2713126258Smlaier} 2714126258Smlaier 2715126258Smlaierint 2716126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) 2717126258Smlaier{ 2718126258Smlaier if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE) 2719126258Smlaier return (0); 2720126258Smlaier return (pf_match(op, a1, a2, g)); 2721126258Smlaier} 2722126258Smlaier 2723223637Sbzint 2724223637Sbz#ifdef __FreeBSD__ 2725223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag, 2726223637Sbz struct pf_mtag *pf_mtag) 2727223637Sbz#else 2728223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag) 2729171168Smlaier#endif 2730171168Smlaier{ 2731171168Smlaier if (*tag == -1) 2732223637Sbz#ifdef __FreeBSD__ 2733171168Smlaier *tag = pf_mtag->tag; 2734223637Sbz#else 2735223637Sbz *tag = m->m_pkthdr.pf.tag; 2736223637Sbz#endif 2737171168Smlaier 2738126258Smlaier return ((!r->match_tag_not && r->match_tag == *tag) || 2739126258Smlaier (r->match_tag_not && r->match_tag != *tag)); 2740126258Smlaier} 2741126258Smlaier 2742126258Smlaierint 2743223637Sbz#ifdef __FreeBSD__ 2744223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid, 2745223637Sbz struct pf_mtag *pf_mtag) 2746223637Sbz#else 2747223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid) 2748223637Sbz#endif 2749126258Smlaier{ 2750171168Smlaier if (tag <= 0 && rtableid < 0) 2751126258Smlaier return (0); 2752126258Smlaier 2753171168Smlaier if (tag > 0) 2754223637Sbz#ifdef __FreeBSD__ 2755171168Smlaier pf_mtag->tag = tag; 2756223637Sbz#else 2757223637Sbz m->m_pkthdr.pf.tag = tag; 2758223637Sbz#endif 2759171168Smlaier if (rtableid >= 0) 2760178888Sjulian#ifdef __FreeBSD__ 2761178888Sjulian { 2762178888Sjulian M_SETFIB(m, rtableid); 2763178888Sjulian } 2764223637Sbz#else 2765223637Sbz m->m_pkthdr.pf.rtableid = rtableid; 2766178888Sjulian#endif 2767126258Smlaier 2768126258Smlaier return (0); 2769126258Smlaier} 2770126258Smlaier 2771223637Sbzvoid 2772145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, 2773223637Sbz struct pf_rule **r, struct pf_rule **a, int *match) 2774145836Smlaier{ 2775145836Smlaier struct pf_anchor_stackframe *f; 2776126258Smlaier 2777171168Smlaier (*r)->anchor->match = 0; 2778171168Smlaier if (match) 2779171168Smlaier *match = 0; 2780223637Sbz#ifdef __FreeBSD__ 2781223637Sbz if (*depth >= sizeof(V_pf_anchor_stack) / 2782223637Sbz sizeof(V_pf_anchor_stack[0])) { 2783223637Sbz#else 2784145836Smlaier if (*depth >= sizeof(pf_anchor_stack) / 2785145836Smlaier sizeof(pf_anchor_stack[0])) { 2786223637Sbz#endif 2787145836Smlaier printf("pf_step_into_anchor: stack overflow\n"); 2788145836Smlaier *r = TAILQ_NEXT(*r, entries); 2789145836Smlaier return; 2790145836Smlaier } else if (*depth == 0 && a != NULL) 2791145836Smlaier *a = *r; 2792223637Sbz#ifdef __FreeBSD__ 2793223637Sbz f = V_pf_anchor_stack + (*depth)++; 2794223637Sbz#else 2795145836Smlaier f = pf_anchor_stack + (*depth)++; 2796223637Sbz#endif 2797145836Smlaier f->rs = *rs; 2798145836Smlaier f->r = *r; 2799145836Smlaier if ((*r)->anchor_wildcard) { 2800145836Smlaier f->parent = &(*r)->anchor->children; 2801145836Smlaier if ((f->child = RB_MIN(pf_anchor_node, f->parent)) == 2802145836Smlaier NULL) { 2803145836Smlaier *r = NULL; 2804145836Smlaier return; 2805145836Smlaier } 2806145836Smlaier *rs = &f->child->ruleset; 2807145836Smlaier } else { 2808145836Smlaier f->parent = NULL; 2809145836Smlaier f->child = NULL; 2810145836Smlaier *rs = &(*r)->anchor->ruleset; 2811145836Smlaier } 2812145836Smlaier *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); 2813145836Smlaier} 2814126258Smlaier 2815171168Smlaierint 2816145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, 2817171168Smlaier struct pf_rule **r, struct pf_rule **a, int *match) 2818145836Smlaier{ 2819145836Smlaier struct pf_anchor_stackframe *f; 2820171168Smlaier int quick = 0; 2821145836Smlaier 2822145836Smlaier do { 2823145836Smlaier if (*depth <= 0) 2824145836Smlaier break; 2825223637Sbz#ifdef __FreeBSD__ 2826223637Sbz f = V_pf_anchor_stack + *depth - 1; 2827223637Sbz#else 2828145836Smlaier f = pf_anchor_stack + *depth - 1; 2829223637Sbz#endif 2830145836Smlaier if (f->parent != NULL && f->child != NULL) { 2831171168Smlaier if (f->child->match || 2832171168Smlaier (match != NULL && *match)) { 2833171168Smlaier f->r->anchor->match = 1; 2834171168Smlaier *match = 0; 2835171168Smlaier } 2836145836Smlaier f->child = RB_NEXT(pf_anchor_node, f->parent, f->child); 2837145836Smlaier if (f->child != NULL) { 2838145836Smlaier *rs = &f->child->ruleset; 2839145836Smlaier *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); 2840145836Smlaier if (*r == NULL) 2841145836Smlaier continue; 2842145836Smlaier else 2843145836Smlaier break; 2844145836Smlaier } 2845145836Smlaier } 2846145836Smlaier (*depth)--; 2847145836Smlaier if (*depth == 0 && a != NULL) 2848145836Smlaier *a = NULL; 2849145836Smlaier *rs = f->rs; 2850223637Sbz if (f->r->anchor->match || (match != NULL && *match)) 2851171168Smlaier quick = f->r->quick; 2852145836Smlaier *r = TAILQ_NEXT(f->r, entries); 2853145836Smlaier } while (*r == NULL); 2854171168Smlaier 2855171168Smlaier return (quick); 2856145836Smlaier} 2857145836Smlaier 2858126258Smlaier#ifdef INET6 2859126258Smlaiervoid 2860126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr, 2861126258Smlaier struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af) 2862126258Smlaier{ 2863126258Smlaier switch (af) { 2864126258Smlaier#ifdef INET 2865126258Smlaier case AF_INET: 2866126258Smlaier naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) | 2867126258Smlaier ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]); 2868126258Smlaier break; 2869126258Smlaier#endif /* INET */ 2870126258Smlaier case AF_INET6: 2871126258Smlaier naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) | 2872126258Smlaier ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]); 2873126258Smlaier naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) | 2874126258Smlaier ((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]); 2875126258Smlaier naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) | 2876126258Smlaier ((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]); 2877126258Smlaier naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) | 2878126258Smlaier ((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]); 2879126258Smlaier break; 2880126258Smlaier } 2881126258Smlaier} 2882126258Smlaier 2883126258Smlaiervoid 2884130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af) 2885126258Smlaier{ 2886126258Smlaier switch (af) { 2887126258Smlaier#ifdef INET 2888126258Smlaier case AF_INET: 2889126258Smlaier addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1); 2890126258Smlaier break; 2891126258Smlaier#endif /* INET */ 2892126258Smlaier case AF_INET6: 2893126258Smlaier if (addr->addr32[3] == 0xffffffff) { 2894126258Smlaier addr->addr32[3] = 0; 2895126258Smlaier if (addr->addr32[2] == 0xffffffff) { 2896126258Smlaier addr->addr32[2] = 0; 2897126258Smlaier if (addr->addr32[1] == 0xffffffff) { 2898126258Smlaier addr->addr32[1] = 0; 2899126258Smlaier addr->addr32[0] = 2900126258Smlaier htonl(ntohl(addr->addr32[0]) + 1); 2901126258Smlaier } else 2902126258Smlaier addr->addr32[1] = 2903126258Smlaier htonl(ntohl(addr->addr32[1]) + 1); 2904126258Smlaier } else 2905126258Smlaier addr->addr32[2] = 2906126258Smlaier htonl(ntohl(addr->addr32[2]) + 1); 2907126258Smlaier } else 2908126258Smlaier addr->addr32[3] = 2909126258Smlaier htonl(ntohl(addr->addr32[3]) + 1); 2910126258Smlaier break; 2911126258Smlaier } 2912126258Smlaier} 2913126258Smlaier#endif /* INET6 */ 2914126258Smlaier 2915126258Smlaierint 2916135920Smlaier#ifdef __FreeBSD__ 2917171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg) 2918135920Smlaier#else 2919171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd) 2920135920Smlaier#endif 2921126258Smlaier{ 2922126258Smlaier struct pf_addr *saddr, *daddr; 2923126258Smlaier u_int16_t sport, dport; 2924127145Smlaier#ifdef __FreeBSD__ 2925126261Smlaier struct inpcbinfo *pi; 2926126261Smlaier#else 2927126258Smlaier struct inpcbtable *tb; 2928126261Smlaier#endif 2929126258Smlaier struct inpcb *inp; 2930126258Smlaier 2931171168Smlaier if (pd == NULL) 2932171168Smlaier return (-1); 2933171168Smlaier pd->lookup.uid = UID_MAX; 2934171168Smlaier pd->lookup.gid = GID_MAX; 2935223637Sbz pd->lookup.pid = NO_PID; 2936223637Sbz 2937135920Smlaier#ifdef __FreeBSD__ 2938135920Smlaier if (inp_arg != NULL) { 2939178325Srwatson INP_LOCK_ASSERT(inp_arg); 2940183606Sbz pd->lookup.uid = inp_arg->inp_cred->cr_uid; 2941183606Sbz pd->lookup.gid = inp_arg->inp_cred->cr_groups[0]; 2942183606Sbz return (1); 2943135920Smlaier } 2944135920Smlaier#endif 2945223637Sbz 2946130613Smlaier switch (pd->proto) { 2947126258Smlaier case IPPROTO_TCP: 2948171168Smlaier if (pd->hdr.tcp == NULL) 2949171168Smlaier return (-1); 2950126258Smlaier sport = pd->hdr.tcp->th_sport; 2951126258Smlaier dport = pd->hdr.tcp->th_dport; 2952127145Smlaier#ifdef __FreeBSD__ 2953181803Sbz pi = &V_tcbinfo; 2954126261Smlaier#else 2955126258Smlaier tb = &tcbtable; 2956126261Smlaier#endif 2957126258Smlaier break; 2958126258Smlaier case IPPROTO_UDP: 2959171168Smlaier if (pd->hdr.udp == NULL) 2960171168Smlaier return (-1); 2961126258Smlaier sport = pd->hdr.udp->uh_sport; 2962126258Smlaier dport = pd->hdr.udp->uh_dport; 2963127145Smlaier#ifdef __FreeBSD__ 2964181803Sbz pi = &V_udbinfo; 2965126261Smlaier#else 2966126258Smlaier tb = &udbtable; 2967126261Smlaier#endif 2968126258Smlaier break; 2969126258Smlaier default: 2970171168Smlaier return (-1); 2971126258Smlaier } 2972126258Smlaier if (direction == PF_IN) { 2973126258Smlaier saddr = pd->src; 2974126258Smlaier daddr = pd->dst; 2975126258Smlaier } else { 2976126258Smlaier u_int16_t p; 2977126258Smlaier 2978126258Smlaier p = sport; 2979126258Smlaier sport = dport; 2980126258Smlaier dport = p; 2981126258Smlaier saddr = pd->dst; 2982126258Smlaier daddr = pd->src; 2983126258Smlaier } 2984130613Smlaier switch (pd->af) { 2985145836Smlaier#ifdef INET 2986126258Smlaier case AF_INET: 2987127145Smlaier#ifdef __FreeBSD__ 2988222691Srwatson /* 2989222691Srwatson * XXXRW: would be nice if we had an mbuf here so that we 2990222691Srwatson * could use in_pcblookup_mbuf(). 2991222691Srwatson */ 2992222488Srwatson inp = in_pcblookup(pi, saddr->v4, sport, daddr->v4, 2993222488Srwatson dport, INPLOOKUP_RLOCKPCB, NULL); 2994126261Smlaier if (inp == NULL) { 2995222488Srwatson inp = in_pcblookup(pi, saddr->v4, sport, 2996222488Srwatson daddr->v4, dport, INPLOOKUP_WILDCARD | 2997222488Srwatson INPLOOKUP_RLOCKPCB, NULL); 2998222488Srwatson if (inp == NULL) 2999171168Smlaier return (-1); 3000126261Smlaier } 3001126261Smlaier#else 3002126258Smlaier inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); 3003126258Smlaier if (inp == NULL) { 3004223637Sbz inp = in_pcblookup_listen(tb, daddr->v4, dport, 0, 3005223637Sbz NULL); 3006126258Smlaier if (inp == NULL) 3007171168Smlaier return (-1); 3008126258Smlaier } 3009126261Smlaier#endif 3010126258Smlaier break; 3011145836Smlaier#endif /* INET */ 3012126258Smlaier#ifdef INET6 3013126258Smlaier case AF_INET6: 3014127145Smlaier#ifdef __FreeBSD__ 3015222691Srwatson /* 3016222691Srwatson * XXXRW: would be nice if we had an mbuf here so that we 3017222691Srwatson * could use in6_pcblookup_mbuf(). 3018222691Srwatson */ 3019222488Srwatson inp = in6_pcblookup(pi, &saddr->v6, sport, 3020222488Srwatson &daddr->v6, dport, INPLOOKUP_RLOCKPCB, NULL); 3021126261Smlaier if (inp == NULL) { 3022222488Srwatson inp = in6_pcblookup(pi, &saddr->v6, sport, 3023222488Srwatson &daddr->v6, dport, INPLOOKUP_WILDCARD | 3024222488Srwatson INPLOOKUP_RLOCKPCB, NULL); 3025222488Srwatson if (inp == NULL) 3026171168Smlaier return (-1); 3027126261Smlaier } 3028126261Smlaier#else 3029126258Smlaier inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6, 3030126258Smlaier dport); 3031126258Smlaier if (inp == NULL) { 3032223637Sbz inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0, 3033223637Sbz NULL); 3034126258Smlaier if (inp == NULL) 3035171168Smlaier return (-1); 3036126258Smlaier } 3037126261Smlaier#endif 3038126258Smlaier break; 3039126258Smlaier#endif /* INET6 */ 3040126258Smlaier 3041126258Smlaier default: 3042171168Smlaier return (-1); 3043126258Smlaier } 3044127145Smlaier#ifdef __FreeBSD__ 3045222488Srwatson INP_RLOCK_ASSERT(inp); 3046183606Sbz pd->lookup.uid = inp->inp_cred->cr_uid; 3047183606Sbz pd->lookup.gid = inp->inp_cred->cr_groups[0]; 3048222488Srwatson INP_RUNLOCK(inp); 3049126261Smlaier#else 3050171168Smlaier pd->lookup.uid = inp->inp_socket->so_euid; 3051171168Smlaier pd->lookup.gid = inp->inp_socket->so_egid; 3052171168Smlaier pd->lookup.pid = inp->inp_socket->so_cpid; 3053126261Smlaier#endif 3054126258Smlaier return (1); 3055126258Smlaier} 3056126258Smlaier 3057126258Smlaieru_int8_t 3058126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) 3059126258Smlaier{ 3060126258Smlaier int hlen; 3061126258Smlaier u_int8_t hdr[60]; 3062126258Smlaier u_int8_t *opt, optlen; 3063126258Smlaier u_int8_t wscale = 0; 3064126258Smlaier 3065126258Smlaier hlen = th_off << 2; /* hlen <= sizeof(hdr) */ 3066126258Smlaier if (hlen <= sizeof(struct tcphdr)) 3067126258Smlaier return (0); 3068126258Smlaier if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af)) 3069126258Smlaier return (0); 3070126258Smlaier opt = hdr + sizeof(struct tcphdr); 3071126258Smlaier hlen -= sizeof(struct tcphdr); 3072126258Smlaier while (hlen >= 3) { 3073126258Smlaier switch (*opt) { 3074126258Smlaier case TCPOPT_EOL: 3075126258Smlaier case TCPOPT_NOP: 3076126258Smlaier ++opt; 3077126258Smlaier --hlen; 3078126258Smlaier break; 3079126258Smlaier case TCPOPT_WINDOW: 3080126258Smlaier wscale = opt[2]; 3081126258Smlaier if (wscale > TCP_MAX_WINSHIFT) 3082126258Smlaier wscale = TCP_MAX_WINSHIFT; 3083126258Smlaier wscale |= PF_WSCALE_FLAG; 3084130613Smlaier /* FALLTHROUGH */ 3085126258Smlaier default: 3086126258Smlaier optlen = opt[1]; 3087126258Smlaier if (optlen < 2) 3088126258Smlaier optlen = 2; 3089126258Smlaier hlen -= optlen; 3090126258Smlaier opt += optlen; 3091130613Smlaier break; 3092126258Smlaier } 3093126258Smlaier } 3094126258Smlaier return (wscale); 3095126258Smlaier} 3096126258Smlaier 3097126258Smlaieru_int16_t 3098126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) 3099126258Smlaier{ 3100126258Smlaier int hlen; 3101126258Smlaier u_int8_t hdr[60]; 3102126258Smlaier u_int8_t *opt, optlen; 3103223637Sbz#ifdef __FreeBSD__ 3104181803Sbz u_int16_t mss = V_tcp_mssdflt; 3105223637Sbz#else 3106223637Sbz u_int16_t mss = tcp_mssdflt; 3107223637Sbz#endif 3108126258Smlaier 3109126258Smlaier hlen = th_off << 2; /* hlen <= sizeof(hdr) */ 3110126258Smlaier if (hlen <= sizeof(struct tcphdr)) 3111126258Smlaier return (0); 3112126258Smlaier if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af)) 3113126258Smlaier return (0); 3114126258Smlaier opt = hdr + sizeof(struct tcphdr); 3115126258Smlaier hlen -= sizeof(struct tcphdr); 3116126258Smlaier while (hlen >= TCPOLEN_MAXSEG) { 3117126258Smlaier switch (*opt) { 3118126258Smlaier case TCPOPT_EOL: 3119126258Smlaier case TCPOPT_NOP: 3120126258Smlaier ++opt; 3121126258Smlaier --hlen; 3122126258Smlaier break; 3123126258Smlaier case TCPOPT_MAXSEG: 3124126258Smlaier bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2); 3125145030Sglebius NTOHS(mss); 3126130613Smlaier /* FALLTHROUGH */ 3127126258Smlaier default: 3128126258Smlaier optlen = opt[1]; 3129126258Smlaier if (optlen < 2) 3130126258Smlaier optlen = 2; 3131126258Smlaier hlen -= optlen; 3132126258Smlaier opt += optlen; 3133130613Smlaier break; 3134126258Smlaier } 3135126258Smlaier } 3136126258Smlaier return (mss); 3137126258Smlaier} 3138126258Smlaier 3139126258Smlaieru_int16_t 3140231852Sbzpf_calc_mss(struct pf_addr *addr, sa_family_t af, int rtableid, u_int16_t offer) 3141126258Smlaier{ 3142126258Smlaier#ifdef INET 3143126258Smlaier struct sockaddr_in *dst; 3144126258Smlaier struct route ro; 3145126258Smlaier#endif /* INET */ 3146126258Smlaier#ifdef INET6 3147126258Smlaier struct sockaddr_in6 *dst6; 3148126258Smlaier struct route_in6 ro6; 3149126258Smlaier#endif /* INET6 */ 3150126258Smlaier struct rtentry *rt = NULL; 3151223637Sbz#ifdef __FreeBSD__ 3152223637Sbz int hlen = 0; 3153181803Sbz u_int16_t mss = V_tcp_mssdflt; 3154223637Sbz#else 3155223637Sbz int hlen; 3156223637Sbz u_int16_t mss = tcp_mssdflt; 3157223637Sbz#endif 3158126258Smlaier 3159126258Smlaier switch (af) { 3160126258Smlaier#ifdef INET 3161126258Smlaier case AF_INET: 3162126258Smlaier hlen = sizeof(struct ip); 3163126258Smlaier bzero(&ro, sizeof(ro)); 3164126258Smlaier dst = (struct sockaddr_in *)&ro.ro_dst; 3165126258Smlaier dst->sin_family = AF_INET; 3166126258Smlaier dst->sin_len = sizeof(*dst); 3167126258Smlaier dst->sin_addr = addr->v4; 3168127145Smlaier#ifdef __FreeBSD__ 3169231852Sbz in_rtalloc_ign(&ro, 0, rtableid); 3170126261Smlaier#else /* ! __FreeBSD__ */ 3171126258Smlaier rtalloc_noclone(&ro, NO_CLONING); 3172126261Smlaier#endif 3173126258Smlaier rt = ro.ro_rt; 3174126258Smlaier break; 3175126258Smlaier#endif /* INET */ 3176126258Smlaier#ifdef INET6 3177126258Smlaier case AF_INET6: 3178126258Smlaier hlen = sizeof(struct ip6_hdr); 3179126258Smlaier bzero(&ro6, sizeof(ro6)); 3180126258Smlaier dst6 = (struct sockaddr_in6 *)&ro6.ro_dst; 3181126258Smlaier dst6->sin6_family = AF_INET6; 3182126258Smlaier dst6->sin6_len = sizeof(*dst6); 3183126258Smlaier dst6->sin6_addr = addr->v6; 3184127145Smlaier#ifdef __FreeBSD__ 3185231852Sbz in6_rtalloc_ign(&ro6, 0, rtableid); 3186126261Smlaier#else /* ! __FreeBSD__ */ 3187126258Smlaier rtalloc_noclone((struct route *)&ro6, NO_CLONING); 3188126261Smlaier#endif 3189126258Smlaier rt = ro6.ro_rt; 3190126258Smlaier break; 3191126258Smlaier#endif /* INET6 */ 3192126258Smlaier } 3193126258Smlaier 3194126258Smlaier if (rt && rt->rt_ifp) { 3195126258Smlaier mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr); 3196223637Sbz#ifdef __FreeBSD__ 3197181803Sbz mss = max(V_tcp_mssdflt, mss); 3198223637Sbz#else 3199223637Sbz mss = max(tcp_mssdflt, mss); 3200223637Sbz#endif 3201126258Smlaier RTFREE(rt); 3202126258Smlaier } 3203126258Smlaier mss = min(mss, offer); 3204126258Smlaier mss = max(mss, 64); /* sanity - at least max opt space */ 3205126258Smlaier return (mss); 3206126258Smlaier} 3207126258Smlaier 3208126258Smlaiervoid 3209126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) 3210126258Smlaier{ 3211126258Smlaier struct pf_rule *r = s->rule.ptr; 3212223637Sbz struct pf_src_node *sn = NULL; 3213126258Smlaier 3214130613Smlaier s->rt_kif = NULL; 3215126258Smlaier if (!r->rt || r->rt == PF_FASTROUTE) 3216126258Smlaier return; 3217223637Sbz switch (s->key[PF_SK_WIRE]->af) { 3218126258Smlaier#ifdef INET 3219126258Smlaier case AF_INET: 3220223637Sbz pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); 3221130613Smlaier s->rt_kif = r->rpool.cur->kif; 3222126258Smlaier break; 3223126258Smlaier#endif /* INET */ 3224126258Smlaier#ifdef INET6 3225126258Smlaier case AF_INET6: 3226223637Sbz pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); 3227130613Smlaier s->rt_kif = r->rpool.cur->kif; 3228126258Smlaier break; 3229126258Smlaier#endif /* INET6 */ 3230126258Smlaier } 3231126258Smlaier} 3232126258Smlaier 3233223637Sbzu_int32_t 3234223637Sbzpf_tcp_iss(struct pf_pdesc *pd) 3235223637Sbz{ 3236223637Sbz MD5_CTX ctx; 3237223637Sbz u_int32_t digest[4]; 3238223637Sbz 3239223637Sbz#ifdef __FreeBSD__ 3240223637Sbz if (V_pf_tcp_secret_init == 0) { 3241223637Sbz read_random(&V_pf_tcp_secret, sizeof(V_pf_tcp_secret)); 3242223637Sbz MD5Init(&V_pf_tcp_secret_ctx); 3243223637Sbz MD5Update(&V_pf_tcp_secret_ctx, V_pf_tcp_secret, 3244223637Sbz sizeof(V_pf_tcp_secret)); 3245223637Sbz V_pf_tcp_secret_init = 1; 3246223637Sbz } 3247223637Sbz 3248223637Sbz ctx = V_pf_tcp_secret_ctx; 3249223637Sbz#else 3250223637Sbz if (pf_tcp_secret_init == 0) { 3251223637Sbz arc4random_buf(pf_tcp_secret, sizeof(pf_tcp_secret)); 3252223637Sbz MD5Init(&pf_tcp_secret_ctx); 3253223637Sbz MD5Update(&pf_tcp_secret_ctx, pf_tcp_secret, 3254223637Sbz sizeof(pf_tcp_secret)); 3255223637Sbz pf_tcp_secret_init = 1; 3256223637Sbz } 3257223637Sbz 3258223637Sbz ctx = pf_tcp_secret_ctx; 3259223637Sbz#endif 3260223637Sbz 3261223637Sbz MD5Update(&ctx, (char *)&pd->hdr.tcp->th_sport, sizeof(u_short)); 3262223637Sbz MD5Update(&ctx, (char *)&pd->hdr.tcp->th_dport, sizeof(u_short)); 3263223637Sbz if (pd->af == AF_INET6) { 3264223637Sbz MD5Update(&ctx, (char *)&pd->src->v6, sizeof(struct in6_addr)); 3265223637Sbz MD5Update(&ctx, (char *)&pd->dst->v6, sizeof(struct in6_addr)); 3266223637Sbz } else { 3267223637Sbz MD5Update(&ctx, (char *)&pd->src->v4, sizeof(struct in_addr)); 3268223637Sbz MD5Update(&ctx, (char *)&pd->dst->v4, sizeof(struct in_addr)); 3269223637Sbz } 3270223637Sbz MD5Final((u_char *)digest, &ctx); 3271223637Sbz#ifdef __FreeBSD__ 3272223637Sbz V_pf_tcp_iss_off += 4096; 3273223637Sbz#define ISN_RANDOM_INCREMENT (4096 - 1) 3274223637Sbz return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) + 3275223637Sbz V_pf_tcp_iss_off); 3276223637Sbz#undef ISN_RANDOM_INCREMENT 3277223637Sbz#else 3278223637Sbz pf_tcp_iss_off += 4096; 3279223637Sbz return (digest[0] + tcp_iss + pf_tcp_iss_off); 3280223637Sbz#endif 3281223637Sbz} 3282223637Sbz 3283126258Smlaierint 3284223637Sbzpf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, 3285130613Smlaier struct pfi_kif *kif, struct mbuf *m, int off, void *h, 3286223637Sbz struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, 3287135920Smlaier#ifdef __FreeBSD__ 3288145836Smlaier struct ifqueue *ifq, struct inpcb *inp) 3289135920Smlaier#else 3290145836Smlaier struct ifqueue *ifq) 3291135920Smlaier#endif 3292126258Smlaier{ 3293130613Smlaier struct pf_rule *nr = NULL; 3294126258Smlaier struct pf_addr *saddr = pd->src, *daddr = pd->dst; 3295126258Smlaier sa_family_t af = pd->af; 3296126258Smlaier struct pf_rule *r, *a = NULL; 3297126258Smlaier struct pf_ruleset *ruleset = NULL; 3298130613Smlaier struct pf_src_node *nsn = NULL; 3299223637Sbz struct tcphdr *th = pd->hdr.tcp; 3300223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 3301223637Sbz struct pf_state_key *sk = NULL, *nk = NULL; 3302126258Smlaier u_short reason; 3303223637Sbz int rewrite = 0, hdrlen = 0; 3304171168Smlaier int tag = -1, rtableid = -1; 3305145836Smlaier int asd = 0; 3306171168Smlaier int match = 0; 3307223637Sbz int state_icmp = 0; 3308223637Sbz#ifdef __FreeBSD__ 3309223637Sbz u_int16_t sport = 0, dport = 0; 3310223637Sbz u_int16_t bproto_sum = 0, bip_sum = 0; 3311223637Sbz#else 3312223637Sbz u_int16_t sport, dport; 3313223637Sbz u_int16_t bproto_sum = 0, bip_sum; 3314223637Sbz#endif 3315223637Sbz u_int8_t icmptype = 0, icmpcode = 0; 3316126258Smlaier 3317223637Sbz 3318223637Sbz if (direction == PF_IN && pf_check_congestion(ifq)) { 3319145836Smlaier REASON_SET(&reason, PFRES_CONGEST); 3320145836Smlaier return (PF_DROP); 3321145836Smlaier } 3322145836Smlaier 3323171168Smlaier#ifdef __FreeBSD__ 3324171168Smlaier if (inp != NULL) 3325171168Smlaier pd->lookup.done = pf_socket_lookup(direction, pd, inp); 3326223637Sbz else if (V_debug_pfugidhack) { 3327171168Smlaier PF_UNLOCK(); 3328171168Smlaier DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n")); 3329223637Sbz pd->lookup.done = pf_socket_lookup(direction, pd, inp); 3330171168Smlaier PF_LOCK(); 3331171168Smlaier } 3332165631Smlaier#endif 3333165631Smlaier 3334223637Sbz switch (pd->proto) { 3335223637Sbz case IPPROTO_TCP: 3336223637Sbz sport = th->th_sport; 3337223637Sbz dport = th->th_dport; 3338223637Sbz hdrlen = sizeof(*th); 3339223637Sbz break; 3340223637Sbz case IPPROTO_UDP: 3341223637Sbz sport = pd->hdr.udp->uh_sport; 3342223637Sbz dport = pd->hdr.udp->uh_dport; 3343223637Sbz hdrlen = sizeof(*pd->hdr.udp); 3344223637Sbz break; 3345223637Sbz#ifdef INET 3346223637Sbz case IPPROTO_ICMP: 3347223637Sbz if (pd->af != AF_INET) 3348223637Sbz break; 3349223637Sbz sport = dport = pd->hdr.icmp->icmp_id; 3350223637Sbz hdrlen = sizeof(*pd->hdr.icmp); 3351223637Sbz icmptype = pd->hdr.icmp->icmp_type; 3352223637Sbz icmpcode = pd->hdr.icmp->icmp_code; 3353223637Sbz 3354223637Sbz if (icmptype == ICMP_UNREACH || 3355223637Sbz icmptype == ICMP_SOURCEQUENCH || 3356223637Sbz icmptype == ICMP_REDIRECT || 3357223637Sbz icmptype == ICMP_TIMXCEED || 3358223637Sbz icmptype == ICMP_PARAMPROB) 3359223637Sbz state_icmp++; 3360223637Sbz break; 3361223637Sbz#endif /* INET */ 3362223637Sbz#ifdef INET6 3363223637Sbz case IPPROTO_ICMPV6: 3364223637Sbz if (af != AF_INET6) 3365223637Sbz break; 3366223637Sbz sport = dport = pd->hdr.icmp6->icmp6_id; 3367223637Sbz hdrlen = sizeof(*pd->hdr.icmp6); 3368223637Sbz icmptype = pd->hdr.icmp6->icmp6_type; 3369223637Sbz icmpcode = pd->hdr.icmp6->icmp6_code; 3370223637Sbz 3371223637Sbz if (icmptype == ICMP6_DST_UNREACH || 3372223637Sbz icmptype == ICMP6_PACKET_TOO_BIG || 3373223637Sbz icmptype == ICMP6_TIME_EXCEEDED || 3374223637Sbz icmptype == ICMP6_PARAM_PROB) 3375223637Sbz state_icmp++; 3376223637Sbz break; 3377223637Sbz#endif /* INET6 */ 3378223637Sbz default: 3379223637Sbz sport = dport = hdrlen = 0; 3380223637Sbz break; 3381223637Sbz } 3382223637Sbz 3383126258Smlaier r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 3384126258Smlaier 3385223637Sbz /* check packet for BINAT/NAT/RDR */ 3386223637Sbz if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, 3387223637Sbz &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) != NULL) { 3388223637Sbz if (nk == NULL || sk == NULL) { 3389223637Sbz REASON_SET(&reason, PFRES_MEMORY); 3390223637Sbz goto cleanup; 3391126258Smlaier } 3392223637Sbz 3393223637Sbz if (pd->ip_sum) 3394223637Sbz bip_sum = *pd->ip_sum; 3395223637Sbz 3396223637Sbz switch (pd->proto) { 3397223637Sbz case IPPROTO_TCP: 3398223637Sbz bproto_sum = th->th_sum; 3399223637Sbz pd->proto_sum = &th->th_sum; 3400223637Sbz 3401223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || 3402223637Sbz nk->port[pd->sidx] != sport) { 3403223637Sbz pf_change_ap(saddr, &th->th_sport, pd->ip_sum, 3404223637Sbz &th->th_sum, &nk->addr[pd->sidx], 3405223637Sbz nk->port[pd->sidx], 0, af); 3406223637Sbz pd->sport = &th->th_sport; 3407223637Sbz sport = th->th_sport; 3408223637Sbz } 3409223637Sbz 3410223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || 3411223637Sbz nk->port[pd->didx] != dport) { 3412223637Sbz pf_change_ap(daddr, &th->th_dport, pd->ip_sum, 3413223637Sbz &th->th_sum, &nk->addr[pd->didx], 3414223637Sbz nk->port[pd->didx], 0, af); 3415223637Sbz dport = th->th_dport; 3416223637Sbz pd->dport = &th->th_dport; 3417223637Sbz } 3418126258Smlaier rewrite++; 3419223637Sbz break; 3420223637Sbz case IPPROTO_UDP: 3421223637Sbz bproto_sum = pd->hdr.udp->uh_sum; 3422223637Sbz pd->proto_sum = &pd->hdr.udp->uh_sum; 3423223637Sbz 3424223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || 3425223637Sbz nk->port[pd->sidx] != sport) { 3426223637Sbz pf_change_ap(saddr, &pd->hdr.udp->uh_sport, 3427223637Sbz pd->ip_sum, &pd->hdr.udp->uh_sum, 3428223637Sbz &nk->addr[pd->sidx], 3429223637Sbz nk->port[pd->sidx], 1, af); 3430223637Sbz sport = pd->hdr.udp->uh_sport; 3431223637Sbz pd->sport = &pd->hdr.udp->uh_sport; 3432223637Sbz } 3433223637Sbz 3434223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || 3435223637Sbz nk->port[pd->didx] != dport) { 3436223637Sbz pf_change_ap(daddr, &pd->hdr.udp->uh_dport, 3437223637Sbz pd->ip_sum, &pd->hdr.udp->uh_sum, 3438223637Sbz &nk->addr[pd->didx], 3439223637Sbz nk->port[pd->didx], 1, af); 3440223637Sbz dport = pd->hdr.udp->uh_dport; 3441223637Sbz pd->dport = &pd->hdr.udp->uh_dport; 3442223637Sbz } 3443223637Sbz rewrite++; 3444223637Sbz break; 3445223637Sbz#ifdef INET 3446223637Sbz case IPPROTO_ICMP: 3447223637Sbz nk->port[0] = nk->port[1]; 3448223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) 3449223637Sbz pf_change_a(&saddr->v4.s_addr, pd->ip_sum, 3450223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 3451223637Sbz 3452223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET)) 3453223637Sbz pf_change_a(&daddr->v4.s_addr, pd->ip_sum, 3454223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 3455223637Sbz 3456223637Sbz if (nk->port[1] != pd->hdr.icmp->icmp_id) { 3457223637Sbz pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( 3458223637Sbz pd->hdr.icmp->icmp_cksum, sport, 3459223637Sbz nk->port[1], 0); 3460223637Sbz pd->hdr.icmp->icmp_id = nk->port[1]; 3461223637Sbz pd->sport = &pd->hdr.icmp->icmp_id; 3462223637Sbz } 3463223637Sbz m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); 3464223637Sbz break; 3465223637Sbz#endif /* INET */ 3466223637Sbz#ifdef INET6 3467223637Sbz case IPPROTO_ICMPV6: 3468223637Sbz nk->port[0] = nk->port[1]; 3469223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) 3470223637Sbz pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, 3471223637Sbz &nk->addr[pd->sidx], 0); 3472223637Sbz 3473223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) 3474223637Sbz pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, 3475223637Sbz &nk->addr[pd->didx], 0); 3476223637Sbz rewrite++; 3477223637Sbz break; 3478223637Sbz#endif /* INET */ 3479223637Sbz default: 3480223637Sbz switch (af) { 3481223637Sbz#ifdef INET 3482223637Sbz case AF_INET: 3483223637Sbz if (PF_ANEQ(saddr, 3484223637Sbz &nk->addr[pd->sidx], AF_INET)) 3485223637Sbz pf_change_a(&saddr->v4.s_addr, 3486223637Sbz pd->ip_sum, 3487223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 3488223637Sbz 3489223637Sbz if (PF_ANEQ(daddr, 3490223637Sbz &nk->addr[pd->didx], AF_INET)) 3491223637Sbz pf_change_a(&daddr->v4.s_addr, 3492223637Sbz pd->ip_sum, 3493223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 3494223637Sbz break; 3495223637Sbz#endif /* INET */ 3496223637Sbz#ifdef INET6 3497223637Sbz case AF_INET6: 3498223637Sbz if (PF_ANEQ(saddr, 3499223637Sbz &nk->addr[pd->sidx], AF_INET6)) 3500223637Sbz PF_ACPY(saddr, &nk->addr[pd->sidx], af); 3501223637Sbz 3502223637Sbz if (PF_ANEQ(daddr, 3503223637Sbz &nk->addr[pd->didx], AF_INET6)) 3504223637Sbz PF_ACPY(saddr, &nk->addr[pd->didx], af); 3505223637Sbz break; 3506223637Sbz#endif /* INET */ 3507223637Sbz } 3508223637Sbz break; 3509126258Smlaier } 3510223637Sbz if (nr->natpass) 3511223637Sbz r = NULL; 3512223637Sbz pd->nat_rule = nr; 3513126258Smlaier } 3514126258Smlaier 3515126258Smlaier while (r != NULL) { 3516126258Smlaier r->evaluations++; 3517171168Smlaier if (pfi_kif_match(r->kif, kif) == r->ifnot) 3518126258Smlaier r = r->skip[PF_SKIP_IFP].ptr; 3519126258Smlaier else if (r->direction && r->direction != direction) 3520126258Smlaier r = r->skip[PF_SKIP_DIR].ptr; 3521126258Smlaier else if (r->af && r->af != af) 3522126258Smlaier r = r->skip[PF_SKIP_AF].ptr; 3523223637Sbz else if (r->proto && r->proto != pd->proto) 3524126258Smlaier r = r->skip[PF_SKIP_PROTO].ptr; 3525171168Smlaier else if (PF_MISMATCHAW(&r->src.addr, saddr, af, 3526231852Sbz r->src.neg, kif, M_GETFIB(m))) 3527126258Smlaier r = r->skip[PF_SKIP_SRC_ADDR].ptr; 3528223637Sbz /* tcp/udp only. port_op always 0 in other cases */ 3529126258Smlaier else if (r->src.port_op && !pf_match_port(r->src.port_op, 3530223637Sbz r->src.port[0], r->src.port[1], sport)) 3531126258Smlaier r = r->skip[PF_SKIP_SRC_PORT].ptr; 3532171168Smlaier else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, 3533231852Sbz r->dst.neg, NULL, M_GETFIB(m))) 3534126258Smlaier r = r->skip[PF_SKIP_DST_ADDR].ptr; 3535223637Sbz /* tcp/udp only. port_op always 0 in other cases */ 3536126258Smlaier else if (r->dst.port_op && !pf_match_port(r->dst.port_op, 3537223637Sbz r->dst.port[0], r->dst.port[1], dport)) 3538126258Smlaier r = r->skip[PF_SKIP_DST_PORT].ptr; 3539223637Sbz /* icmp only. type always 0 in other cases */ 3540223637Sbz else if (r->type && r->type != icmptype + 1) 3541223637Sbz r = TAILQ_NEXT(r, entries); 3542223637Sbz /* icmp only. type always 0 in other cases */ 3543223637Sbz else if (r->code && r->code != icmpcode + 1) 3544223637Sbz r = TAILQ_NEXT(r, entries); 3545171168Smlaier else if (r->tos && !(r->tos == pd->tos)) 3546126258Smlaier r = TAILQ_NEXT(r, entries); 3547126258Smlaier else if (r->rule_flag & PFRULE_FRAGMENT) 3548126258Smlaier r = TAILQ_NEXT(r, entries); 3549223637Sbz else if (pd->proto == IPPROTO_TCP && 3550223637Sbz (r->flagset & th->th_flags) != r->flags) 3551126258Smlaier r = TAILQ_NEXT(r, entries); 3552223637Sbz /* tcp/udp only. uid.op always 0 in other cases */ 3553171168Smlaier else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = 3554135920Smlaier#ifdef __FreeBSD__ 3555171168Smlaier pf_socket_lookup(direction, pd, inp), 1)) && 3556135920Smlaier#else 3557171168Smlaier pf_socket_lookup(direction, pd), 1)) && 3558135920Smlaier#endif 3559126258Smlaier !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], 3560171168Smlaier pd->lookup.uid)) 3561126258Smlaier r = TAILQ_NEXT(r, entries); 3562223637Sbz /* tcp/udp only. gid.op always 0 in other cases */ 3563171168Smlaier else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = 3564135920Smlaier#ifdef __FreeBSD__ 3565171168Smlaier pf_socket_lookup(direction, pd, inp), 1)) && 3566135920Smlaier#else 3567171168Smlaier pf_socket_lookup(direction, pd), 1)) && 3568135920Smlaier#endif 3569126258Smlaier !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], 3570171168Smlaier pd->lookup.gid)) 3571126258Smlaier r = TAILQ_NEXT(r, entries); 3572223637Sbz else if (r->prob && 3573223637Sbz#ifdef __FreeBSD__ 3574223637Sbz r->prob <= arc4random()) 3575223637Sbz#else 3576223637Sbz r->prob <= arc4random_uniform(UINT_MAX - 1) + 1) 3577223637Sbz#endif 3578126258Smlaier r = TAILQ_NEXT(r, entries); 3579223637Sbz#ifdef __FreeBSD__ 3580223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) 3581223637Sbz#else 3582223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag)) 3583223637Sbz#endif 3584126258Smlaier r = TAILQ_NEXT(r, entries); 3585223637Sbz else if (r->os_fingerprint != PF_OSFP_ANY && 3586223637Sbz (pd->proto != IPPROTO_TCP || !pf_osfp_match( 3587223637Sbz pf_osfp_fingerprint(pd, m, off, th), 3588223637Sbz r->os_fingerprint))) 3589126258Smlaier r = TAILQ_NEXT(r, entries); 3590126258Smlaier else { 3591126258Smlaier if (r->tag) 3592126258Smlaier tag = r->tag; 3593171168Smlaier if (r->rtableid >= 0) 3594171168Smlaier rtableid = r->rtableid; 3595126258Smlaier if (r->anchor == NULL) { 3596171168Smlaier match = 1; 3597126258Smlaier *rm = r; 3598126258Smlaier *am = a; 3599126258Smlaier *rsm = ruleset; 3600126258Smlaier if ((*rm)->quick) 3601126258Smlaier break; 3602126258Smlaier r = TAILQ_NEXT(r, entries); 3603126258Smlaier } else 3604145836Smlaier pf_step_into_anchor(&asd, &ruleset, 3605171168Smlaier PF_RULESET_FILTER, &r, &a, &match); 3606126258Smlaier } 3607171168Smlaier if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, 3608171168Smlaier PF_RULESET_FILTER, &r, &a, &match)) 3609171168Smlaier break; 3610126258Smlaier } 3611126258Smlaier r = *rm; 3612126258Smlaier a = *am; 3613126258Smlaier ruleset = *rsm; 3614126258Smlaier 3615126258Smlaier REASON_SET(&reason, PFRES_MATCH); 3616126258Smlaier 3617223637Sbz if (r->log || (nr != NULL && nr->log)) { 3618126258Smlaier if (rewrite) 3619223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3620171168Smlaier PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, 3621171168Smlaier a, ruleset, pd); 3622126258Smlaier } 3623126258Smlaier 3624126258Smlaier if ((r->action == PF_DROP) && 3625126258Smlaier ((r->rule_flag & PFRULE_RETURNRST) || 3626126258Smlaier (r->rule_flag & PFRULE_RETURNICMP) || 3627126258Smlaier (r->rule_flag & PFRULE_RETURN))) { 3628126258Smlaier /* undo NAT changes, if they have taken place */ 3629130613Smlaier if (nr != NULL) { 3630223637Sbz PF_ACPY(saddr, &sk->addr[pd->sidx], af); 3631223637Sbz PF_ACPY(daddr, &sk->addr[pd->didx], af); 3632223637Sbz if (pd->sport) 3633223637Sbz *pd->sport = sk->port[pd->sidx]; 3634223637Sbz if (pd->dport) 3635223637Sbz *pd->dport = sk->port[pd->didx]; 3636223637Sbz if (pd->proto_sum) 3637223637Sbz *pd->proto_sum = bproto_sum; 3638223637Sbz if (pd->ip_sum) 3639223637Sbz *pd->ip_sum = bip_sum; 3640223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3641126258Smlaier } 3642223637Sbz if (pd->proto == IPPROTO_TCP && 3643223637Sbz ((r->rule_flag & PFRULE_RETURNRST) || 3644126258Smlaier (r->rule_flag & PFRULE_RETURN)) && 3645126258Smlaier !(th->th_flags & TH_RST)) { 3646223637Sbz u_int32_t ack = ntohl(th->th_seq) + pd->p_len; 3647223637Sbz int len = 0; 3648223637Sbz#ifdef INET 3649223637Sbz struct ip *h4; 3650223637Sbz#endif 3651223637Sbz#ifdef INET6 3652223637Sbz struct ip6_hdr *h6; 3653223637Sbz#endif 3654126258Smlaier 3655223637Sbz switch (af) { 3656223637Sbz#ifdef INET 3657223637Sbz case AF_INET: 3658223637Sbz h4 = mtod(m, struct ip *); 3659223637Sbz len = ntohs(h4->ip_len) - off; 3660223637Sbz break; 3661223637Sbz#endif 3662223637Sbz#ifdef INET6 3663223637Sbz case AF_INET6: 3664223637Sbz h6 = mtod(m, struct ip6_hdr *); 3665223637Sbz len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); 3666223637Sbz break; 3667223637Sbz#endif 3668223637Sbz } 3669223637Sbz 3670223637Sbz if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) 3671223637Sbz REASON_SET(&reason, PFRES_PROTCKSUM); 3672223637Sbz else { 3673223637Sbz if (th->th_flags & TH_SYN) 3674223637Sbz ack++; 3675223637Sbz if (th->th_flags & TH_FIN) 3676223637Sbz ack++; 3677162238Scsjp#ifdef __FreeBSD__ 3678223637Sbz pf_send_tcp(m, r, af, pd->dst, 3679162238Scsjp#else 3680223637Sbz pf_send_tcp(r, af, pd->dst, 3681162238Scsjp#endif 3682223637Sbz pd->src, th->th_dport, th->th_sport, 3683223637Sbz ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, 3684223637Sbz r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); 3685223637Sbz } 3686223637Sbz } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && 3687223637Sbz r->return_icmp) 3688126258Smlaier pf_send_icmp(m, r->return_icmp >> 8, 3689126258Smlaier r->return_icmp & 255, af, r); 3690223637Sbz else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && 3691223637Sbz r->return_icmp6) 3692126258Smlaier pf_send_icmp(m, r->return_icmp6 >> 8, 3693126258Smlaier r->return_icmp6 & 255, af, r); 3694126258Smlaier } 3695126258Smlaier 3696126258Smlaier if (r->action == PF_DROP) 3697223637Sbz goto cleanup; 3698126258Smlaier 3699223637Sbz#ifdef __FreeBSD__ 3700223637Sbz if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag)) { 3701223637Sbz#else 3702223637Sbz if (pf_tag_packet(m, tag, rtableid)) { 3703223637Sbz#endif 3704126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 3705223637Sbz goto cleanup; 3706126258Smlaier } 3707126258Smlaier 3708223637Sbz if (!state_icmp && (r->keep_state || nr != NULL || 3709223637Sbz (pd->flags & PFDESC_TCP_NORM))) { 3710223637Sbz int action; 3711223637Sbz action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m, 3712223637Sbz off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, 3713223637Sbz bip_sum, hdrlen); 3714223637Sbz if (action != PF_PASS) 3715223637Sbz return (action); 3716223637Sbz } else { 3717223637Sbz#ifdef __FreeBSD__ 3718223637Sbz if (sk != NULL) 3719223637Sbz pool_put(&V_pf_state_key_pl, sk); 3720223637Sbz if (nk != NULL) 3721223637Sbz pool_put(&V_pf_state_key_pl, nk); 3722223637Sbz#else 3723223637Sbz if (sk != NULL) 3724223637Sbz pool_put(&pf_state_key_pl, sk); 3725223637Sbz if (nk != NULL) 3726223637Sbz pool_put(&pf_state_key_pl, nk); 3727223637Sbz#endif 3728223637Sbz } 3729126258Smlaier 3730223637Sbz /* copy back packet headers if we performed NAT operations */ 3731223637Sbz if (rewrite) 3732223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3733130613Smlaier 3734223637Sbz#if NPFSYNC > 0 3735223637Sbz if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) && 3736223637Sbz#ifdef __FreeBSD__ 3737223637Sbz direction == PF_OUT && pfsync_up_ptr != NULL && pfsync_up_ptr()) { 3738223637Sbz#else 3739223637Sbz direction == PF_OUT && pfsync_up()) { 3740223637Sbz#endif 3741223637Sbz /* 3742223637Sbz * We want the state created, but we dont 3743223637Sbz * want to send this in case a partner 3744223637Sbz * firewall has to know about it to allow 3745223637Sbz * replies through it. 3746223637Sbz */ 3747223637Sbz#ifdef __FreeBSD__ 3748228150Sglebius if (pfsync_defer_ptr != NULL && 3749228150Sglebius pfsync_defer_ptr(*sm, m)) 3750223637Sbz#else 3751223637Sbz if (pfsync_defer(*sm, m)) 3752223637Sbz#endif 3753223637Sbz return (PF_DEFER); 3754223637Sbz } 3755223637Sbz#endif 3756223637Sbz 3757223637Sbz return (PF_PASS); 3758223637Sbz 3759130613Smlaiercleanup: 3760223637Sbz#ifdef __FreeBSD__ 3761223637Sbz if (sk != NULL) 3762223637Sbz pool_put(&V_pf_state_key_pl, sk); 3763223637Sbz if (nk != NULL) 3764223637Sbz pool_put(&V_pf_state_key_pl, nk); 3765223637Sbz#else 3766223637Sbz if (sk != NULL) 3767223637Sbz pool_put(&pf_state_key_pl, sk); 3768223637Sbz if (nk != NULL) 3769223637Sbz pool_put(&pf_state_key_pl, nk); 3770223637Sbz#endif 3771223637Sbz return (PF_DROP); 3772223637Sbz} 3773126258Smlaier 3774223637Sbzstatic __inline int 3775223637Sbzpf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, 3776223637Sbz struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw, 3777223637Sbz struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk, 3778223637Sbz struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite, 3779223637Sbz struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum, 3780223637Sbz u_int16_t bip_sum, int hdrlen) 3781223637Sbz{ 3782223637Sbz struct pf_state *s = NULL; 3783223637Sbz struct pf_src_node *sn = NULL; 3784223637Sbz struct tcphdr *th = pd->hdr.tcp; 3785223637Sbz#ifdef __FreeBSD__ 3786223637Sbz u_int16_t mss = V_tcp_mssdflt; 3787223637Sbz#else 3788223637Sbz u_int16_t mss = tcp_mssdflt; 3789223637Sbz#endif 3790223637Sbz u_short reason; 3791223637Sbz 3792223637Sbz /* check maximums */ 3793223637Sbz if (r->max_states && (r->states_cur >= r->max_states)) { 3794223637Sbz#ifdef __FreeBSD__ 3795223637Sbz V_pf_status.lcounters[LCNT_STATES]++; 3796223637Sbz#else 3797223637Sbz pf_status.lcounters[LCNT_STATES]++; 3798223637Sbz#endif 3799223637Sbz REASON_SET(&reason, PFRES_MAXSTATES); 3800223637Sbz return (PF_DROP); 3801223637Sbz } 3802223637Sbz /* src node for filter rule */ 3803223637Sbz if ((r->rule_flag & PFRULE_SRCTRACK || 3804223637Sbz r->rpool.opts & PF_POOL_STICKYADDR) && 3805223637Sbz pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) { 3806223637Sbz REASON_SET(&reason, PFRES_SRCLIMIT); 3807223637Sbz goto csfailed; 3808223637Sbz } 3809223637Sbz /* src node for translation rule */ 3810223637Sbz if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && 3811223637Sbz pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) { 3812223637Sbz REASON_SET(&reason, PFRES_SRCLIMIT); 3813223637Sbz goto csfailed; 3814223637Sbz } 3815223637Sbz#ifdef __FreeBSD__ 3816223637Sbz s = pool_get(&V_pf_state_pl, PR_NOWAIT | PR_ZERO); 3817223637Sbz#else 3818223637Sbz s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO); 3819223637Sbz#endif 3820223637Sbz if (s == NULL) { 3821223637Sbz REASON_SET(&reason, PFRES_MEMORY); 3822223637Sbz goto csfailed; 3823223637Sbz } 3824223637Sbz s->rule.ptr = r; 3825223637Sbz s->nat_rule.ptr = nr; 3826223637Sbz s->anchor.ptr = a; 3827223637Sbz STATE_INC_COUNTERS(s); 3828223637Sbz if (r->allow_opts) 3829223637Sbz s->state_flags |= PFSTATE_ALLOWOPTS; 3830223637Sbz if (r->rule_flag & PFRULE_STATESLOPPY) 3831223637Sbz s->state_flags |= PFSTATE_SLOPPY; 3832223637Sbz if (r->rule_flag & PFRULE_PFLOW) 3833223637Sbz s->state_flags |= PFSTATE_PFLOW; 3834223637Sbz s->log = r->log & PF_LOG_ALL; 3835223637Sbz s->sync_state = PFSYNC_S_NONE; 3836223637Sbz if (nr != NULL) 3837223637Sbz s->log |= nr->log & PF_LOG_ALL; 3838223637Sbz switch (pd->proto) { 3839223637Sbz case IPPROTO_TCP: 3840126258Smlaier s->src.seqlo = ntohl(th->th_seq); 3841223637Sbz s->src.seqhi = s->src.seqlo + pd->p_len + 1; 3842126258Smlaier if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && 3843126258Smlaier r->keep_state == PF_STATE_MODULATE) { 3844126258Smlaier /* Generate sequence number modulator */ 3845223637Sbz if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) == 3846223637Sbz 0) 3847223637Sbz s->src.seqdiff = 1; 3848126258Smlaier pf_change_a(&th->th_seq, &th->th_sum, 3849126258Smlaier htonl(s->src.seqlo + s->src.seqdiff), 0); 3850223637Sbz *rewrite = 1; 3851126258Smlaier } else 3852126258Smlaier s->src.seqdiff = 0; 3853126258Smlaier if (th->th_flags & TH_SYN) { 3854126258Smlaier s->src.seqhi++; 3855223637Sbz s->src.wscale = pf_get_wscale(m, off, 3856223637Sbz th->th_off, pd->af); 3857126258Smlaier } 3858126258Smlaier s->src.max_win = MAX(ntohs(th->th_win), 1); 3859126258Smlaier if (s->src.wscale & PF_WSCALE_MASK) { 3860126258Smlaier /* Remove scale factor from initial window */ 3861126258Smlaier int win = s->src.max_win; 3862126258Smlaier win += 1 << (s->src.wscale & PF_WSCALE_MASK); 3863126258Smlaier s->src.max_win = (win - 1) >> 3864126258Smlaier (s->src.wscale & PF_WSCALE_MASK); 3865126258Smlaier } 3866126258Smlaier if (th->th_flags & TH_FIN) 3867126258Smlaier s->src.seqhi++; 3868126258Smlaier s->dst.seqhi = 1; 3869126258Smlaier s->dst.max_win = 1; 3870126258Smlaier s->src.state = TCPS_SYN_SENT; 3871126258Smlaier s->dst.state = TCPS_CLOSED; 3872126258Smlaier s->timeout = PFTM_TCP_FIRST_PACKET; 3873223637Sbz break; 3874223637Sbz case IPPROTO_UDP: 3875223637Sbz s->src.state = PFUDPS_SINGLE; 3876223637Sbz s->dst.state = PFUDPS_NO_TRAFFIC; 3877223637Sbz s->timeout = PFTM_UDP_FIRST_PACKET; 3878223637Sbz break; 3879223637Sbz case IPPROTO_ICMP: 3880223637Sbz#ifdef INET6 3881223637Sbz case IPPROTO_ICMPV6: 3882223637Sbz#endif 3883223637Sbz s->timeout = PFTM_ICMP_FIRST_PACKET; 3884223637Sbz break; 3885223637Sbz default: 3886223637Sbz s->src.state = PFOTHERS_SINGLE; 3887223637Sbz s->dst.state = PFOTHERS_NO_TRAFFIC; 3888223637Sbz s->timeout = PFTM_OTHER_FIRST_PACKET; 3889223637Sbz } 3890223637Sbz 3891223637Sbz s->creation = time_second; 3892223637Sbz s->expire = time_second; 3893223637Sbz 3894223637Sbz if (sn != NULL) { 3895223637Sbz s->src_node = sn; 3896223637Sbz s->src_node->states++; 3897223637Sbz } 3898223637Sbz if (nsn != NULL) { 3899223637Sbz /* XXX We only modify one side for now. */ 3900223637Sbz PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); 3901223637Sbz s->nat_src_node = nsn; 3902223637Sbz s->nat_src_node->states++; 3903223637Sbz } 3904223637Sbz if (pd->proto == IPPROTO_TCP) { 3905126258Smlaier if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, 3906126258Smlaier off, pd, th, &s->src, &s->dst)) { 3907126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 3908130613Smlaier pf_src_tree_remove_state(s); 3909145836Smlaier STATE_DEC_COUNTERS(s); 3910223637Sbz#ifdef __FreeBSD__ 3911223637Sbz pool_put(&V_pf_state_pl, s); 3912223637Sbz#else 3913126258Smlaier pool_put(&pf_state_pl, s); 3914223637Sbz#endif 3915126258Smlaier return (PF_DROP); 3916126258Smlaier } 3917126258Smlaier if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub && 3918145836Smlaier pf_normalize_tcp_stateful(m, off, pd, &reason, th, s, 3919223637Sbz &s->src, &s->dst, rewrite)) { 3920145836Smlaier /* This really shouldn't happen!!! */ 3921145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 3922145836Smlaier ("pf_normalize_tcp_stateful failed on first pkt")); 3923126258Smlaier pf_normalize_tcp_cleanup(s); 3924130613Smlaier pf_src_tree_remove_state(s); 3925145836Smlaier STATE_DEC_COUNTERS(s); 3926162238Scsjp#ifdef __FreeBSD__ 3927223637Sbz pool_put(&V_pf_state_pl, s); 3928162238Scsjp#else 3929223637Sbz pool_put(&pf_state_pl, s); 3930162238Scsjp#endif 3931223637Sbz return (PF_DROP); 3932126258Smlaier } 3933126258Smlaier } 3934223637Sbz s->direction = pd->dir; 3935126258Smlaier 3936223637Sbz if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk, 3937223637Sbz pd->src, pd->dst, sport, dport)) 3938223637Sbz goto csfailed; 3939126258Smlaier 3940223637Sbz if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) { 3941223637Sbz if (pd->proto == IPPROTO_TCP) 3942223637Sbz pf_normalize_tcp_cleanup(s); 3943223637Sbz REASON_SET(&reason, PFRES_STATEINS); 3944223637Sbz pf_src_tree_remove_state(s); 3945223637Sbz STATE_DEC_COUNTERS(s); 3946135920Smlaier#ifdef __FreeBSD__ 3947223637Sbz pool_put(&V_pf_state_pl, s); 3948135920Smlaier#else 3949223637Sbz pool_put(&pf_state_pl, s); 3950135920Smlaier#endif 3951223637Sbz return (PF_DROP); 3952223637Sbz } else 3953223637Sbz *sm = s; 3954126258Smlaier 3955223637Sbz pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */ 3956223637Sbz if (tag > 0) { 3957223637Sbz pf_tag_ref(tag); 3958223637Sbz s->tag = tag; 3959145836Smlaier } 3960223637Sbz if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == 3961223637Sbz TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { 3962223637Sbz s->src.state = PF_TCPS_PROXY_SRC; 3963223637Sbz /* undo NAT changes, if they have taken place */ 3964223637Sbz if (nr != NULL) { 3965223637Sbz struct pf_state_key *skt = s->key[PF_SK_WIRE]; 3966223637Sbz if (pd->dir == PF_OUT) 3967223637Sbz skt = s->key[PF_SK_STACK]; 3968223637Sbz PF_ACPY(pd->src, &skt->addr[pd->sidx], pd->af); 3969223637Sbz PF_ACPY(pd->dst, &skt->addr[pd->didx], pd->af); 3970223637Sbz if (pd->sport) 3971223637Sbz *pd->sport = skt->port[pd->sidx]; 3972223637Sbz if (pd->dport) 3973223637Sbz *pd->dport = skt->port[pd->didx]; 3974223637Sbz if (pd->proto_sum) 3975223637Sbz *pd->proto_sum = bproto_sum; 3976223637Sbz if (pd->ip_sum) 3977223637Sbz *pd->ip_sum = bip_sum; 3978223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3979223637Sbz } 3980223637Sbz s->src.seqhi = htonl(arc4random()); 3981223637Sbz /* Find mss option */ 3982231852Sbz int rtid = M_GETFIB(m); 3983223637Sbz mss = pf_get_mss(m, off, th->th_off, pd->af); 3984231852Sbz mss = pf_calc_mss(pd->src, pd->af, rtid, mss); 3985231852Sbz mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); 3986223637Sbz s->src.mss = mss; 3987171168Smlaier#ifdef __FreeBSD__ 3988223637Sbz pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport, 3989223637Sbz#else 3990223637Sbz pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, 3991223637Sbz#endif 3992223637Sbz th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, 3993223637Sbz TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); 3994223637Sbz REASON_SET(&reason, PFRES_SYNPROXY); 3995223637Sbz return (PF_SYNPROXY_DROP); 3996171168Smlaier } 3997165631Smlaier 3998223637Sbz return (PF_PASS); 3999126258Smlaier 4000223637Sbzcsfailed: 4001135920Smlaier#ifdef __FreeBSD__ 4002223637Sbz if (sk != NULL) 4003223637Sbz pool_put(&V_pf_state_key_pl, sk); 4004223637Sbz if (nk != NULL) 4005223637Sbz pool_put(&V_pf_state_key_pl, nk); 4006135920Smlaier#else 4007223637Sbz if (sk != NULL) 4008223637Sbz pool_put(&pf_state_key_pl, sk); 4009223637Sbz if (nk != NULL) 4010223637Sbz pool_put(&pf_state_key_pl, nk); 4011135920Smlaier#endif 4012223637Sbz 4013223637Sbz if (sn != NULL && sn->states == 0 && sn->expire == 0) { 4014135920Smlaier#ifdef __FreeBSD__ 4015223637Sbz RB_REMOVE(pf_src_tree, &V_tree_src_tracking, sn); 4016223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4017223637Sbz V_pf_status.src_nodes--; 4018223637Sbz pool_put(&V_pf_src_tree_pl, sn); 4019135920Smlaier#else 4020223637Sbz RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); 4021223637Sbz pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4022223637Sbz pf_status.src_nodes--; 4023223637Sbz pool_put(&pf_src_tree_pl, sn); 4024135920Smlaier#endif 4025126258Smlaier } 4026223637Sbz if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { 4027171168Smlaier#ifdef __FreeBSD__ 4028223637Sbz RB_REMOVE(pf_src_tree, &V_tree_src_tracking, nsn); 4029223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4030223637Sbz V_pf_status.src_nodes--; 4031223637Sbz pool_put(&V_pf_src_tree_pl, nsn); 4032171168Smlaier#else 4033223637Sbz RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); 4034223637Sbz pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4035223637Sbz pf_status.src_nodes--; 4036223637Sbz pool_put(&pf_src_tree_pl, nsn); 4037171168Smlaier#endif 4038126258Smlaier } 4039223637Sbz return (PF_DROP); 4040126258Smlaier} 4041126258Smlaier 4042126258Smlaierint 4043130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, 4044126258Smlaier struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, 4045126258Smlaier struct pf_ruleset **rsm) 4046126258Smlaier{ 4047126258Smlaier struct pf_rule *r, *a = NULL; 4048126258Smlaier struct pf_ruleset *ruleset = NULL; 4049126258Smlaier sa_family_t af = pd->af; 4050126258Smlaier u_short reason; 4051126258Smlaier int tag = -1; 4052145836Smlaier int asd = 0; 4053171168Smlaier int match = 0; 4054126258Smlaier 4055126258Smlaier r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 4056126258Smlaier while (r != NULL) { 4057126258Smlaier r->evaluations++; 4058171168Smlaier if (pfi_kif_match(r->kif, kif) == r->ifnot) 4059126258Smlaier r = r->skip[PF_SKIP_IFP].ptr; 4060126258Smlaier else if (r->direction && r->direction != direction) 4061126258Smlaier r = r->skip[PF_SKIP_DIR].ptr; 4062126258Smlaier else if (r->af && r->af != af) 4063126258Smlaier r = r->skip[PF_SKIP_AF].ptr; 4064126258Smlaier else if (r->proto && r->proto != pd->proto) 4065126258Smlaier r = r->skip[PF_SKIP_PROTO].ptr; 4066171168Smlaier else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, 4067231852Sbz r->src.neg, kif, M_GETFIB(m))) 4068126258Smlaier r = r->skip[PF_SKIP_SRC_ADDR].ptr; 4069171168Smlaier else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, 4070231852Sbz r->dst.neg, NULL, M_GETFIB(m))) 4071126258Smlaier r = r->skip[PF_SKIP_DST_ADDR].ptr; 4072171168Smlaier else if (r->tos && !(r->tos == pd->tos)) 4073126258Smlaier r = TAILQ_NEXT(r, entries); 4074173815Smlaier else if (r->os_fingerprint != PF_OSFP_ANY) 4075126258Smlaier r = TAILQ_NEXT(r, entries); 4076173815Smlaier else if (pd->proto == IPPROTO_UDP && 4077173815Smlaier (r->src.port_op || r->dst.port_op)) 4078173815Smlaier r = TAILQ_NEXT(r, entries); 4079173815Smlaier else if (pd->proto == IPPROTO_TCP && 4080173815Smlaier (r->src.port_op || r->dst.port_op || r->flagset)) 4081173815Smlaier r = TAILQ_NEXT(r, entries); 4082173815Smlaier else if ((pd->proto == IPPROTO_ICMP || 4083173815Smlaier pd->proto == IPPROTO_ICMPV6) && 4084173815Smlaier (r->type || r->code)) 4085173815Smlaier r = TAILQ_NEXT(r, entries); 4086223637Sbz else if (r->prob && r->prob <= 4087223637Sbz (arc4random() % (UINT_MAX - 1) + 1)) 4088126258Smlaier r = TAILQ_NEXT(r, entries); 4089223637Sbz#ifdef __FreeBSD__ 4090223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) 4091223637Sbz#else 4092223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag)) 4093223637Sbz#endif 4094126258Smlaier r = TAILQ_NEXT(r, entries); 4095126258Smlaier else { 4096126258Smlaier if (r->anchor == NULL) { 4097171168Smlaier match = 1; 4098126258Smlaier *rm = r; 4099126258Smlaier *am = a; 4100126258Smlaier *rsm = ruleset; 4101126258Smlaier if ((*rm)->quick) 4102126258Smlaier break; 4103126258Smlaier r = TAILQ_NEXT(r, entries); 4104126258Smlaier } else 4105145836Smlaier pf_step_into_anchor(&asd, &ruleset, 4106171168Smlaier PF_RULESET_FILTER, &r, &a, &match); 4107126258Smlaier } 4108171168Smlaier if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, 4109171168Smlaier PF_RULESET_FILTER, &r, &a, &match)) 4110171168Smlaier break; 4111126258Smlaier } 4112126258Smlaier r = *rm; 4113126258Smlaier a = *am; 4114126258Smlaier ruleset = *rsm; 4115126258Smlaier 4116126258Smlaier REASON_SET(&reason, PFRES_MATCH); 4117130613Smlaier 4118126258Smlaier if (r->log) 4119171168Smlaier PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset, 4120171168Smlaier pd); 4121126258Smlaier 4122126258Smlaier if (r->action != PF_PASS) 4123126258Smlaier return (PF_DROP); 4124126258Smlaier 4125223637Sbz#ifdef __FreeBSD__ 4126223637Sbz if (pf_tag_packet(m, tag, -1, pd->pf_mtag)) { 4127223637Sbz#else 4128223637Sbz if (pf_tag_packet(m, tag, -1)) { 4129223637Sbz#endif 4130126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 4131126258Smlaier return (PF_DROP); 4132126258Smlaier } 4133126258Smlaier 4134126258Smlaier return (PF_PASS); 4135126258Smlaier} 4136126258Smlaier 4137126258Smlaierint 4138200930Sdelphijpf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, 4139200930Sdelphij struct pf_state **state, struct pfi_kif *kif, struct mbuf *m, int off, 4140200930Sdelphij struct pf_pdesc *pd, u_short *reason, int *copyback) 4141126258Smlaier{ 4142223637Sbz struct tcphdr *th = pd->hdr.tcp; 4143223637Sbz u_int16_t win = ntohs(th->th_win); 4144223637Sbz u_int32_t ack, end, seq, orig_seq; 4145223637Sbz u_int8_t sws, dws; 4146223637Sbz int ackskew; 4147126258Smlaier 4148126258Smlaier if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) { 4149126258Smlaier sws = src->wscale & PF_WSCALE_MASK; 4150126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 4151126258Smlaier } else 4152126258Smlaier sws = dws = 0; 4153126258Smlaier 4154126258Smlaier /* 4155126258Smlaier * Sequence tracking algorithm from Guido van Rooij's paper: 4156126258Smlaier * http://www.madison-gurkha.com/publications/tcp_filtering/ 4157126258Smlaier * tcp_filtering.ps 4158126258Smlaier */ 4159126258Smlaier 4160145836Smlaier orig_seq = seq = ntohl(th->th_seq); 4161126258Smlaier if (src->seqlo == 0) { 4162126258Smlaier /* First packet from this end. Set its state */ 4163126258Smlaier 4164126258Smlaier if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) && 4165126258Smlaier src->scrub == NULL) { 4166126258Smlaier if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) { 4167126258Smlaier REASON_SET(reason, PFRES_MEMORY); 4168126258Smlaier return (PF_DROP); 4169126258Smlaier } 4170126258Smlaier } 4171126258Smlaier 4172126258Smlaier /* Deferred generation of sequence number modulator */ 4173126258Smlaier if (dst->seqdiff && !src->seqdiff) { 4174223637Sbz /* use random iss for the TCP server */ 4175223637Sbz while ((src->seqdiff = arc4random() - seq) == 0) 4176126258Smlaier ; 4177126258Smlaier ack = ntohl(th->th_ack) - dst->seqdiff; 4178126258Smlaier pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + 4179126258Smlaier src->seqdiff), 0); 4180126258Smlaier pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0); 4181200930Sdelphij *copyback = 1; 4182126258Smlaier } else { 4183126258Smlaier ack = ntohl(th->th_ack); 4184126258Smlaier } 4185126258Smlaier 4186126258Smlaier end = seq + pd->p_len; 4187126258Smlaier if (th->th_flags & TH_SYN) { 4188126258Smlaier end++; 4189126258Smlaier if (dst->wscale & PF_WSCALE_FLAG) { 4190126258Smlaier src->wscale = pf_get_wscale(m, off, th->th_off, 4191126258Smlaier pd->af); 4192126258Smlaier if (src->wscale & PF_WSCALE_FLAG) { 4193126258Smlaier /* Remove scale factor from initial 4194126258Smlaier * window */ 4195126258Smlaier sws = src->wscale & PF_WSCALE_MASK; 4196126258Smlaier win = ((u_int32_t)win + (1 << sws) - 1) 4197126258Smlaier >> sws; 4198126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 4199126258Smlaier } else { 4200126258Smlaier /* fixup other window */ 4201126258Smlaier dst->max_win <<= dst->wscale & 4202126258Smlaier PF_WSCALE_MASK; 4203126258Smlaier /* in case of a retrans SYN|ACK */ 4204126258Smlaier dst->wscale = 0; 4205126258Smlaier } 4206126258Smlaier } 4207126258Smlaier } 4208126258Smlaier if (th->th_flags & TH_FIN) 4209126258Smlaier end++; 4210126258Smlaier 4211126258Smlaier src->seqlo = seq; 4212126258Smlaier if (src->state < TCPS_SYN_SENT) 4213126258Smlaier src->state = TCPS_SYN_SENT; 4214126258Smlaier 4215126258Smlaier /* 4216126258Smlaier * May need to slide the window (seqhi may have been set by 4217126258Smlaier * the crappy stack check or if we picked up the connection 4218126258Smlaier * after establishment) 4219126258Smlaier */ 4220126258Smlaier if (src->seqhi == 1 || 4221126258Smlaier SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi)) 4222126258Smlaier src->seqhi = end + MAX(1, dst->max_win << dws); 4223126258Smlaier if (win > src->max_win) 4224126258Smlaier src->max_win = win; 4225126258Smlaier 4226126258Smlaier } else { 4227126258Smlaier ack = ntohl(th->th_ack) - dst->seqdiff; 4228126258Smlaier if (src->seqdiff) { 4229126258Smlaier /* Modulate sequence numbers */ 4230126258Smlaier pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + 4231126258Smlaier src->seqdiff), 0); 4232126258Smlaier pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0); 4233200930Sdelphij *copyback = 1; 4234126258Smlaier } 4235126258Smlaier end = seq + pd->p_len; 4236126258Smlaier if (th->th_flags & TH_SYN) 4237126258Smlaier end++; 4238126258Smlaier if (th->th_flags & TH_FIN) 4239126258Smlaier end++; 4240126258Smlaier } 4241126258Smlaier 4242126258Smlaier if ((th->th_flags & TH_ACK) == 0) { 4243126258Smlaier /* Let it pass through the ack skew check */ 4244126258Smlaier ack = dst->seqlo; 4245126258Smlaier } else if ((ack == 0 && 4246126258Smlaier (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) || 4247126258Smlaier /* broken tcp stacks do not set ack */ 4248126258Smlaier (dst->state < TCPS_SYN_SENT)) { 4249126258Smlaier /* 4250126258Smlaier * Many stacks (ours included) will set the ACK number in an 4251126258Smlaier * FIN|ACK if the SYN times out -- no sequence to ACK. 4252126258Smlaier */ 4253126258Smlaier ack = dst->seqlo; 4254126258Smlaier } 4255126258Smlaier 4256126258Smlaier if (seq == end) { 4257126258Smlaier /* Ease sequencing restrictions on no data packets */ 4258126258Smlaier seq = src->seqlo; 4259126258Smlaier end = seq; 4260126258Smlaier } 4261126258Smlaier 4262126258Smlaier ackskew = dst->seqlo - ack; 4263126258Smlaier 4264171168Smlaier 4265171168Smlaier /* 4266171168Smlaier * Need to demodulate the sequence numbers in any TCP SACK options 4267171168Smlaier * (Selective ACK). We could optionally validate the SACK values 4268171168Smlaier * against the current ACK window, either forwards or backwards, but 4269171168Smlaier * I'm not confident that SACK has been implemented properly 4270171168Smlaier * everywhere. It wouldn't surprise me if several stacks accidently 4271171168Smlaier * SACK too far backwards of previously ACKed data. There really aren't 4272171168Smlaier * any security implications of bad SACKing unless the target stack 4273171168Smlaier * doesn't validate the option length correctly. Someone trying to 4274171168Smlaier * spoof into a TCP connection won't bother blindly sending SACK 4275171168Smlaier * options anyway. 4276171168Smlaier */ 4277171168Smlaier if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) { 4278171168Smlaier if (pf_modulate_sack(m, off, pd, th, dst)) 4279200930Sdelphij *copyback = 1; 4280171168Smlaier } 4281171168Smlaier 4282171168Smlaier 4283223637Sbz#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ 4284126258Smlaier if (SEQ_GEQ(src->seqhi, end) && 4285126258Smlaier /* Last octet inside other's window space */ 4286126258Smlaier SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) && 4287126258Smlaier /* Retrans: not more than one window back */ 4288126258Smlaier (ackskew >= -MAXACKWINDOW) && 4289126258Smlaier /* Acking not more than one reassembled fragment backwards */ 4290145836Smlaier (ackskew <= (MAXACKWINDOW << sws)) && 4291126258Smlaier /* Acking not more than one window forward */ 4292145836Smlaier ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo || 4293223637Sbz (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo) || 4294223637Sbz (pd->flags & PFDESC_IP_REAS) == 0)) { 4295171168Smlaier /* Require an exact/+1 sequence match on resets when possible */ 4296126258Smlaier 4297145836Smlaier if (dst->scrub || src->scrub) { 4298145836Smlaier if (pf_normalize_tcp_stateful(m, off, pd, reason, th, 4299200930Sdelphij *state, src, dst, copyback)) 4300145836Smlaier return (PF_DROP); 4301145836Smlaier } 4302145836Smlaier 4303126258Smlaier /* update max window */ 4304126258Smlaier if (src->max_win < win) 4305126258Smlaier src->max_win = win; 4306126258Smlaier /* synchronize sequencing */ 4307126258Smlaier if (SEQ_GT(end, src->seqlo)) 4308126258Smlaier src->seqlo = end; 4309126258Smlaier /* slide the window of what the other end can send */ 4310126258Smlaier if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) 4311126258Smlaier dst->seqhi = ack + MAX((win << sws), 1); 4312126258Smlaier 4313126258Smlaier 4314126258Smlaier /* update states */ 4315126258Smlaier if (th->th_flags & TH_SYN) 4316126258Smlaier if (src->state < TCPS_SYN_SENT) 4317126258Smlaier src->state = TCPS_SYN_SENT; 4318126258Smlaier if (th->th_flags & TH_FIN) 4319126258Smlaier if (src->state < TCPS_CLOSING) 4320126258Smlaier src->state = TCPS_CLOSING; 4321126258Smlaier if (th->th_flags & TH_ACK) { 4322145836Smlaier if (dst->state == TCPS_SYN_SENT) { 4323126258Smlaier dst->state = TCPS_ESTABLISHED; 4324145836Smlaier if (src->state == TCPS_ESTABLISHED && 4325145836Smlaier (*state)->src_node != NULL && 4326145836Smlaier pf_src_connlimit(state)) { 4327145836Smlaier REASON_SET(reason, PFRES_SRCLIMIT); 4328145836Smlaier return (PF_DROP); 4329145836Smlaier } 4330145836Smlaier } else if (dst->state == TCPS_CLOSING) 4331126258Smlaier dst->state = TCPS_FIN_WAIT_2; 4332126258Smlaier } 4333126258Smlaier if (th->th_flags & TH_RST) 4334126258Smlaier src->state = dst->state = TCPS_TIME_WAIT; 4335126258Smlaier 4336126258Smlaier /* update expire time */ 4337126261Smlaier (*state)->expire = time_second; 4338126258Smlaier if (src->state >= TCPS_FIN_WAIT_2 && 4339126258Smlaier dst->state >= TCPS_FIN_WAIT_2) 4340126258Smlaier (*state)->timeout = PFTM_TCP_CLOSED; 4341171168Smlaier else if (src->state >= TCPS_CLOSING && 4342171168Smlaier dst->state >= TCPS_CLOSING) 4343126258Smlaier (*state)->timeout = PFTM_TCP_FIN_WAIT; 4344126258Smlaier else if (src->state < TCPS_ESTABLISHED || 4345126258Smlaier dst->state < TCPS_ESTABLISHED) 4346126258Smlaier (*state)->timeout = PFTM_TCP_OPENING; 4347126258Smlaier else if (src->state >= TCPS_CLOSING || 4348126258Smlaier dst->state >= TCPS_CLOSING) 4349126258Smlaier (*state)->timeout = PFTM_TCP_CLOSING; 4350126258Smlaier else 4351126258Smlaier (*state)->timeout = PFTM_TCP_ESTABLISHED; 4352126258Smlaier 4353126258Smlaier /* Fall through to PASS packet */ 4354126258Smlaier 4355126258Smlaier } else if ((dst->state < TCPS_SYN_SENT || 4356126258Smlaier dst->state >= TCPS_FIN_WAIT_2 || 4357126258Smlaier src->state >= TCPS_FIN_WAIT_2) && 4358126258Smlaier SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) && 4359126258Smlaier /* Within a window forward of the originating packet */ 4360126258Smlaier SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) { 4361126258Smlaier /* Within a window backward of the originating packet */ 4362126258Smlaier 4363126258Smlaier /* 4364126258Smlaier * This currently handles three situations: 4365126258Smlaier * 1) Stupid stacks will shotgun SYNs before their peer 4366126258Smlaier * replies. 4367126258Smlaier * 2) When PF catches an already established stream (the 4368126258Smlaier * firewall rebooted, the state table was flushed, routes 4369126258Smlaier * changed...) 4370126258Smlaier * 3) Packets get funky immediately after the connection 4371126258Smlaier * closes (this should catch Solaris spurious ACK|FINs 4372126258Smlaier * that web servers like to spew after a close) 4373126258Smlaier * 4374126258Smlaier * This must be a little more careful than the above code 4375126258Smlaier * since packet floods will also be caught here. We don't 4376126258Smlaier * update the TTL here to mitigate the damage of a packet 4377126258Smlaier * flood and so the same code can handle awkward establishment 4378126258Smlaier * and a loosened connection close. 4379126258Smlaier * In the establishment case, a correct peer response will 4380126258Smlaier * validate the connection, go through the normal state code 4381126258Smlaier * and keep updating the state TTL. 4382126258Smlaier */ 4383126258Smlaier 4384223637Sbz#ifdef __FreeBSD__ 4385223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 4386223637Sbz#else 4387126258Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 4388223637Sbz#endif 4389126258Smlaier printf("pf: loose state match: "); 4390126258Smlaier pf_print_state(*state); 4391126258Smlaier pf_print_flags(th->th_flags); 4392171168Smlaier printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " 4393223637Sbz "pkts=%llu:%llu dir=%s,%s\n", seq, orig_seq, ack, 4394171168Smlaier#ifdef __FreeBSD__ 4395223637Sbz pd->p_len, ackskew, (unsigned long long)(*state)->packets[0], 4396223637Sbz (unsigned long long)(*state)->packets[1], 4397171168Smlaier#else 4398223637Sbz pd->p_len, ackskew, (*state)->packets[0], 4399223637Sbz (*state)->packets[1], 4400171168Smlaier#endif 4401223637Sbz pd->dir == PF_IN ? "in" : "out", 4402223637Sbz pd->dir == (*state)->direction ? "fwd" : "rev"); 4403126258Smlaier } 4404126258Smlaier 4405145836Smlaier if (dst->scrub || src->scrub) { 4406145836Smlaier if (pf_normalize_tcp_stateful(m, off, pd, reason, th, 4407200930Sdelphij *state, src, dst, copyback)) 4408145836Smlaier return (PF_DROP); 4409145836Smlaier } 4410145836Smlaier 4411126258Smlaier /* update max window */ 4412126258Smlaier if (src->max_win < win) 4413126258Smlaier src->max_win = win; 4414126258Smlaier /* synchronize sequencing */ 4415126258Smlaier if (SEQ_GT(end, src->seqlo)) 4416126258Smlaier src->seqlo = end; 4417126258Smlaier /* slide the window of what the other end can send */ 4418126258Smlaier if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) 4419126258Smlaier dst->seqhi = ack + MAX((win << sws), 1); 4420126258Smlaier 4421126258Smlaier /* 4422126258Smlaier * Cannot set dst->seqhi here since this could be a shotgunned 4423126258Smlaier * SYN and not an already established connection. 4424126258Smlaier */ 4425126258Smlaier 4426126258Smlaier if (th->th_flags & TH_FIN) 4427126258Smlaier if (src->state < TCPS_CLOSING) 4428126258Smlaier src->state = TCPS_CLOSING; 4429126258Smlaier if (th->th_flags & TH_RST) 4430126258Smlaier src->state = dst->state = TCPS_TIME_WAIT; 4431126258Smlaier 4432126258Smlaier /* Fall through to PASS packet */ 4433126258Smlaier 4434126258Smlaier } else { 4435126258Smlaier if ((*state)->dst.state == TCPS_SYN_SENT && 4436126258Smlaier (*state)->src.state == TCPS_SYN_SENT) { 4437126258Smlaier /* Send RST for state mismatches during handshake */ 4438145836Smlaier if (!(th->th_flags & TH_RST)) 4439162238Scsjp#ifdef __FreeBSD__ 4440223637Sbz pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4441162238Scsjp#else 4442126258Smlaier pf_send_tcp((*state)->rule.ptr, pd->af, 4443162238Scsjp#endif 4444126258Smlaier pd->dst, pd->src, th->th_dport, 4445145836Smlaier th->th_sport, ntohl(th->th_ack), 0, 4446145836Smlaier TH_RST, 0, 0, 4447171168Smlaier (*state)->rule.ptr->return_ttl, 1, 0, 4448145836Smlaier pd->eh, kif->pfik_ifp); 4449126258Smlaier src->seqlo = 0; 4450126258Smlaier src->seqhi = 1; 4451126258Smlaier src->max_win = 1; 4452223637Sbz#ifdef __FreeBSD__ 4453223637Sbz } else if (V_pf_status.debug >= PF_DEBUG_MISC) { 4454223637Sbz#else 4455126258Smlaier } else if (pf_status.debug >= PF_DEBUG_MISC) { 4456223637Sbz#endif 4457126258Smlaier printf("pf: BAD state: "); 4458126258Smlaier pf_print_state(*state); 4459126258Smlaier pf_print_flags(th->th_flags); 4460171168Smlaier printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " 4461171168Smlaier "pkts=%llu:%llu dir=%s,%s\n", 4462171168Smlaier seq, orig_seq, ack, pd->p_len, ackskew, 4463171168Smlaier#ifdef __FreeBSD__ 4464171168Smlaier (unsigned long long)(*state)->packets[0], 4465171168Smlaier (unsigned long long)(*state)->packets[1], 4466171168Smlaier#else 4467126258Smlaier (*state)->packets[0], (*state)->packets[1], 4468171168Smlaier#endif 4469223637Sbz pd->dir == PF_IN ? "in" : "out", 4470223637Sbz pd->dir == (*state)->direction ? "fwd" : "rev"); 4471126258Smlaier printf("pf: State failure on: %c %c %c %c | %c %c\n", 4472126258Smlaier SEQ_GEQ(src->seqhi, end) ? ' ' : '1', 4473126258Smlaier SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ? 4474126258Smlaier ' ': '2', 4475126258Smlaier (ackskew >= -MAXACKWINDOW) ? ' ' : '3', 4476126258Smlaier (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4', 4477126258Smlaier SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5', 4478126258Smlaier SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6'); 4479126258Smlaier } 4480145836Smlaier REASON_SET(reason, PFRES_BADSTATE); 4481126258Smlaier return (PF_DROP); 4482126258Smlaier } 4483126258Smlaier 4484200930Sdelphij return (PF_PASS); 4485200930Sdelphij} 4486126258Smlaier 4487200930Sdelphijint 4488200930Sdelphijpf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst, 4489200930Sdelphij struct pf_state **state, struct pf_pdesc *pd, u_short *reason) 4490200930Sdelphij{ 4491200930Sdelphij struct tcphdr *th = pd->hdr.tcp; 4492200930Sdelphij 4493200930Sdelphij if (th->th_flags & TH_SYN) 4494200930Sdelphij if (src->state < TCPS_SYN_SENT) 4495200930Sdelphij src->state = TCPS_SYN_SENT; 4496200930Sdelphij if (th->th_flags & TH_FIN) 4497200930Sdelphij if (src->state < TCPS_CLOSING) 4498200930Sdelphij src->state = TCPS_CLOSING; 4499200930Sdelphij if (th->th_flags & TH_ACK) { 4500200930Sdelphij if (dst->state == TCPS_SYN_SENT) { 4501200930Sdelphij dst->state = TCPS_ESTABLISHED; 4502200930Sdelphij if (src->state == TCPS_ESTABLISHED && 4503200930Sdelphij (*state)->src_node != NULL && 4504200930Sdelphij pf_src_connlimit(state)) { 4505200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4506200930Sdelphij return (PF_DROP); 4507200930Sdelphij } 4508200930Sdelphij } else if (dst->state == TCPS_CLOSING) { 4509200930Sdelphij dst->state = TCPS_FIN_WAIT_2; 4510200930Sdelphij } else if (src->state == TCPS_SYN_SENT && 4511200930Sdelphij dst->state < TCPS_SYN_SENT) { 4512200930Sdelphij /* 4513200930Sdelphij * Handle a special sloppy case where we only see one 4514200930Sdelphij * half of the connection. If there is a ACK after 4515200930Sdelphij * the initial SYN without ever seeing a packet from 4516200930Sdelphij * the destination, set the connection to established. 4517200930Sdelphij */ 4518200930Sdelphij dst->state = src->state = TCPS_ESTABLISHED; 4519200930Sdelphij if ((*state)->src_node != NULL && 4520200930Sdelphij pf_src_connlimit(state)) { 4521200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4522200930Sdelphij return (PF_DROP); 4523200930Sdelphij } 4524200930Sdelphij } else if (src->state == TCPS_CLOSING && 4525200930Sdelphij dst->state == TCPS_ESTABLISHED && 4526200930Sdelphij dst->seqlo == 0) { 4527200930Sdelphij /* 4528200930Sdelphij * Handle the closing of half connections where we 4529200930Sdelphij * don't see the full bidirectional FIN/ACK+ACK 4530200930Sdelphij * handshake. 4531200930Sdelphij */ 4532200930Sdelphij dst->state = TCPS_CLOSING; 4533200930Sdelphij } 4534200930Sdelphij } 4535200930Sdelphij if (th->th_flags & TH_RST) 4536200930Sdelphij src->state = dst->state = TCPS_TIME_WAIT; 4537200930Sdelphij 4538200930Sdelphij /* update expire time */ 4539200930Sdelphij (*state)->expire = time_second; 4540200930Sdelphij if (src->state >= TCPS_FIN_WAIT_2 && 4541200930Sdelphij dst->state >= TCPS_FIN_WAIT_2) 4542200930Sdelphij (*state)->timeout = PFTM_TCP_CLOSED; 4543200930Sdelphij else if (src->state >= TCPS_CLOSING && 4544200930Sdelphij dst->state >= TCPS_CLOSING) 4545200930Sdelphij (*state)->timeout = PFTM_TCP_FIN_WAIT; 4546200930Sdelphij else if (src->state < TCPS_ESTABLISHED || 4547200930Sdelphij dst->state < TCPS_ESTABLISHED) 4548200930Sdelphij (*state)->timeout = PFTM_TCP_OPENING; 4549200930Sdelphij else if (src->state >= TCPS_CLOSING || 4550200930Sdelphij dst->state >= TCPS_CLOSING) 4551200930Sdelphij (*state)->timeout = PFTM_TCP_CLOSING; 4552200930Sdelphij else 4553200930Sdelphij (*state)->timeout = PFTM_TCP_ESTABLISHED; 4554200930Sdelphij 4555200930Sdelphij return (PF_PASS); 4556200930Sdelphij} 4557200930Sdelphij 4558200930Sdelphijint 4559200930Sdelphijpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 4560200930Sdelphij struct mbuf *m, int off, void *h, struct pf_pdesc *pd, 4561200930Sdelphij u_short *reason) 4562200930Sdelphij{ 4563223637Sbz struct pf_state_key_cmp key; 4564200930Sdelphij struct tcphdr *th = pd->hdr.tcp; 4565200930Sdelphij int copyback = 0; 4566200930Sdelphij struct pf_state_peer *src, *dst; 4567223637Sbz struct pf_state_key *sk; 4568200930Sdelphij 4569200930Sdelphij key.af = pd->af; 4570200930Sdelphij key.proto = IPPROTO_TCP; 4571223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4572223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4573223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4574223637Sbz key.port[0] = th->th_sport; 4575223637Sbz key.port[1] = th->th_dport; 4576223637Sbz } else { /* stack side, reverse */ 4577223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4578223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4579223637Sbz key.port[1] = th->th_sport; 4580223637Sbz key.port[0] = th->th_dport; 4581200930Sdelphij } 4582200930Sdelphij 4583223637Sbz#ifdef __FreeBSD__ 4584223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4585223637Sbz#else 4586223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4587223637Sbz#endif 4588200930Sdelphij 4589200930Sdelphij if (direction == (*state)->direction) { 4590200930Sdelphij src = &(*state)->src; 4591200930Sdelphij dst = &(*state)->dst; 4592200930Sdelphij } else { 4593200930Sdelphij src = &(*state)->dst; 4594200930Sdelphij dst = &(*state)->src; 4595200930Sdelphij } 4596200930Sdelphij 4597223637Sbz sk = (*state)->key[pd->didx]; 4598223637Sbz 4599200930Sdelphij if ((*state)->src.state == PF_TCPS_PROXY_SRC) { 4600200930Sdelphij if (direction != (*state)->direction) { 4601200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4602200930Sdelphij return (PF_SYNPROXY_DROP); 4603200930Sdelphij } 4604200930Sdelphij if (th->th_flags & TH_SYN) { 4605200930Sdelphij if (ntohl(th->th_seq) != (*state)->src.seqlo) { 4606200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4607200930Sdelphij return (PF_DROP); 4608200930Sdelphij } 4609200930Sdelphij#ifdef __FreeBSD__ 4610200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, 4611200930Sdelphij#else 4612200930Sdelphij pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, 4613200930Sdelphij#endif 4614200930Sdelphij pd->src, th->th_dport, th->th_sport, 4615200930Sdelphij (*state)->src.seqhi, ntohl(th->th_seq) + 1, 4616200930Sdelphij TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 4617200930Sdelphij 0, NULL, NULL); 4618200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4619200930Sdelphij return (PF_SYNPROXY_DROP); 4620200930Sdelphij } else if (!(th->th_flags & TH_ACK) || 4621200930Sdelphij (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || 4622200930Sdelphij (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { 4623200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4624200930Sdelphij return (PF_DROP); 4625200930Sdelphij } else if ((*state)->src_node != NULL && 4626200930Sdelphij pf_src_connlimit(state)) { 4627200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4628200930Sdelphij return (PF_DROP); 4629200930Sdelphij } else 4630200930Sdelphij (*state)->src.state = PF_TCPS_PROXY_DST; 4631200930Sdelphij } 4632200930Sdelphij if ((*state)->src.state == PF_TCPS_PROXY_DST) { 4633200930Sdelphij if (direction == (*state)->direction) { 4634200930Sdelphij if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || 4635200930Sdelphij (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || 4636200930Sdelphij (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { 4637200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4638200930Sdelphij return (PF_DROP); 4639200930Sdelphij } 4640200930Sdelphij (*state)->src.max_win = MAX(ntohs(th->th_win), 1); 4641200930Sdelphij if ((*state)->dst.seqhi == 1) 4642200930Sdelphij (*state)->dst.seqhi = htonl(arc4random()); 4643200930Sdelphij#ifdef __FreeBSD__ 4644200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4645200930Sdelphij#else 4646223637Sbz pf_send_tcp((*state)->rule.ptr, pd->af, 4647200930Sdelphij#endif 4648223637Sbz &sk->addr[pd->sidx], &sk->addr[pd->didx], 4649223637Sbz sk->port[pd->sidx], sk->port[pd->didx], 4650200930Sdelphij (*state)->dst.seqhi, 0, TH_SYN, 0, 4651200930Sdelphij (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); 4652200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4653200930Sdelphij return (PF_SYNPROXY_DROP); 4654200930Sdelphij } else if (((th->th_flags & (TH_SYN|TH_ACK)) != 4655200930Sdelphij (TH_SYN|TH_ACK)) || 4656200930Sdelphij (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) { 4657200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4658200930Sdelphij return (PF_DROP); 4659200930Sdelphij } else { 4660200930Sdelphij (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); 4661200930Sdelphij (*state)->dst.seqlo = ntohl(th->th_seq); 4662200930Sdelphij#ifdef __FreeBSD__ 4663200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, 4664200930Sdelphij#else 4665200930Sdelphij pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, 4666200930Sdelphij#endif 4667200930Sdelphij pd->src, th->th_dport, th->th_sport, 4668200930Sdelphij ntohl(th->th_ack), ntohl(th->th_seq) + 1, 4669200930Sdelphij TH_ACK, (*state)->src.max_win, 0, 0, 0, 4670200930Sdelphij (*state)->tag, NULL, NULL); 4671200930Sdelphij#ifdef __FreeBSD__ 4672200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4673200930Sdelphij#else 4674223637Sbz pf_send_tcp((*state)->rule.ptr, pd->af, 4675200930Sdelphij#endif 4676223637Sbz &sk->addr[pd->sidx], &sk->addr[pd->didx], 4677223637Sbz sk->port[pd->sidx], sk->port[pd->didx], 4678200930Sdelphij (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, 4679200930Sdelphij TH_ACK, (*state)->dst.max_win, 0, 0, 1, 4680200930Sdelphij 0, NULL, NULL); 4681200930Sdelphij (*state)->src.seqdiff = (*state)->dst.seqhi - 4682200930Sdelphij (*state)->src.seqlo; 4683200930Sdelphij (*state)->dst.seqdiff = (*state)->src.seqhi - 4684200930Sdelphij (*state)->dst.seqlo; 4685200930Sdelphij (*state)->src.seqhi = (*state)->src.seqlo + 4686200930Sdelphij (*state)->dst.max_win; 4687200930Sdelphij (*state)->dst.seqhi = (*state)->dst.seqlo + 4688200930Sdelphij (*state)->src.max_win; 4689200930Sdelphij (*state)->src.wscale = (*state)->dst.wscale = 0; 4690200930Sdelphij (*state)->src.state = (*state)->dst.state = 4691200930Sdelphij TCPS_ESTABLISHED; 4692200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4693200930Sdelphij return (PF_SYNPROXY_DROP); 4694200930Sdelphij } 4695200930Sdelphij } 4696200930Sdelphij 4697200930Sdelphij if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) && 4698200930Sdelphij dst->state >= TCPS_FIN_WAIT_2 && 4699200930Sdelphij src->state >= TCPS_FIN_WAIT_2) { 4700223637Sbz#ifdef __FreeBSD__ 4701223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 4702223637Sbz#else 4703200930Sdelphij if (pf_status.debug >= PF_DEBUG_MISC) { 4704223637Sbz#endif 4705200930Sdelphij printf("pf: state reuse "); 4706200930Sdelphij pf_print_state(*state); 4707200930Sdelphij pf_print_flags(th->th_flags); 4708200930Sdelphij printf("\n"); 4709200930Sdelphij } 4710200930Sdelphij /* XXX make sure it's the same direction ?? */ 4711200930Sdelphij (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; 4712200930Sdelphij pf_unlink_state(*state); 4713200930Sdelphij *state = NULL; 4714200930Sdelphij return (PF_DROP); 4715200930Sdelphij } 4716200930Sdelphij 4717200930Sdelphij if ((*state)->state_flags & PFSTATE_SLOPPY) { 4718200930Sdelphij if (pf_tcp_track_sloppy(src, dst, state, pd, reason) == PF_DROP) 4719200930Sdelphij return (PF_DROP); 4720200930Sdelphij } else { 4721200930Sdelphij if (pf_tcp_track_full(src, dst, state, kif, m, off, pd, reason, 4722200930Sdelphij ©back) == PF_DROP) 4723200930Sdelphij return (PF_DROP); 4724200930Sdelphij } 4725200930Sdelphij 4726126258Smlaier /* translate source/destination address, if necessary */ 4727223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4728223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4729223637Sbz 4730223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || 4731223637Sbz nk->port[pd->sidx] != th->th_sport) 4732126258Smlaier pf_change_ap(pd->src, &th->th_sport, pd->ip_sum, 4733223637Sbz &th->th_sum, &nk->addr[pd->sidx], 4734223637Sbz nk->port[pd->sidx], 0, pd->af); 4735223637Sbz 4736223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || 4737223637Sbz nk->port[pd->didx] != th->th_dport) 4738126258Smlaier pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, 4739223637Sbz &th->th_sum, &nk->addr[pd->didx], 4740223637Sbz nk->port[pd->didx], 0, pd->af); 4741223637Sbz copyback = 1; 4742126258Smlaier } 4743126258Smlaier 4744223637Sbz /* Copyback sequence modulation or stateful scrub changes if needed */ 4745223637Sbz if (copyback) 4746223637Sbz#ifdef __FreeBSD__ 4747223637Sbz m_copyback(m, off, sizeof(*th), (caddr_t)th); 4748223637Sbz#else 4749223637Sbz m_copyback(m, off, sizeof(*th), th); 4750223637Sbz#endif 4751223637Sbz 4752126258Smlaier return (PF_PASS); 4753126258Smlaier} 4754126258Smlaier 4755126258Smlaierint 4756130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, 4757130613Smlaier struct mbuf *m, int off, void *h, struct pf_pdesc *pd) 4758126258Smlaier{ 4759126258Smlaier struct pf_state_peer *src, *dst; 4760223637Sbz struct pf_state_key_cmp key; 4761126258Smlaier struct udphdr *uh = pd->hdr.udp; 4762126258Smlaier 4763126258Smlaier key.af = pd->af; 4764126258Smlaier key.proto = IPPROTO_UDP; 4765223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4766223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4767223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4768223637Sbz key.port[0] = uh->uh_sport; 4769223637Sbz key.port[1] = uh->uh_dport; 4770223637Sbz } else { /* stack side, reverse */ 4771223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4772223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4773223637Sbz key.port[1] = uh->uh_sport; 4774223637Sbz key.port[0] = uh->uh_dport; 4775130613Smlaier } 4776126258Smlaier 4777223637Sbz#ifdef __FreeBSD__ 4778223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4779223637Sbz#else 4780223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4781223637Sbz#endif 4782126258Smlaier 4783126258Smlaier if (direction == (*state)->direction) { 4784126258Smlaier src = &(*state)->src; 4785126258Smlaier dst = &(*state)->dst; 4786126258Smlaier } else { 4787126258Smlaier src = &(*state)->dst; 4788126258Smlaier dst = &(*state)->src; 4789126258Smlaier } 4790126258Smlaier 4791126258Smlaier /* update states */ 4792126258Smlaier if (src->state < PFUDPS_SINGLE) 4793126258Smlaier src->state = PFUDPS_SINGLE; 4794126258Smlaier if (dst->state == PFUDPS_SINGLE) 4795126258Smlaier dst->state = PFUDPS_MULTIPLE; 4796126258Smlaier 4797126258Smlaier /* update expire time */ 4798126261Smlaier (*state)->expire = time_second; 4799126258Smlaier if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE) 4800126258Smlaier (*state)->timeout = PFTM_UDP_MULTIPLE; 4801126258Smlaier else 4802126258Smlaier (*state)->timeout = PFTM_UDP_SINGLE; 4803126258Smlaier 4804126258Smlaier /* translate source/destination address, if necessary */ 4805223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4806223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4807223637Sbz 4808223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || 4809223637Sbz nk->port[pd->sidx] != uh->uh_sport) 4810126258Smlaier pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum, 4811223637Sbz &uh->uh_sum, &nk->addr[pd->sidx], 4812223637Sbz nk->port[pd->sidx], 1, pd->af); 4813223637Sbz 4814223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || 4815223637Sbz nk->port[pd->didx] != uh->uh_dport) 4816126258Smlaier pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, 4817223637Sbz &uh->uh_sum, &nk->addr[pd->didx], 4818223637Sbz nk->port[pd->didx], 1, pd->af); 4819223637Sbz#ifdef __FreeBSD__ 4820126261Smlaier m_copyback(m, off, sizeof(*uh), (caddr_t)uh); 4821223637Sbz#else 4822223637Sbz m_copyback(m, off, sizeof(*uh), uh); 4823223637Sbz#endif 4824126258Smlaier } 4825126258Smlaier 4826126258Smlaier return (PF_PASS); 4827126258Smlaier} 4828126258Smlaier 4829126258Smlaierint 4830130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, 4831145836Smlaier struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) 4832126258Smlaier{ 4833223637Sbz struct pf_addr *saddr = pd->src, *daddr = pd->dst; 4834223637Sbz#ifdef __FreeBSD__ 4835223637Sbz u_int16_t icmpid = 0, *icmpsum; 4836223637Sbz#else 4837223637Sbz u_int16_t icmpid, *icmpsum; 4838223637Sbz#endif 4839223637Sbz u_int8_t icmptype; 4840130613Smlaier int state_icmp = 0; 4841223637Sbz struct pf_state_key_cmp key; 4842126258Smlaier 4843126258Smlaier switch (pd->proto) { 4844126258Smlaier#ifdef INET 4845126258Smlaier case IPPROTO_ICMP: 4846126258Smlaier icmptype = pd->hdr.icmp->icmp_type; 4847126258Smlaier icmpid = pd->hdr.icmp->icmp_id; 4848126258Smlaier icmpsum = &pd->hdr.icmp->icmp_cksum; 4849126258Smlaier 4850126258Smlaier if (icmptype == ICMP_UNREACH || 4851126258Smlaier icmptype == ICMP_SOURCEQUENCH || 4852126258Smlaier icmptype == ICMP_REDIRECT || 4853126258Smlaier icmptype == ICMP_TIMXCEED || 4854126258Smlaier icmptype == ICMP_PARAMPROB) 4855126258Smlaier state_icmp++; 4856126258Smlaier break; 4857126258Smlaier#endif /* INET */ 4858126258Smlaier#ifdef INET6 4859126258Smlaier case IPPROTO_ICMPV6: 4860126258Smlaier icmptype = pd->hdr.icmp6->icmp6_type; 4861126258Smlaier icmpid = pd->hdr.icmp6->icmp6_id; 4862126258Smlaier icmpsum = &pd->hdr.icmp6->icmp6_cksum; 4863126258Smlaier 4864126258Smlaier if (icmptype == ICMP6_DST_UNREACH || 4865126258Smlaier icmptype == ICMP6_PACKET_TOO_BIG || 4866126258Smlaier icmptype == ICMP6_TIME_EXCEEDED || 4867126258Smlaier icmptype == ICMP6_PARAM_PROB) 4868126258Smlaier state_icmp++; 4869126258Smlaier break; 4870126258Smlaier#endif /* INET6 */ 4871126258Smlaier } 4872126258Smlaier 4873126258Smlaier if (!state_icmp) { 4874126258Smlaier 4875126258Smlaier /* 4876126258Smlaier * ICMP query/reply message not related to a TCP/UDP packet. 4877126258Smlaier * Search for an ICMP state. 4878126258Smlaier */ 4879126258Smlaier key.af = pd->af; 4880126258Smlaier key.proto = pd->proto; 4881223637Sbz key.port[0] = key.port[1] = icmpid; 4882223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4883223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4884223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4885223637Sbz } else { /* stack side, reverse */ 4886223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4887223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4888130613Smlaier } 4889126258Smlaier 4890223637Sbz#ifdef __FreeBSD__ 4891223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4892223637Sbz#else 4893223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4894223637Sbz#endif 4895126258Smlaier 4896126261Smlaier (*state)->expire = time_second; 4897126258Smlaier (*state)->timeout = PFTM_ICMP_ERROR_REPLY; 4898126258Smlaier 4899126258Smlaier /* translate source/destination address, if necessary */ 4900223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4901223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4902223637Sbz 4903223637Sbz switch (pd->af) { 4904126258Smlaier#ifdef INET 4905223637Sbz case AF_INET: 4906223637Sbz if (PF_ANEQ(pd->src, 4907223637Sbz &nk->addr[pd->sidx], AF_INET)) 4908126258Smlaier pf_change_a(&saddr->v4.s_addr, 4909126258Smlaier pd->ip_sum, 4910223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 4911223637Sbz 4912223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], 4913223637Sbz AF_INET)) 4914223637Sbz pf_change_a(&daddr->v4.s_addr, 4915223637Sbz pd->ip_sum, 4916223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 4917223637Sbz 4918223637Sbz if (nk->port[0] != 4919223637Sbz pd->hdr.icmp->icmp_id) { 4920149884Smlaier pd->hdr.icmp->icmp_cksum = 4921149884Smlaier pf_cksum_fixup( 4922149884Smlaier pd->hdr.icmp->icmp_cksum, icmpid, 4923223637Sbz nk->port[pd->sidx], 0); 4924149884Smlaier pd->hdr.icmp->icmp_id = 4925223637Sbz nk->port[pd->sidx]; 4926223637Sbz } 4927223637Sbz 4928223637Sbz m_copyback(m, off, ICMP_MINLEN, 4929223637Sbz#ifdef __FreeBSD__ 4930223637Sbz (caddr_t) 4931223637Sbz#endif 4932223637Sbz pd->hdr.icmp); 4933223637Sbz break; 4934126258Smlaier#endif /* INET */ 4935126258Smlaier#ifdef INET6 4936223637Sbz case AF_INET6: 4937223637Sbz if (PF_ANEQ(pd->src, 4938223637Sbz &nk->addr[pd->sidx], AF_INET6)) 4939126258Smlaier pf_change_a6(saddr, 4940126258Smlaier &pd->hdr.icmp6->icmp6_cksum, 4941223637Sbz &nk->addr[pd->sidx], 0); 4942223637Sbz 4943223637Sbz if (PF_ANEQ(pd->dst, 4944223637Sbz &nk->addr[pd->didx], AF_INET6)) 4945126258Smlaier pf_change_a6(daddr, 4946126258Smlaier &pd->hdr.icmp6->icmp6_cksum, 4947223637Sbz &nk->addr[pd->didx], 0); 4948223637Sbz 4949223637Sbz m_copyback(m, off, 4950223637Sbz sizeof(struct icmp6_hdr), 4951223637Sbz#ifdef __FreeBSD__ 4952223637Sbz (caddr_t) 4953223637Sbz#endif 4954223637Sbz pd->hdr.icmp6); 4955223637Sbz break; 4956126258Smlaier#endif /* INET6 */ 4957126258Smlaier } 4958126258Smlaier } 4959126258Smlaier return (PF_PASS); 4960126258Smlaier 4961126258Smlaier } else { 4962126258Smlaier /* 4963126258Smlaier * ICMP error message in response to a TCP/UDP packet. 4964126258Smlaier * Extract the inner TCP/UDP header and search for that state. 4965126258Smlaier */ 4966126258Smlaier 4967126258Smlaier struct pf_pdesc pd2; 4968223637Sbz#ifdef __FreeBSD__ 4969223637Sbz bzero(&pd2, sizeof pd2); 4970223637Sbz#endif 4971126258Smlaier#ifdef INET 4972126258Smlaier struct ip h2; 4973126258Smlaier#endif /* INET */ 4974126258Smlaier#ifdef INET6 4975126258Smlaier struct ip6_hdr h2_6; 4976126258Smlaier int terminal = 0; 4977126258Smlaier#endif /* INET6 */ 4978223637Sbz#ifdef __FreeBSD__ 4979223637Sbz int ipoff2 = 0; 4980223637Sbz int off2 = 0; 4981223637Sbz#else 4982223637Sbz int ipoff2; 4983223637Sbz int off2; 4984223637Sbz#endif 4985126258Smlaier 4986126258Smlaier pd2.af = pd->af; 4987223637Sbz /* Payload packet is from the opposite direction. */ 4988223637Sbz pd2.sidx = (direction == PF_IN) ? 1 : 0; 4989223637Sbz pd2.didx = (direction == PF_IN) ? 0 : 1; 4990126258Smlaier switch (pd->af) { 4991126258Smlaier#ifdef INET 4992126258Smlaier case AF_INET: 4993126258Smlaier /* offset of h2 in mbuf chain */ 4994126258Smlaier ipoff2 = off + ICMP_MINLEN; 4995126258Smlaier 4996126258Smlaier if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), 4997145836Smlaier NULL, reason, pd2.af)) { 4998126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 4999126258Smlaier ("pf: ICMP error message too short " 5000126258Smlaier "(ip)\n")); 5001126258Smlaier return (PF_DROP); 5002126258Smlaier } 5003126258Smlaier /* 5004126258Smlaier * ICMP error messages don't refer to non-first 5005126258Smlaier * fragments 5006126258Smlaier */ 5007145836Smlaier if (h2.ip_off & htons(IP_OFFMASK)) { 5008145836Smlaier REASON_SET(reason, PFRES_FRAG); 5009126258Smlaier return (PF_DROP); 5010145836Smlaier } 5011126258Smlaier 5012126258Smlaier /* offset of protocol header that follows h2 */ 5013126258Smlaier off2 = ipoff2 + (h2.ip_hl << 2); 5014126258Smlaier 5015126258Smlaier pd2.proto = h2.ip_p; 5016126258Smlaier pd2.src = (struct pf_addr *)&h2.ip_src; 5017126258Smlaier pd2.dst = (struct pf_addr *)&h2.ip_dst; 5018126258Smlaier pd2.ip_sum = &h2.ip_sum; 5019126258Smlaier break; 5020126258Smlaier#endif /* INET */ 5021126258Smlaier#ifdef INET6 5022126258Smlaier case AF_INET6: 5023126258Smlaier ipoff2 = off + sizeof(struct icmp6_hdr); 5024126258Smlaier 5025126258Smlaier if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6), 5026145836Smlaier NULL, reason, pd2.af)) { 5027126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5028126258Smlaier ("pf: ICMP error message too short " 5029126258Smlaier "(ip6)\n")); 5030126258Smlaier return (PF_DROP); 5031126258Smlaier } 5032126258Smlaier pd2.proto = h2_6.ip6_nxt; 5033126258Smlaier pd2.src = (struct pf_addr *)&h2_6.ip6_src; 5034126258Smlaier pd2.dst = (struct pf_addr *)&h2_6.ip6_dst; 5035126258Smlaier pd2.ip_sum = NULL; 5036126258Smlaier off2 = ipoff2 + sizeof(h2_6); 5037126258Smlaier do { 5038126258Smlaier switch (pd2.proto) { 5039126258Smlaier case IPPROTO_FRAGMENT: 5040126258Smlaier /* 5041126258Smlaier * ICMPv6 error messages for 5042126258Smlaier * non-first fragments 5043126258Smlaier */ 5044145836Smlaier REASON_SET(reason, PFRES_FRAG); 5045126258Smlaier return (PF_DROP); 5046126258Smlaier case IPPROTO_AH: 5047126258Smlaier case IPPROTO_HOPOPTS: 5048126258Smlaier case IPPROTO_ROUTING: 5049126258Smlaier case IPPROTO_DSTOPTS: { 5050126258Smlaier /* get next header and header length */ 5051126258Smlaier struct ip6_ext opt6; 5052126258Smlaier 5053126258Smlaier if (!pf_pull_hdr(m, off2, &opt6, 5054145836Smlaier sizeof(opt6), NULL, reason, 5055145836Smlaier pd2.af)) { 5056126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5057126258Smlaier ("pf: ICMPv6 short opt\n")); 5058126258Smlaier return (PF_DROP); 5059126258Smlaier } 5060126258Smlaier if (pd2.proto == IPPROTO_AH) 5061126258Smlaier off2 += (opt6.ip6e_len + 2) * 4; 5062126258Smlaier else 5063126258Smlaier off2 += (opt6.ip6e_len + 1) * 8; 5064126258Smlaier pd2.proto = opt6.ip6e_nxt; 5065126258Smlaier /* goto the next header */ 5066126258Smlaier break; 5067126258Smlaier } 5068126258Smlaier default: 5069126258Smlaier terminal++; 5070126258Smlaier break; 5071126258Smlaier } 5072126258Smlaier } while (!terminal); 5073126258Smlaier break; 5074126258Smlaier#endif /* INET6 */ 5075126258Smlaier } 5076126258Smlaier 5077126258Smlaier switch (pd2.proto) { 5078126258Smlaier case IPPROTO_TCP: { 5079126258Smlaier struct tcphdr th; 5080126258Smlaier u_int32_t seq; 5081126258Smlaier struct pf_state_peer *src, *dst; 5082126258Smlaier u_int8_t dws; 5083128129Smlaier int copyback = 0; 5084126258Smlaier 5085126258Smlaier /* 5086126258Smlaier * Only the first 8 bytes of the TCP header can be 5087126258Smlaier * expected. Don't access any TCP header fields after 5088126258Smlaier * th_seq, an ackskew test is not possible. 5089126258Smlaier */ 5090145836Smlaier if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason, 5091145836Smlaier pd2.af)) { 5092126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5093126258Smlaier ("pf: ICMP error message too short " 5094126258Smlaier "(tcp)\n")); 5095126258Smlaier return (PF_DROP); 5096126258Smlaier } 5097126258Smlaier 5098126258Smlaier key.af = pd2.af; 5099126258Smlaier key.proto = IPPROTO_TCP; 5100223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5101223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5102223637Sbz key.port[pd2.sidx] = th.th_sport; 5103223637Sbz key.port[pd2.didx] = th.th_dport; 5104126258Smlaier 5105223637Sbz#ifdef __FreeBSD__ 5106223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5107223637Sbz#else 5108223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5109223637Sbz#endif 5110126258Smlaier 5111126258Smlaier if (direction == (*state)->direction) { 5112126258Smlaier src = &(*state)->dst; 5113126258Smlaier dst = &(*state)->src; 5114126258Smlaier } else { 5115126258Smlaier src = &(*state)->src; 5116126258Smlaier dst = &(*state)->dst; 5117126258Smlaier } 5118126258Smlaier 5119171929Sdhartmei if (src->wscale && dst->wscale) 5120126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 5121126258Smlaier else 5122126258Smlaier dws = 0; 5123126258Smlaier 5124126258Smlaier /* Demodulate sequence number */ 5125126258Smlaier seq = ntohl(th.th_seq) - src->seqdiff; 5126128129Smlaier if (src->seqdiff) { 5127128129Smlaier pf_change_a(&th.th_seq, icmpsum, 5128126258Smlaier htonl(seq), 0); 5129128129Smlaier copyback = 1; 5130128129Smlaier } 5131126258Smlaier 5132200930Sdelphij if (!((*state)->state_flags & PFSTATE_SLOPPY) && 5133200930Sdelphij (!SEQ_GEQ(src->seqhi, seq) || 5134200930Sdelphij !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) { 5135223637Sbz#ifdef __FreeBSD__ 5136223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 5137223637Sbz#else 5138126258Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 5139223637Sbz#endif 5140126258Smlaier printf("pf: BAD ICMP %d:%d ", 5141126258Smlaier icmptype, pd->hdr.icmp->icmp_code); 5142126258Smlaier pf_print_host(pd->src, 0, pd->af); 5143126258Smlaier printf(" -> "); 5144126258Smlaier pf_print_host(pd->dst, 0, pd->af); 5145126258Smlaier printf(" state: "); 5146126258Smlaier pf_print_state(*state); 5147126258Smlaier printf(" seq=%u\n", seq); 5148126258Smlaier } 5149145836Smlaier REASON_SET(reason, PFRES_BADSTATE); 5150126258Smlaier return (PF_DROP); 5151223637Sbz } else { 5152223637Sbz#ifdef __FreeBSD__ 5153223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 5154223637Sbz#else 5155223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 5156223637Sbz#endif 5157223637Sbz printf("pf: OK ICMP %d:%d ", 5158223637Sbz icmptype, pd->hdr.icmp->icmp_code); 5159223637Sbz pf_print_host(pd->src, 0, pd->af); 5160223637Sbz printf(" -> "); 5161223637Sbz pf_print_host(pd->dst, 0, pd->af); 5162223637Sbz printf(" state: "); 5163223637Sbz pf_print_state(*state); 5164223637Sbz printf(" seq=%u\n", seq); 5165223637Sbz } 5166126258Smlaier } 5167126258Smlaier 5168223637Sbz /* translate source/destination address, if necessary */ 5169223637Sbz if ((*state)->key[PF_SK_WIRE] != 5170223637Sbz (*state)->key[PF_SK_STACK]) { 5171223637Sbz struct pf_state_key *nk = 5172223637Sbz (*state)->key[pd->didx]; 5173223637Sbz 5174223637Sbz if (PF_ANEQ(pd2.src, 5175223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5176223637Sbz nk->port[pd2.sidx] != th.th_sport) 5177126258Smlaier pf_change_icmp(pd2.src, &th.th_sport, 5178223637Sbz daddr, &nk->addr[pd2.sidx], 5179223637Sbz nk->port[pd2.sidx], NULL, 5180126258Smlaier pd2.ip_sum, icmpsum, 5181126258Smlaier pd->ip_sum, 0, pd2.af); 5182223637Sbz 5183223637Sbz if (PF_ANEQ(pd2.dst, 5184223637Sbz &nk->addr[pd2.didx], pd2.af) || 5185223637Sbz nk->port[pd2.didx] != th.th_dport) 5186126258Smlaier pf_change_icmp(pd2.dst, &th.th_dport, 5187223637Sbz NULL, /* XXX Inbound NAT? */ 5188223637Sbz &nk->addr[pd2.didx], 5189223637Sbz nk->port[pd2.didx], NULL, 5190126258Smlaier pd2.ip_sum, icmpsum, 5191126258Smlaier pd->ip_sum, 0, pd2.af); 5192128129Smlaier copyback = 1; 5193128129Smlaier } 5194128129Smlaier 5195128129Smlaier if (copyback) { 5196126258Smlaier switch (pd2.af) { 5197126258Smlaier#ifdef INET 5198126258Smlaier case AF_INET: 5199126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5200223637Sbz#ifdef __FreeBSD__ 5201223637Sbz (caddr_t) 5202223637Sbz#endif 5203223637Sbz pd->hdr.icmp); 5204126258Smlaier m_copyback(m, ipoff2, sizeof(h2), 5205223637Sbz#ifdef __FreeBSD__ 5206223637Sbz (caddr_t) 5207223637Sbz#endif 5208223637Sbz &h2); 5209126258Smlaier break; 5210126258Smlaier#endif /* INET */ 5211126258Smlaier#ifdef INET6 5212126258Smlaier case AF_INET6: 5213126258Smlaier m_copyback(m, off, 5214126258Smlaier sizeof(struct icmp6_hdr), 5215223637Sbz#ifdef __FreeBSD__ 5216223637Sbz (caddr_t) 5217223637Sbz#endif 5218223637Sbz pd->hdr.icmp6); 5219126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5220223637Sbz#ifdef __FreeBSD__ 5221223637Sbz (caddr_t) 5222223637Sbz#endif 5223223637Sbz &h2_6); 5224126258Smlaier break; 5225126258Smlaier#endif /* INET6 */ 5226126258Smlaier } 5227223637Sbz#ifdef __FreeBSD__ 5228126261Smlaier m_copyback(m, off2, 8, (caddr_t)&th); 5229223637Sbz#else 5230223637Sbz m_copyback(m, off2, 8, &th); 5231223637Sbz#endif 5232126258Smlaier } 5233126258Smlaier 5234126258Smlaier return (PF_PASS); 5235126258Smlaier break; 5236126258Smlaier } 5237126258Smlaier case IPPROTO_UDP: { 5238126258Smlaier struct udphdr uh; 5239126258Smlaier 5240126258Smlaier if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), 5241145836Smlaier NULL, reason, pd2.af)) { 5242126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5243126258Smlaier ("pf: ICMP error message too short " 5244126258Smlaier "(udp)\n")); 5245126258Smlaier return (PF_DROP); 5246126258Smlaier } 5247126258Smlaier 5248126258Smlaier key.af = pd2.af; 5249126258Smlaier key.proto = IPPROTO_UDP; 5250223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5251223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5252223637Sbz key.port[pd2.sidx] = uh.uh_sport; 5253223637Sbz key.port[pd2.didx] = uh.uh_dport; 5254126258Smlaier 5255223637Sbz#ifdef __FreeBSD__ 5256223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5257223637Sbz#else 5258223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5259223637Sbz#endif 5260126258Smlaier 5261223637Sbz /* translate source/destination address, if necessary */ 5262223637Sbz if ((*state)->key[PF_SK_WIRE] != 5263223637Sbz (*state)->key[PF_SK_STACK]) { 5264223637Sbz struct pf_state_key *nk = 5265223637Sbz (*state)->key[pd->didx]; 5266223637Sbz 5267223637Sbz if (PF_ANEQ(pd2.src, 5268223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5269223637Sbz nk->port[pd2.sidx] != uh.uh_sport) 5270126258Smlaier pf_change_icmp(pd2.src, &uh.uh_sport, 5271223637Sbz daddr, &nk->addr[pd2.sidx], 5272223637Sbz nk->port[pd2.sidx], &uh.uh_sum, 5273126258Smlaier pd2.ip_sum, icmpsum, 5274126258Smlaier pd->ip_sum, 1, pd2.af); 5275223637Sbz 5276223637Sbz if (PF_ANEQ(pd2.dst, 5277223637Sbz &nk->addr[pd2.didx], pd2.af) || 5278223637Sbz nk->port[pd2.didx] != uh.uh_dport) 5279126258Smlaier pf_change_icmp(pd2.dst, &uh.uh_dport, 5280223637Sbz NULL, /* XXX Inbound NAT? */ 5281223637Sbz &nk->addr[pd2.didx], 5282223637Sbz nk->port[pd2.didx], &uh.uh_sum, 5283126258Smlaier pd2.ip_sum, icmpsum, 5284126258Smlaier pd->ip_sum, 1, pd2.af); 5285223637Sbz 5286126258Smlaier switch (pd2.af) { 5287126258Smlaier#ifdef INET 5288126258Smlaier case AF_INET: 5289126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5290223637Sbz#ifdef __FreeBSD__ 5291223637Sbz (caddr_t) 5292223637Sbz#endif 5293223637Sbz pd->hdr.icmp); 5294223637Sbz#ifdef __FreeBSD__ 5295223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5296223637Sbz#else 5297223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5298223637Sbz#endif 5299126258Smlaier break; 5300126258Smlaier#endif /* INET */ 5301126258Smlaier#ifdef INET6 5302126258Smlaier case AF_INET6: 5303126258Smlaier m_copyback(m, off, 5304126258Smlaier sizeof(struct icmp6_hdr), 5305223637Sbz#ifdef __FreeBSD__ 5306223637Sbz (caddr_t) 5307223637Sbz#endif 5308223637Sbz pd->hdr.icmp6); 5309126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5310223637Sbz#ifdef __FreeBSD__ 5311223637Sbz (caddr_t) 5312223637Sbz#endif 5313223637Sbz &h2_6); 5314126258Smlaier break; 5315126258Smlaier#endif /* INET6 */ 5316126258Smlaier } 5317223637Sbz#ifdef __FreeBSD__ 5318223637Sbz m_copyback(m, off2, sizeof(uh), (caddr_t)&uh); 5319223637Sbz#else 5320223637Sbz m_copyback(m, off2, sizeof(uh), &uh); 5321223637Sbz#endif 5322126258Smlaier } 5323126258Smlaier return (PF_PASS); 5324126258Smlaier break; 5325126258Smlaier } 5326126258Smlaier#ifdef INET 5327126258Smlaier case IPPROTO_ICMP: { 5328126258Smlaier struct icmp iih; 5329126258Smlaier 5330126258Smlaier if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, 5331145836Smlaier NULL, reason, pd2.af)) { 5332126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5333126258Smlaier ("pf: ICMP error message too short i" 5334126258Smlaier "(icmp)\n")); 5335126258Smlaier return (PF_DROP); 5336126258Smlaier } 5337126258Smlaier 5338126258Smlaier key.af = pd2.af; 5339126258Smlaier key.proto = IPPROTO_ICMP; 5340223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5341223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5342223637Sbz key.port[0] = key.port[1] = iih.icmp_id; 5343126258Smlaier 5344223637Sbz#ifdef __FreeBSD__ 5345223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5346223637Sbz#else 5347223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5348223637Sbz#endif 5349126258Smlaier 5350223637Sbz /* translate source/destination address, if necessary */ 5351223637Sbz if ((*state)->key[PF_SK_WIRE] != 5352223637Sbz (*state)->key[PF_SK_STACK]) { 5353223637Sbz struct pf_state_key *nk = 5354223637Sbz (*state)->key[pd->didx]; 5355223637Sbz 5356223637Sbz if (PF_ANEQ(pd2.src, 5357223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5358223637Sbz nk->port[pd2.sidx] != iih.icmp_id) 5359126258Smlaier pf_change_icmp(pd2.src, &iih.icmp_id, 5360223637Sbz daddr, &nk->addr[pd2.sidx], 5361223637Sbz nk->port[pd2.sidx], NULL, 5362126258Smlaier pd2.ip_sum, icmpsum, 5363126258Smlaier pd->ip_sum, 0, AF_INET); 5364223637Sbz 5365223637Sbz if (PF_ANEQ(pd2.dst, 5366223637Sbz &nk->addr[pd2.didx], pd2.af) || 5367223637Sbz nk->port[pd2.didx] != iih.icmp_id) 5368126258Smlaier pf_change_icmp(pd2.dst, &iih.icmp_id, 5369223637Sbz NULL, /* XXX Inbound NAT? */ 5370223637Sbz &nk->addr[pd2.didx], 5371223637Sbz nk->port[pd2.didx], NULL, 5372126258Smlaier pd2.ip_sum, icmpsum, 5373126258Smlaier pd->ip_sum, 0, AF_INET); 5374223637Sbz 5375223637Sbz#ifdef __FreeBSD__ 5376223637Sbz m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); 5377223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5378223637Sbz m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih); 5379223637Sbz#else 5380223637Sbz m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); 5381223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5382223637Sbz m_copyback(m, off2, ICMP_MINLEN, &iih); 5383223637Sbz#endif 5384126258Smlaier } 5385126258Smlaier return (PF_PASS); 5386126258Smlaier break; 5387126258Smlaier } 5388126258Smlaier#endif /* INET */ 5389126258Smlaier#ifdef INET6 5390126258Smlaier case IPPROTO_ICMPV6: { 5391126258Smlaier struct icmp6_hdr iih; 5392126258Smlaier 5393126258Smlaier if (!pf_pull_hdr(m, off2, &iih, 5394145836Smlaier sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) { 5395126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5396126258Smlaier ("pf: ICMP error message too short " 5397126258Smlaier "(icmp6)\n")); 5398126258Smlaier return (PF_DROP); 5399126258Smlaier } 5400126258Smlaier 5401126258Smlaier key.af = pd2.af; 5402126258Smlaier key.proto = IPPROTO_ICMPV6; 5403223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5404223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5405223637Sbz key.port[0] = key.port[1] = iih.icmp6_id; 5406126258Smlaier 5407223637Sbz#ifdef __FreeBSD__ 5408223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5409223637Sbz#else 5410223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5411223637Sbz#endif 5412126258Smlaier 5413223637Sbz /* translate source/destination address, if necessary */ 5414223637Sbz if ((*state)->key[PF_SK_WIRE] != 5415223637Sbz (*state)->key[PF_SK_STACK]) { 5416223637Sbz struct pf_state_key *nk = 5417223637Sbz (*state)->key[pd->didx]; 5418223637Sbz 5419223637Sbz if (PF_ANEQ(pd2.src, 5420223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5421223637Sbz nk->port[pd2.sidx] != iih.icmp6_id) 5422126258Smlaier pf_change_icmp(pd2.src, &iih.icmp6_id, 5423223637Sbz daddr, &nk->addr[pd2.sidx], 5424223637Sbz nk->port[pd2.sidx], NULL, 5425126258Smlaier pd2.ip_sum, icmpsum, 5426126258Smlaier pd->ip_sum, 0, AF_INET6); 5427223637Sbz 5428223637Sbz if (PF_ANEQ(pd2.dst, 5429223637Sbz &nk->addr[pd2.didx], pd2.af) || 5430223637Sbz nk->port[pd2.didx] != iih.icmp6_id) 5431126258Smlaier pf_change_icmp(pd2.dst, &iih.icmp6_id, 5432223637Sbz NULL, /* XXX Inbound NAT? */ 5433223637Sbz &nk->addr[pd2.didx], 5434223637Sbz nk->port[pd2.didx], NULL, 5435126258Smlaier pd2.ip_sum, icmpsum, 5436126258Smlaier pd->ip_sum, 0, AF_INET6); 5437223637Sbz 5438223637Sbz#ifdef __FreeBSD__ 5439126258Smlaier m_copyback(m, off, sizeof(struct icmp6_hdr), 5440126261Smlaier (caddr_t)pd->hdr.icmp6); 5441223637Sbz m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6); 5442126258Smlaier m_copyback(m, off2, sizeof(struct icmp6_hdr), 5443126261Smlaier (caddr_t)&iih); 5444223637Sbz#else 5445223637Sbz m_copyback(m, off, sizeof(struct icmp6_hdr), 5446223637Sbz pd->hdr.icmp6); 5447223637Sbz m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); 5448223637Sbz m_copyback(m, off2, sizeof(struct icmp6_hdr), 5449223637Sbz &iih); 5450223637Sbz#endif 5451126258Smlaier } 5452126258Smlaier return (PF_PASS); 5453126258Smlaier break; 5454126258Smlaier } 5455126258Smlaier#endif /* INET6 */ 5456126258Smlaier default: { 5457126258Smlaier key.af = pd2.af; 5458126258Smlaier key.proto = pd2.proto; 5459223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5460223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5461223637Sbz key.port[0] = key.port[1] = 0; 5462126258Smlaier 5463223637Sbz#ifdef __FreeBSD__ 5464223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5465223637Sbz#else 5466223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5467223637Sbz#endif 5468126258Smlaier 5469223637Sbz /* translate source/destination address, if necessary */ 5470223637Sbz if ((*state)->key[PF_SK_WIRE] != 5471223637Sbz (*state)->key[PF_SK_STACK]) { 5472223637Sbz struct pf_state_key *nk = 5473223637Sbz (*state)->key[pd->didx]; 5474223637Sbz 5475223637Sbz if (PF_ANEQ(pd2.src, 5476223637Sbz &nk->addr[pd2.sidx], pd2.af)) 5477223637Sbz pf_change_icmp(pd2.src, NULL, daddr, 5478223637Sbz &nk->addr[pd2.sidx], 0, NULL, 5479126258Smlaier pd2.ip_sum, icmpsum, 5480126258Smlaier pd->ip_sum, 0, pd2.af); 5481223637Sbz 5482223637Sbz if (PF_ANEQ(pd2.dst, 5483223637Sbz &nk->addr[pd2.didx], pd2.af)) 5484223637Sbz pf_change_icmp(pd2.src, NULL, 5485223637Sbz NULL, /* XXX Inbound NAT? */ 5486223637Sbz &nk->addr[pd2.didx], 0, NULL, 5487126258Smlaier pd2.ip_sum, icmpsum, 5488126258Smlaier pd->ip_sum, 0, pd2.af); 5489223637Sbz 5490126258Smlaier switch (pd2.af) { 5491126258Smlaier#ifdef INET 5492126258Smlaier case AF_INET: 5493223637Sbz#ifdef __FreeBSD__ 5494126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5495126261Smlaier (caddr_t)pd->hdr.icmp); 5496223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5497223637Sbz#else 5498223637Sbz m_copyback(m, off, ICMP_MINLEN, 5499223637Sbz pd->hdr.icmp); 5500223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5501223637Sbz#endif 5502126258Smlaier break; 5503126258Smlaier#endif /* INET */ 5504126258Smlaier#ifdef INET6 5505126258Smlaier case AF_INET6: 5506126258Smlaier m_copyback(m, off, 5507126258Smlaier sizeof(struct icmp6_hdr), 5508223637Sbz#ifdef __FreeBSD__ 5509223637Sbz (caddr_t) 5510223637Sbz#endif 5511223637Sbz pd->hdr.icmp6); 5512126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5513223637Sbz#ifdef __FreeBSD__ 5514223637Sbz (caddr_t) 5515223637Sbz#endif 5516223637Sbz &h2_6); 5517126258Smlaier break; 5518126258Smlaier#endif /* INET6 */ 5519126258Smlaier } 5520126258Smlaier } 5521126258Smlaier return (PF_PASS); 5522126258Smlaier break; 5523126258Smlaier } 5524126258Smlaier } 5525126258Smlaier } 5526126258Smlaier} 5527126258Smlaier 5528126258Smlaierint 5529130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, 5530223637Sbz struct mbuf *m, struct pf_pdesc *pd) 5531126258Smlaier{ 5532126258Smlaier struct pf_state_peer *src, *dst; 5533223637Sbz struct pf_state_key_cmp key; 5534126258Smlaier 5535126258Smlaier key.af = pd->af; 5536126258Smlaier key.proto = pd->proto; 5537130613Smlaier if (direction == PF_IN) { 5538223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 5539223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 5540223637Sbz key.port[0] = key.port[1] = 0; 5541130613Smlaier } else { 5542223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 5543223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 5544223637Sbz key.port[1] = key.port[0] = 0; 5545130613Smlaier } 5546126258Smlaier 5547223637Sbz#ifdef __FreeBSD__ 5548223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5549223637Sbz#else 5550223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5551223637Sbz#endif 5552126258Smlaier 5553126258Smlaier if (direction == (*state)->direction) { 5554126258Smlaier src = &(*state)->src; 5555126258Smlaier dst = &(*state)->dst; 5556126258Smlaier } else { 5557126258Smlaier src = &(*state)->dst; 5558126258Smlaier dst = &(*state)->src; 5559126258Smlaier } 5560126258Smlaier 5561126258Smlaier /* update states */ 5562126258Smlaier if (src->state < PFOTHERS_SINGLE) 5563126258Smlaier src->state = PFOTHERS_SINGLE; 5564126258Smlaier if (dst->state == PFOTHERS_SINGLE) 5565126258Smlaier dst->state = PFOTHERS_MULTIPLE; 5566126258Smlaier 5567126258Smlaier /* update expire time */ 5568126261Smlaier (*state)->expire = time_second; 5569126258Smlaier if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE) 5570126258Smlaier (*state)->timeout = PFTM_OTHER_MULTIPLE; 5571126258Smlaier else 5572126258Smlaier (*state)->timeout = PFTM_OTHER_SINGLE; 5573126258Smlaier 5574126258Smlaier /* translate source/destination address, if necessary */ 5575223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 5576223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 5577223637Sbz 5578223637Sbz#ifdef __FreeBSD__ 5579223637Sbz KASSERT(nk, ("%s: nk is null", __FUNCTION__)); 5580223637Sbz KASSERT(pd, ("%s: pd is null", __FUNCTION__)); 5581223637Sbz KASSERT(pd->src, ("%s: pd->src is null", __FUNCTION__)); 5582223637Sbz KASSERT(pd->dst, ("%s: pd->dst is null", __FUNCTION__)); 5583223637Sbz#else 5584223637Sbz KASSERT(nk); 5585223637Sbz KASSERT(pd); 5586223637Sbz KASSERT(pd->src); 5587223637Sbz KASSERT(pd->dst); 5588223637Sbz#endif 5589223637Sbz switch (pd->af) { 5590126258Smlaier#ifdef INET 5591223637Sbz case AF_INET: 5592223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) 5593126258Smlaier pf_change_a(&pd->src->v4.s_addr, 5594223637Sbz pd->ip_sum, 5595223637Sbz nk->addr[pd->sidx].v4.s_addr, 5596126258Smlaier 0); 5597223637Sbz 5598223637Sbz 5599223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) 5600126258Smlaier pf_change_a(&pd->dst->v4.s_addr, 5601223637Sbz pd->ip_sum, 5602223637Sbz nk->addr[pd->didx].v4.s_addr, 5603126258Smlaier 0); 5604223637Sbz 5605126258Smlaier break; 5606126258Smlaier#endif /* INET */ 5607126258Smlaier#ifdef INET6 5608223637Sbz case AF_INET6: 5609223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) 5610223637Sbz PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); 5611223637Sbz 5612223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) 5613223637Sbz PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); 5614126258Smlaier#endif /* INET6 */ 5615223637Sbz } 5616126258Smlaier } 5617126258Smlaier return (PF_PASS); 5618126258Smlaier} 5619126258Smlaier 5620126258Smlaier/* 5621126258Smlaier * ipoff and off are measured from the start of the mbuf chain. 5622126258Smlaier * h must be at "ipoff" on the mbuf chain. 5623126258Smlaier */ 5624126258Smlaiervoid * 5625126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len, 5626126258Smlaier u_short *actionp, u_short *reasonp, sa_family_t af) 5627126258Smlaier{ 5628126258Smlaier switch (af) { 5629126258Smlaier#ifdef INET 5630126258Smlaier case AF_INET: { 5631126258Smlaier struct ip *h = mtod(m, struct ip *); 5632126258Smlaier u_int16_t fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3; 5633126258Smlaier 5634126258Smlaier if (fragoff) { 5635126258Smlaier if (fragoff >= len) 5636126258Smlaier ACTION_SET(actionp, PF_PASS); 5637126258Smlaier else { 5638126258Smlaier ACTION_SET(actionp, PF_DROP); 5639126258Smlaier REASON_SET(reasonp, PFRES_FRAG); 5640126258Smlaier } 5641126258Smlaier return (NULL); 5642126258Smlaier } 5643130613Smlaier if (m->m_pkthdr.len < off + len || 5644130613Smlaier ntohs(h->ip_len) < off + len) { 5645126258Smlaier ACTION_SET(actionp, PF_DROP); 5646126258Smlaier REASON_SET(reasonp, PFRES_SHORT); 5647126258Smlaier return (NULL); 5648126258Smlaier } 5649126258Smlaier break; 5650126258Smlaier } 5651126258Smlaier#endif /* INET */ 5652126258Smlaier#ifdef INET6 5653126258Smlaier case AF_INET6: { 5654126258Smlaier struct ip6_hdr *h = mtod(m, struct ip6_hdr *); 5655126258Smlaier 5656126258Smlaier if (m->m_pkthdr.len < off + len || 5657126258Smlaier (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) < 5658126258Smlaier (unsigned)(off + len)) { 5659126258Smlaier ACTION_SET(actionp, PF_DROP); 5660126258Smlaier REASON_SET(reasonp, PFRES_SHORT); 5661126258Smlaier return (NULL); 5662126258Smlaier } 5663126258Smlaier break; 5664126258Smlaier } 5665126258Smlaier#endif /* INET6 */ 5666126258Smlaier } 5667126258Smlaier m_copydata(m, off, len, p); 5668126258Smlaier return (p); 5669126258Smlaier} 5670126258Smlaier 5671126258Smlaierint 5672231852Sbzpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif, 5673231852Sbz int rtableid) 5674126258Smlaier{ 5675223637Sbz#ifdef __FreeBSD__ 5676223637Sbz#ifdef RADIX_MPATH 5677223637Sbz struct radix_node_head *rnh; 5678223637Sbz#endif 5679223637Sbz#endif 5680126258Smlaier struct sockaddr_in *dst; 5681171168Smlaier int ret = 1; 5682171168Smlaier int check_mpath; 5683171168Smlaier#ifndef __FreeBSD__ 5684171168Smlaier extern int ipmultipath; 5685171168Smlaier#endif 5686145836Smlaier#ifdef INET6 5687171168Smlaier#ifndef __FreeBSD__ 5688171168Smlaier extern int ip6_multipath; 5689171168Smlaier#endif 5690145836Smlaier struct sockaddr_in6 *dst6; 5691145836Smlaier struct route_in6 ro; 5692145836Smlaier#else 5693126258Smlaier struct route ro; 5694145836Smlaier#endif 5695171168Smlaier struct radix_node *rn; 5696171168Smlaier struct rtentry *rt; 5697171168Smlaier struct ifnet *ifp; 5698126258Smlaier 5699171168Smlaier check_mpath = 0; 5700223637Sbz#ifdef __FreeBSD__ 5701223637Sbz#ifdef RADIX_MPATH 5702223637Sbz /* XXX: stick to table 0 for now */ 5703223637Sbz rnh = rt_tables_get_rnh(0, af); 5704223637Sbz if (rnh != NULL && rn_mpath_capable(rnh)) 5705223637Sbz check_mpath = 1; 5706223637Sbz#endif 5707223637Sbz#endif 5708126258Smlaier bzero(&ro, sizeof(ro)); 5709145836Smlaier switch (af) { 5710145836Smlaier case AF_INET: 5711145836Smlaier dst = satosin(&ro.ro_dst); 5712145836Smlaier dst->sin_family = AF_INET; 5713145836Smlaier dst->sin_len = sizeof(*dst); 5714145836Smlaier dst->sin_addr = addr->v4; 5715223637Sbz#ifndef __FreeBSD__ 5716171168Smlaier if (ipmultipath) 5717171168Smlaier check_mpath = 1; 5718171168Smlaier#endif 5719145836Smlaier break; 5720145836Smlaier#ifdef INET6 5721145836Smlaier case AF_INET6: 5722223637Sbz /* 5723223637Sbz * Skip check for addresses with embedded interface scope, 5724223637Sbz * as they would always match anyway. 5725223637Sbz */ 5726223637Sbz if (IN6_IS_SCOPE_EMBED(&addr->v6)) 5727223637Sbz goto out; 5728145836Smlaier dst6 = (struct sockaddr_in6 *)&ro.ro_dst; 5729145836Smlaier dst6->sin6_family = AF_INET6; 5730145836Smlaier dst6->sin6_len = sizeof(*dst6); 5731145836Smlaier dst6->sin6_addr = addr->v6; 5732223637Sbz#ifndef __FreeBSD__ 5733171168Smlaier if (ip6_multipath) 5734171168Smlaier check_mpath = 1; 5735171168Smlaier#endif 5736145836Smlaier break; 5737145836Smlaier#endif /* INET6 */ 5738145836Smlaier default: 5739145836Smlaier return (0); 5740145836Smlaier } 5741145836Smlaier 5742171168Smlaier /* Skip checks for ipsec interfaces */ 5743171168Smlaier if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC) 5744171168Smlaier goto out; 5745171168Smlaier 5746127145Smlaier#ifdef __FreeBSD__ 5747231852Sbz switch (af) { 5748231852Sbz#ifdef INET6 5749231852Sbz case AF_INET6: 5750231852Sbz in6_rtalloc_ign(&ro, 0, rtableid); 5751231852Sbz break; 5752231852Sbz#endif 5753222529Sbz#ifdef INET 5754231852Sbz case AF_INET: 5755231852Sbz in_rtalloc_ign((struct route *)&ro, 0, rtableid); 5756231852Sbz break; 5757222529Sbz#endif 5758231852Sbz default: 5759231852Sbz rtalloc_ign((struct route *)&ro, 0); /* No/default FIB. */ 5760231852Sbz break; 5761231852Sbz } 5762126261Smlaier#else /* ! __FreeBSD__ */ 5763145836Smlaier rtalloc_noclone((struct route *)&ro, NO_CLONING); 5764126261Smlaier#endif 5765126258Smlaier 5766126258Smlaier if (ro.ro_rt != NULL) { 5767171168Smlaier /* No interface given, this is a no-route check */ 5768171168Smlaier if (kif == NULL) 5769171168Smlaier goto out; 5770171168Smlaier 5771171168Smlaier if (kif->pfik_ifp == NULL) { 5772171168Smlaier ret = 0; 5773171168Smlaier goto out; 5774171168Smlaier } 5775171168Smlaier 5776171168Smlaier /* Perform uRPF check if passed input interface */ 5777171168Smlaier ret = 0; 5778171168Smlaier rn = (struct radix_node *)ro.ro_rt; 5779171168Smlaier do { 5780171168Smlaier rt = (struct rtentry *)rn; 5781171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */ 5782171168Smlaier if (rt->rt_ifp->if_type == IFT_CARP) 5783171168Smlaier ifp = rt->rt_ifp->if_carpdev; 5784171168Smlaier else 5785171168Smlaier#endif 5786171168Smlaier ifp = rt->rt_ifp; 5787171168Smlaier 5788171168Smlaier if (kif->pfik_ifp == ifp) 5789171168Smlaier ret = 1; 5790223637Sbz#ifdef __FreeBSD__ 5791223637Sbz#ifdef RADIX_MPATH 5792171168Smlaier rn = rn_mpath_next(rn); 5793171168Smlaier#endif 5794223637Sbz#else 5795223637Sbz rn = rn_mpath_next(rn, 0); 5796223637Sbz#endif 5797171168Smlaier } while (check_mpath == 1 && rn != NULL && ret == 0); 5798171168Smlaier } else 5799171168Smlaier ret = 0; 5800171168Smlaierout: 5801171168Smlaier if (ro.ro_rt != NULL) 5802126258Smlaier RTFREE(ro.ro_rt); 5803171168Smlaier return (ret); 5804145836Smlaier} 5805145836Smlaier 5806145836Smlaierint 5807231852Sbzpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw, 5808231852Sbz int rtableid) 5809145836Smlaier{ 5810145836Smlaier struct sockaddr_in *dst; 5811145836Smlaier#ifdef INET6 5812145836Smlaier struct sockaddr_in6 *dst6; 5813145836Smlaier struct route_in6 ro; 5814145836Smlaier#else 5815145836Smlaier struct route ro; 5816145836Smlaier#endif 5817145836Smlaier int ret = 0; 5818145836Smlaier 5819145836Smlaier bzero(&ro, sizeof(ro)); 5820145836Smlaier switch (af) { 5821145836Smlaier case AF_INET: 5822145836Smlaier dst = satosin(&ro.ro_dst); 5823145836Smlaier dst->sin_family = AF_INET; 5824145836Smlaier dst->sin_len = sizeof(*dst); 5825145836Smlaier dst->sin_addr = addr->v4; 5826145836Smlaier break; 5827145836Smlaier#ifdef INET6 5828145836Smlaier case AF_INET6: 5829145836Smlaier dst6 = (struct sockaddr_in6 *)&ro.ro_dst; 5830145836Smlaier dst6->sin6_family = AF_INET6; 5831145836Smlaier dst6->sin6_len = sizeof(*dst6); 5832145836Smlaier dst6->sin6_addr = addr->v6; 5833145836Smlaier break; 5834145836Smlaier#endif /* INET6 */ 5835145836Smlaier default: 5836145836Smlaier return (0); 5837145836Smlaier } 5838145836Smlaier 5839145836Smlaier#ifdef __FreeBSD__ 5840231852Sbz switch (af) { 5841231852Sbz#ifdef INET6 5842231852Sbz case AF_INET6: 5843231852Sbz in6_rtalloc_ign(&ro, 0, rtableid); 5844231852Sbz break; 5845231852Sbz#endif 5846222529Sbz#ifdef INET 5847231852Sbz case AF_INET: 5848231852Sbz in_rtalloc_ign((struct route *)&ro, 0, rtableid); 5849231852Sbz break; 5850222529Sbz#endif 5851231852Sbz default: 5852186119Sqingli rtalloc_ign((struct route *)&ro, 0); 5853231852Sbz break; 5854231852Sbz } 5855145836Smlaier#else /* ! __FreeBSD__ */ 5856145836Smlaier rtalloc_noclone((struct route *)&ro, NO_CLONING); 5857145836Smlaier#endif 5858145836Smlaier 5859145836Smlaier if (ro.ro_rt != NULL) { 5860145836Smlaier#ifdef __FreeBSD__ 5861145836Smlaier /* XXX_IMPORT: later */ 5862145836Smlaier#else 5863145836Smlaier if (ro.ro_rt->rt_labelid == aw->v.rtlabel) 5864145836Smlaier ret = 1; 5865145836Smlaier#endif 5866145836Smlaier RTFREE(ro.ro_rt); 5867145836Smlaier } 5868145836Smlaier 5869126258Smlaier return (ret); 5870126258Smlaier} 5871126258Smlaier 5872126258Smlaier#ifdef INET 5873126258Smlaiervoid 5874126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 5875171168Smlaier struct pf_state *s, struct pf_pdesc *pd) 5876126258Smlaier{ 5877126258Smlaier struct mbuf *m0, *m1; 5878126258Smlaier struct route iproute; 5879171168Smlaier struct route *ro = NULL; 5880126258Smlaier struct sockaddr_in *dst; 5881126258Smlaier struct ip *ip; 5882126258Smlaier struct ifnet *ifp = NULL; 5883126258Smlaier struct pf_addr naddr; 5884130613Smlaier struct pf_src_node *sn = NULL; 5885126258Smlaier int error = 0; 5886127145Smlaier#ifdef __FreeBSD__ 5887126261Smlaier int sw_csum; 5888126261Smlaier#endif 5889171168Smlaier#ifdef IPSEC 5890171168Smlaier struct m_tag *mtag; 5891171168Smlaier#endif /* IPSEC */ 5892126258Smlaier 5893126258Smlaier if (m == NULL || *m == NULL || r == NULL || 5894126258Smlaier (dir != PF_IN && dir != PF_OUT) || oifp == NULL) 5895126258Smlaier panic("pf_route: invalid parameters"); 5896126258Smlaier 5897223637Sbz#ifdef __FreeBSD__ 5898171168Smlaier if (pd->pf_mtag->routed++ > 3) { 5899223637Sbz#else 5900223637Sbz if ((*m)->m_pkthdr.pf.routed++ > 3) { 5901223637Sbz#endif 5902171168Smlaier m0 = *m; 5903171168Smlaier *m = NULL; 5904171168Smlaier goto bad; 5905132303Smlaier } 5906132303Smlaier 5907126258Smlaier if (r->rt == PF_DUPTO) { 5908127145Smlaier#ifdef __FreeBSD__ 5909132303Smlaier if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) 5910126261Smlaier#else 5911132303Smlaier if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) 5912126261Smlaier#endif 5913126258Smlaier return; 5914126258Smlaier } else { 5915126258Smlaier if ((r->rt == PF_REPLYTO) == (r->direction == dir)) 5916126258Smlaier return; 5917126258Smlaier m0 = *m; 5918126258Smlaier } 5919126258Smlaier 5920145836Smlaier if (m0->m_len < sizeof(struct ip)) { 5921145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 5922145836Smlaier ("pf_route: m0->m_len < sizeof(struct ip)\n")); 5923145836Smlaier goto bad; 5924145836Smlaier } 5925145836Smlaier 5926126258Smlaier ip = mtod(m0, struct ip *); 5927126258Smlaier 5928126258Smlaier ro = &iproute; 5929126258Smlaier bzero((caddr_t)ro, sizeof(*ro)); 5930126258Smlaier dst = satosin(&ro->ro_dst); 5931126258Smlaier dst->sin_family = AF_INET; 5932126258Smlaier dst->sin_len = sizeof(*dst); 5933126258Smlaier dst->sin_addr = ip->ip_dst; 5934126258Smlaier 5935126258Smlaier if (r->rt == PF_FASTROUTE) { 5936223637Sbz#ifdef __FreeBSD__ 5937231852Sbz in_rtalloc_ign(ro, 0, M_GETFIB(m0)); 5938223637Sbz#else 5939223637Sbz rtalloc(ro); 5940223637Sbz#endif 5941126258Smlaier if (ro->ro_rt == 0) { 5942223637Sbz#ifdef __FreeBSD__ 5943196039Srwatson KMOD_IPSTAT_INC(ips_noroute); 5944223637Sbz#else 5945223637Sbz ipstat.ips_noroute++; 5946223637Sbz#endif 5947126258Smlaier goto bad; 5948126258Smlaier } 5949126258Smlaier 5950126258Smlaier ifp = ro->ro_rt->rt_ifp; 5951126258Smlaier ro->ro_rt->rt_use++; 5952126258Smlaier 5953126258Smlaier if (ro->ro_rt->rt_flags & RTF_GATEWAY) 5954126258Smlaier dst = satosin(ro->ro_rt->rt_gateway); 5955126258Smlaier } else { 5956145836Smlaier if (TAILQ_EMPTY(&r->rpool.list)) { 5957145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 5958145836Smlaier ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n")); 5959145836Smlaier goto bad; 5960145836Smlaier } 5961126258Smlaier if (s == NULL) { 5962130613Smlaier pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src, 5963130613Smlaier &naddr, NULL, &sn); 5964126258Smlaier if (!PF_AZERO(&naddr, AF_INET)) 5965126258Smlaier dst->sin_addr.s_addr = naddr.v4.s_addr; 5966130613Smlaier ifp = r->rpool.cur->kif ? 5967130613Smlaier r->rpool.cur->kif->pfik_ifp : NULL; 5968126258Smlaier } else { 5969126258Smlaier if (!PF_AZERO(&s->rt_addr, AF_INET)) 5970126258Smlaier dst->sin_addr.s_addr = 5971126258Smlaier s->rt_addr.v4.s_addr; 5972130613Smlaier ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; 5973126258Smlaier } 5974126258Smlaier } 5975126258Smlaier if (ifp == NULL) 5976126258Smlaier goto bad; 5977126258Smlaier 5978130639Smlaier if (oifp != ifp) { 5979127145Smlaier#ifdef __FreeBSD__ 5980126261Smlaier PF_UNLOCK(); 5981145836Smlaier if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { 5982126261Smlaier PF_LOCK(); 5983126261Smlaier goto bad; 5984126261Smlaier } else if (m0 == NULL) { 5985126261Smlaier PF_LOCK(); 5986126261Smlaier goto done; 5987126261Smlaier } 5988126261Smlaier PF_LOCK(); 5989126261Smlaier#else 5990145836Smlaier if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) 5991126258Smlaier goto bad; 5992126258Smlaier else if (m0 == NULL) 5993126258Smlaier goto done; 5994126261Smlaier#endif 5995145836Smlaier if (m0->m_len < sizeof(struct ip)) { 5996145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 5997145836Smlaier ("pf_route: m0->m_len < sizeof(struct ip)\n")); 5998145836Smlaier goto bad; 5999145836Smlaier } 6000126258Smlaier ip = mtod(m0, struct ip *); 6001126258Smlaier } 6002126258Smlaier 6003127145Smlaier#ifdef __FreeBSD__ 6004126261Smlaier /* Copied from FreeBSD 5.1-CURRENT ip_output. */ 6005126261Smlaier m0->m_pkthdr.csum_flags |= CSUM_IP; 6006126261Smlaier sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist; 6007126261Smlaier if (sw_csum & CSUM_DELAY_DATA) { 6008126261Smlaier /* 6009126261Smlaier * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least) 6010126261Smlaier */ 6011126261Smlaier NTOHS(ip->ip_len); 6012223637Sbz NTOHS(ip->ip_off); /* XXX: needed? */ 6013126261Smlaier in_delayed_cksum(m0); 6014126261Smlaier HTONS(ip->ip_len); 6015126261Smlaier HTONS(ip->ip_off); 6016126261Smlaier sw_csum &= ~CSUM_DELAY_DATA; 6017126261Smlaier } 6018126261Smlaier m0->m_pkthdr.csum_flags &= ifp->if_hwassist; 6019126261Smlaier 6020126261Smlaier if (ntohs(ip->ip_len) <= ifp->if_mtu || 6021126261Smlaier (ifp->if_hwassist & CSUM_FRAGMENT && 6022223637Sbz ((ip->ip_off & htons(IP_DF)) == 0))) { 6023126261Smlaier /* 6024126261Smlaier * ip->ip_len = htons(ip->ip_len); 6025126261Smlaier * ip->ip_off = htons(ip->ip_off); 6026126261Smlaier */ 6027126261Smlaier ip->ip_sum = 0; 6028126261Smlaier if (sw_csum & CSUM_DELAY_IP) { 6029126261Smlaier /* From KAME */ 6030126261Smlaier if (ip->ip_v == IPVERSION && 6031126261Smlaier (ip->ip_hl << 2) == sizeof(*ip)) { 6032126261Smlaier ip->ip_sum = in_cksum_hdr(ip); 6033126261Smlaier } else { 6034126261Smlaier ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); 6035126261Smlaier } 6036126261Smlaier } 6037126261Smlaier PF_UNLOCK(); 6038191148Skmacy error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro); 6039126261Smlaier PF_LOCK(); 6040126261Smlaier goto done; 6041126261Smlaier } 6042126261Smlaier#else 6043126258Smlaier /* Copied from ip_output. */ 6044130613Smlaier#ifdef IPSEC 6045130613Smlaier /* 6046130613Smlaier * If deferred crypto processing is needed, check that the 6047130613Smlaier * interface supports it. 6048130613Smlaier */ 6049130613Smlaier if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL)) 6050130613Smlaier != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) { 6051130613Smlaier /* Notify IPsec to do its own crypto. */ 6052130613Smlaier ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1)); 6053130613Smlaier goto bad; 6054130613Smlaier } 6055130613Smlaier#endif /* IPSEC */ 6056130613Smlaier 6057130613Smlaier /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */ 6058171168Smlaier if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) { 6059130613Smlaier if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || 6060130613Smlaier ifp->if_bridge != NULL) { 6061130613Smlaier in_delayed_cksum(m0); 6062223637Sbz m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clr */ 6063130613Smlaier } 6064171168Smlaier } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) { 6065130613Smlaier if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) || 6066130613Smlaier ifp->if_bridge != NULL) { 6067130613Smlaier in_delayed_cksum(m0); 6068223637Sbz m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clr */ 6069130613Smlaier } 6070130613Smlaier } 6071130613Smlaier 6072126258Smlaier if (ntohs(ip->ip_len) <= ifp->if_mtu) { 6073223637Sbz ip->ip_sum = 0; 6074126258Smlaier if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && 6075126258Smlaier ifp->if_bridge == NULL) { 6076171168Smlaier m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; 6077223637Sbz#ifdef __FreeBSD__ 6078196039Srwatson KMOD_IPSTAT_INC(ips_outhwcsum); 6079223637Sbz#else 6080223637Sbz ipstat.ips_outhwcsum++; 6081223637Sbz#endif 6082223637Sbz } else 6083126258Smlaier ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); 6084126258Smlaier /* Update relevant hardware checksum stats for TCP/UDP */ 6085171168Smlaier if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) 6086196039Srwatson KMOD_TCPSTAT_INC(tcps_outhwcsum); 6087171168Smlaier else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) 6088196039Srwatson KMOD_UDPSTAT_INC(udps_outhwcsum); 6089126258Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); 6090126258Smlaier goto done; 6091126258Smlaier } 6092126261Smlaier#endif 6093223637Sbz 6094126258Smlaier /* 6095126258Smlaier * Too large for interface; fragment if possible. 6096126258Smlaier * Must be able to put at least 8 bytes per fragment. 6097126258Smlaier */ 6098223637Sbz if (ip->ip_off & htons(IP_DF)) { 6099223637Sbz#ifdef __FreeBSD__ 6100196039Srwatson KMOD_IPSTAT_INC(ips_cantfrag); 6101223637Sbz#else 6102223637Sbz ipstat.ips_cantfrag++; 6103223637Sbz#endif 6104126258Smlaier if (r->rt != PF_DUPTO) { 6105127145Smlaier#ifdef __FreeBSD__ 6106126261Smlaier /* icmp_error() expects host byte ordering */ 6107126261Smlaier NTOHS(ip->ip_len); 6108126261Smlaier NTOHS(ip->ip_off); 6109126261Smlaier PF_UNLOCK(); 6110126258Smlaier icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, 6111145886Smlaier ifp->if_mtu); 6112145874Smlaier PF_LOCK(); 6113145874Smlaier#else 6114145874Smlaier icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, 6115171168Smlaier ifp->if_mtu); 6116126261Smlaier#endif 6117126258Smlaier goto done; 6118126258Smlaier } else 6119126258Smlaier goto bad; 6120126258Smlaier } 6121126258Smlaier 6122126258Smlaier m1 = m0; 6123127145Smlaier#ifdef __FreeBSD__ 6124126261Smlaier /* 6125126261Smlaier * XXX: is cheaper + less error prone than own function 6126126261Smlaier */ 6127126261Smlaier NTOHS(ip->ip_len); 6128126261Smlaier NTOHS(ip->ip_off); 6129126261Smlaier error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum); 6130126261Smlaier#else 6131126258Smlaier error = ip_fragment(m0, ifp, ifp->if_mtu); 6132126261Smlaier#endif 6133127531Smlaier if (error) { 6134223637Sbz#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ 6135127531Smlaier m0 = NULL; 6136126261Smlaier#endif 6137126258Smlaier goto bad; 6138127531Smlaier } 6139126258Smlaier 6140126258Smlaier for (m0 = m1; m0; m0 = m1) { 6141126258Smlaier m1 = m0->m_nextpkt; 6142126258Smlaier m0->m_nextpkt = 0; 6143127145Smlaier#ifdef __FreeBSD__ 6144126261Smlaier if (error == 0) { 6145126261Smlaier PF_UNLOCK(); 6146126261Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), 6147126261Smlaier NULL); 6148126261Smlaier PF_LOCK(); 6149126261Smlaier } else 6150126261Smlaier#else 6151126258Smlaier if (error == 0) 6152126258Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), 6153126258Smlaier NULL); 6154126258Smlaier else 6155126261Smlaier#endif 6156126258Smlaier m_freem(m0); 6157126258Smlaier } 6158126258Smlaier 6159126258Smlaier if (error == 0) 6160223637Sbz#ifdef __FreeBSD__ 6161196039Srwatson KMOD_IPSTAT_INC(ips_fragmented); 6162223637Sbz#else 6163223637Sbz ipstat.ips_fragmented++; 6164223637Sbz#endif 6165126258Smlaier 6166126258Smlaierdone: 6167126258Smlaier if (r->rt != PF_DUPTO) 6168126258Smlaier *m = NULL; 6169126258Smlaier if (ro == &iproute && ro->ro_rt) 6170126258Smlaier RTFREE(ro->ro_rt); 6171126258Smlaier return; 6172126258Smlaier 6173126258Smlaierbad: 6174126258Smlaier m_freem(m0); 6175126258Smlaier goto done; 6176126258Smlaier} 6177126258Smlaier#endif /* INET */ 6178126258Smlaier 6179126258Smlaier#ifdef INET6 6180126258Smlaiervoid 6181126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 6182171168Smlaier struct pf_state *s, struct pf_pdesc *pd) 6183126258Smlaier{ 6184126258Smlaier struct mbuf *m0; 6185126258Smlaier struct route_in6 ip6route; 6186126258Smlaier struct route_in6 *ro; 6187126258Smlaier struct sockaddr_in6 *dst; 6188126258Smlaier struct ip6_hdr *ip6; 6189126258Smlaier struct ifnet *ifp = NULL; 6190126258Smlaier struct pf_addr naddr; 6191130613Smlaier struct pf_src_node *sn = NULL; 6192126258Smlaier 6193126258Smlaier if (m == NULL || *m == NULL || r == NULL || 6194126258Smlaier (dir != PF_IN && dir != PF_OUT) || oifp == NULL) 6195126258Smlaier panic("pf_route6: invalid parameters"); 6196126258Smlaier 6197223637Sbz#ifdef __FreeBSD__ 6198171168Smlaier if (pd->pf_mtag->routed++ > 3) { 6199223637Sbz#else 6200223637Sbz if ((*m)->m_pkthdr.pf.routed++ > 3) { 6201223637Sbz#endif 6202171168Smlaier m0 = *m; 6203171168Smlaier *m = NULL; 6204171168Smlaier goto bad; 6205132303Smlaier } 6206132303Smlaier 6207126258Smlaier if (r->rt == PF_DUPTO) { 6208127145Smlaier#ifdef __FreeBSD__ 6209132303Smlaier if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) 6210126261Smlaier#else 6211132303Smlaier if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) 6212126261Smlaier#endif 6213126258Smlaier return; 6214126258Smlaier } else { 6215126258Smlaier if ((r->rt == PF_REPLYTO) == (r->direction == dir)) 6216126258Smlaier return; 6217126258Smlaier m0 = *m; 6218126258Smlaier } 6219126258Smlaier 6220145836Smlaier if (m0->m_len < sizeof(struct ip6_hdr)) { 6221145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6222145836Smlaier ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); 6223145836Smlaier goto bad; 6224145836Smlaier } 6225126258Smlaier ip6 = mtod(m0, struct ip6_hdr *); 6226126258Smlaier 6227126258Smlaier ro = &ip6route; 6228126258Smlaier bzero((caddr_t)ro, sizeof(*ro)); 6229126258Smlaier dst = (struct sockaddr_in6 *)&ro->ro_dst; 6230126258Smlaier dst->sin6_family = AF_INET6; 6231126258Smlaier dst->sin6_len = sizeof(*dst); 6232126258Smlaier dst->sin6_addr = ip6->ip6_dst; 6233126258Smlaier 6234171168Smlaier /* Cheat. XXX why only in the v6 case??? */ 6235126258Smlaier if (r->rt == PF_FASTROUTE) { 6236127145Smlaier#ifdef __FreeBSD__ 6237132280Smlaier m0->m_flags |= M_SKIP_FIREWALL; 6238126261Smlaier PF_UNLOCK(); 6239126261Smlaier ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 6240126261Smlaier#else 6241223637Sbz m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 6242223637Sbz ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 6243126261Smlaier#endif 6244126258Smlaier return; 6245126258Smlaier } 6246126258Smlaier 6247145836Smlaier if (TAILQ_EMPTY(&r->rpool.list)) { 6248145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6249145836Smlaier ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n")); 6250145836Smlaier goto bad; 6251145836Smlaier } 6252126258Smlaier if (s == NULL) { 6253130613Smlaier pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src, 6254130613Smlaier &naddr, NULL, &sn); 6255126258Smlaier if (!PF_AZERO(&naddr, AF_INET6)) 6256126258Smlaier PF_ACPY((struct pf_addr *)&dst->sin6_addr, 6257126258Smlaier &naddr, AF_INET6); 6258130613Smlaier ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL; 6259126258Smlaier } else { 6260126258Smlaier if (!PF_AZERO(&s->rt_addr, AF_INET6)) 6261126258Smlaier PF_ACPY((struct pf_addr *)&dst->sin6_addr, 6262126258Smlaier &s->rt_addr, AF_INET6); 6263130613Smlaier ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; 6264126258Smlaier } 6265126258Smlaier if (ifp == NULL) 6266126258Smlaier goto bad; 6267126258Smlaier 6268126258Smlaier if (oifp != ifp) { 6269127145Smlaier#ifdef __FreeBSD__ 6270132303Smlaier PF_UNLOCK(); 6271145836Smlaier if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { 6272126261Smlaier PF_LOCK(); 6273132303Smlaier goto bad; 6274132303Smlaier } else if (m0 == NULL) { 6275132303Smlaier PF_LOCK(); 6276132303Smlaier goto done; 6277132303Smlaier } 6278132303Smlaier PF_LOCK(); 6279126261Smlaier#else 6280145836Smlaier if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) 6281132303Smlaier goto bad; 6282132303Smlaier else if (m0 == NULL) 6283132303Smlaier goto done; 6284126261Smlaier#endif 6285145836Smlaier if (m0->m_len < sizeof(struct ip6_hdr)) { 6286145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6287145836Smlaier ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); 6288145836Smlaier goto bad; 6289145836Smlaier } 6290132303Smlaier ip6 = mtod(m0, struct ip6_hdr *); 6291126258Smlaier } 6292126258Smlaier 6293126258Smlaier /* 6294126258Smlaier * If the packet is too large for the outgoing interface, 6295126258Smlaier * send back an icmp6 error. 6296126258Smlaier */ 6297171168Smlaier if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr)) 6298126258Smlaier dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index); 6299126258Smlaier if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { 6300127145Smlaier#ifdef __FreeBSD__ 6301126261Smlaier PF_UNLOCK(); 6302126261Smlaier#endif 6303223637Sbz nd6_output(ifp, ifp, m0, dst, NULL); 6304127145Smlaier#ifdef __FreeBSD__ 6305126261Smlaier PF_LOCK(); 6306126261Smlaier#endif 6307126258Smlaier } else { 6308126258Smlaier in6_ifstat_inc(ifp, ifs6_in_toobig); 6309127145Smlaier#ifdef __FreeBSD__ 6310126261Smlaier if (r->rt != PF_DUPTO) { 6311126261Smlaier PF_UNLOCK(); 6312126261Smlaier icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); 6313126261Smlaier PF_LOCK(); 6314223637Sbz } else 6315126261Smlaier#else 6316126258Smlaier if (r->rt != PF_DUPTO) 6317126258Smlaier icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); 6318126258Smlaier else 6319126261Smlaier#endif 6320126258Smlaier goto bad; 6321126258Smlaier } 6322126258Smlaier 6323126258Smlaierdone: 6324126258Smlaier if (r->rt != PF_DUPTO) 6325126258Smlaier *m = NULL; 6326126258Smlaier return; 6327126258Smlaier 6328126258Smlaierbad: 6329126258Smlaier m_freem(m0); 6330126258Smlaier goto done; 6331126258Smlaier} 6332126258Smlaier#endif /* INET6 */ 6333126258Smlaier 6334127145Smlaier#ifdef __FreeBSD__ 6335126258Smlaier/* 6336132566Smlaier * FreeBSD supports cksum offloads for the following drivers. 6337137413Sru * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4), 6338132566Smlaier * ti(4), txp(4), xl(4) 6339132566Smlaier * 6340132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR : 6341132566Smlaier * network driver performed cksum including pseudo header, need to verify 6342132566Smlaier * csum_data 6343132566Smlaier * CSUM_DATA_VALID : 6344132566Smlaier * network driver performed cksum, needs to additional pseudo header 6345132566Smlaier * cksum computation with partial csum_data(i.e. lack of H/W support for 6346132566Smlaier * pseudo header, for instance hme(4), sk(4) and possibly gem(4)) 6347132566Smlaier * 6348132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and 6349132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper 6350132566Smlaier * TCP/UDP layer. 6351132566Smlaier * Also, set csum_data to 0xffff to force cksum validation. 6352126261Smlaier */ 6353126261Smlaierint 6354126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af) 6355126261Smlaier{ 6356126261Smlaier u_int16_t sum = 0; 6357126261Smlaier int hw_assist = 0; 6358126261Smlaier struct ip *ip; 6359126261Smlaier 6360126261Smlaier if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) 6361126261Smlaier return (1); 6362126261Smlaier if (m->m_pkthdr.len < off + len) 6363126261Smlaier return (1); 6364126261Smlaier 6365126261Smlaier switch (p) { 6366126261Smlaier case IPPROTO_TCP: 6367126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 6368126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { 6369126261Smlaier sum = m->m_pkthdr.csum_data; 6370126261Smlaier } else { 6371223637Sbz ip = mtod(m, struct ip *); 6372126261Smlaier sum = in_pseudo(ip->ip_src.s_addr, 6373223637Sbz ip->ip_dst.s_addr, htonl((u_short)len + 6374223637Sbz m->m_pkthdr.csum_data + IPPROTO_TCP)); 6375126261Smlaier } 6376126261Smlaier sum ^= 0xffff; 6377126261Smlaier ++hw_assist; 6378126261Smlaier } 6379126261Smlaier break; 6380126261Smlaier case IPPROTO_UDP: 6381126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 6382126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { 6383126261Smlaier sum = m->m_pkthdr.csum_data; 6384126261Smlaier } else { 6385223637Sbz ip = mtod(m, struct ip *); 6386126261Smlaier sum = in_pseudo(ip->ip_src.s_addr, 6387223637Sbz ip->ip_dst.s_addr, htonl((u_short)len + 6388223637Sbz m->m_pkthdr.csum_data + IPPROTO_UDP)); 6389126261Smlaier } 6390126261Smlaier sum ^= 0xffff; 6391126261Smlaier ++hw_assist; 6392223637Sbz } 6393126261Smlaier break; 6394126261Smlaier case IPPROTO_ICMP: 6395126261Smlaier#ifdef INET6 6396126261Smlaier case IPPROTO_ICMPV6: 6397126261Smlaier#endif /* INET6 */ 6398126261Smlaier break; 6399126261Smlaier default: 6400126261Smlaier return (1); 6401126261Smlaier } 6402126261Smlaier 6403126261Smlaier if (!hw_assist) { 6404126261Smlaier switch (af) { 6405126261Smlaier case AF_INET: 6406126261Smlaier if (p == IPPROTO_ICMP) { 6407126261Smlaier if (m->m_len < off) 6408126261Smlaier return (1); 6409126261Smlaier m->m_data += off; 6410126261Smlaier m->m_len -= off; 6411126261Smlaier sum = in_cksum(m, len); 6412126261Smlaier m->m_data -= off; 6413126261Smlaier m->m_len += off; 6414126261Smlaier } else { 6415126261Smlaier if (m->m_len < sizeof(struct ip)) 6416126261Smlaier return (1); 6417126261Smlaier sum = in4_cksum(m, p, off, len); 6418126261Smlaier } 6419126261Smlaier break; 6420126261Smlaier#ifdef INET6 6421126261Smlaier case AF_INET6: 6422126261Smlaier if (m->m_len < sizeof(struct ip6_hdr)) 6423126261Smlaier return (1); 6424126261Smlaier sum = in6_cksum(m, p, off, len); 6425126261Smlaier break; 6426126261Smlaier#endif /* INET6 */ 6427126261Smlaier default: 6428126261Smlaier return (1); 6429126261Smlaier } 6430126261Smlaier } 6431126261Smlaier if (sum) { 6432126261Smlaier switch (p) { 6433126261Smlaier case IPPROTO_TCP: 6434183550Szec { 6435196039Srwatson KMOD_TCPSTAT_INC(tcps_rcvbadsum); 6436126261Smlaier break; 6437183550Szec } 6438126261Smlaier case IPPROTO_UDP: 6439183550Szec { 6440196039Srwatson KMOD_UDPSTAT_INC(udps_badsum); 6441126261Smlaier break; 6442183550Szec } 6443222529Sbz#ifdef INET 6444126261Smlaier case IPPROTO_ICMP: 6445183550Szec { 6446196039Srwatson KMOD_ICMPSTAT_INC(icps_checksum); 6447126261Smlaier break; 6448183550Szec } 6449222529Sbz#endif 6450126261Smlaier#ifdef INET6 6451126261Smlaier case IPPROTO_ICMPV6: 6452183550Szec { 6453196039Srwatson KMOD_ICMP6STAT_INC(icp6s_checksum); 6454126261Smlaier break; 6455183550Szec } 6456126261Smlaier#endif /* INET6 */ 6457126261Smlaier } 6458126261Smlaier return (1); 6459132566Smlaier } else { 6460132566Smlaier if (p == IPPROTO_TCP || p == IPPROTO_UDP) { 6461132566Smlaier m->m_pkthdr.csum_flags |= 6462132566Smlaier (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 6463132566Smlaier m->m_pkthdr.csum_data = 0xffff; 6464132566Smlaier } 6465126261Smlaier } 6466126261Smlaier return (0); 6467126261Smlaier} 6468171168Smlaier#else /* !__FreeBSD__ */ 6469223637Sbz 6470126261Smlaier/* 6471126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag 6472126258Smlaier * off is the offset where the protocol header starts 6473126258Smlaier * len is the total length of protocol header plus payload 6474126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1. 6475126258Smlaier */ 6476126258Smlaierint 6477130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, 6478130613Smlaier sa_family_t af) 6479126258Smlaier{ 6480126258Smlaier u_int16_t flag_ok, flag_bad; 6481126258Smlaier u_int16_t sum; 6482126258Smlaier 6483126258Smlaier switch (p) { 6484126258Smlaier case IPPROTO_TCP: 6485126258Smlaier flag_ok = M_TCP_CSUM_IN_OK; 6486126258Smlaier flag_bad = M_TCP_CSUM_IN_BAD; 6487126258Smlaier break; 6488126258Smlaier case IPPROTO_UDP: 6489126258Smlaier flag_ok = M_UDP_CSUM_IN_OK; 6490126258Smlaier flag_bad = M_UDP_CSUM_IN_BAD; 6491126258Smlaier break; 6492126258Smlaier case IPPROTO_ICMP: 6493126258Smlaier#ifdef INET6 6494126258Smlaier case IPPROTO_ICMPV6: 6495126258Smlaier#endif /* INET6 */ 6496126258Smlaier flag_ok = flag_bad = 0; 6497126258Smlaier break; 6498126258Smlaier default: 6499126258Smlaier return (1); 6500126258Smlaier } 6501171168Smlaier if (m->m_pkthdr.csum_flags & flag_ok) 6502126258Smlaier return (0); 6503171168Smlaier if (m->m_pkthdr.csum_flags & flag_bad) 6504126258Smlaier return (1); 6505126258Smlaier if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) 6506126258Smlaier return (1); 6507126258Smlaier if (m->m_pkthdr.len < off + len) 6508126258Smlaier return (1); 6509145836Smlaier switch (af) { 6510145836Smlaier#ifdef INET 6511126258Smlaier case AF_INET: 6512126258Smlaier if (p == IPPROTO_ICMP) { 6513126258Smlaier if (m->m_len < off) 6514126258Smlaier return (1); 6515126258Smlaier m->m_data += off; 6516126258Smlaier m->m_len -= off; 6517126258Smlaier sum = in_cksum(m, len); 6518126258Smlaier m->m_data -= off; 6519126258Smlaier m->m_len += off; 6520126258Smlaier } else { 6521126258Smlaier if (m->m_len < sizeof(struct ip)) 6522126258Smlaier return (1); 6523126258Smlaier sum = in4_cksum(m, p, off, len); 6524126258Smlaier } 6525126258Smlaier break; 6526145836Smlaier#endif /* INET */ 6527126258Smlaier#ifdef INET6 6528126258Smlaier case AF_INET6: 6529126258Smlaier if (m->m_len < sizeof(struct ip6_hdr)) 6530126258Smlaier return (1); 6531126258Smlaier sum = in6_cksum(m, p, off, len); 6532126258Smlaier break; 6533126258Smlaier#endif /* INET6 */ 6534126258Smlaier default: 6535126258Smlaier return (1); 6536126258Smlaier } 6537126258Smlaier if (sum) { 6538171168Smlaier m->m_pkthdr.csum_flags |= flag_bad; 6539126258Smlaier switch (p) { 6540126258Smlaier case IPPROTO_TCP: 6541196039Srwatson KMOD_TCPSTAT_INC(tcps_rcvbadsum); 6542126258Smlaier break; 6543126258Smlaier case IPPROTO_UDP: 6544196039Srwatson KMOD_UDPSTAT_INC(udps_badsum); 6545126258Smlaier break; 6546222529Sbz#ifdef INET 6547126258Smlaier case IPPROTO_ICMP: 6548196039Srwatson KMOD_ICMPSTAT_INC(icps_checksum); 6549126258Smlaier break; 6550222529Sbz#endif 6551126258Smlaier#ifdef INET6 6552126258Smlaier case IPPROTO_ICMPV6: 6553196039Srwatson KMOD_ICMP6STAT_INC(icp6s_checksum); 6554126258Smlaier break; 6555126258Smlaier#endif /* INET6 */ 6556126258Smlaier } 6557126258Smlaier return (1); 6558126258Smlaier } 6559171168Smlaier m->m_pkthdr.csum_flags |= flag_ok; 6560126258Smlaier return (0); 6561126258Smlaier} 6562223637Sbz#endif 6563126258Smlaier 6564223637Sbz#ifndef __FreeBSD__ 6565223637Sbzstruct pf_divert * 6566223637Sbzpf_find_divert(struct mbuf *m) 6567223637Sbz{ 6568223637Sbz struct m_tag *mtag; 6569223637Sbz 6570223637Sbz if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) 6571223637Sbz return (NULL); 6572223637Sbz 6573223637Sbz return ((struct pf_divert *)(mtag + 1)); 6574223637Sbz} 6575223637Sbz 6576223637Sbzstruct pf_divert * 6577223637Sbzpf_get_divert(struct mbuf *m) 6578223637Sbz{ 6579223637Sbz struct m_tag *mtag; 6580223637Sbz 6581223637Sbz if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) { 6582223637Sbz mtag = m_tag_get(PACKET_TAG_PF_DIVERT, sizeof(struct pf_divert), 6583223637Sbz M_NOWAIT); 6584223637Sbz if (mtag == NULL) 6585223637Sbz return (NULL); 6586223637Sbz bzero(mtag + 1, sizeof(struct pf_divert)); 6587223637Sbz m_tag_prepend(m, mtag); 6588223637Sbz } 6589223637Sbz 6590223637Sbz return ((struct pf_divert *)(mtag + 1)); 6591223637Sbz} 6592223637Sbz#endif 6593223637Sbz 6594126258Smlaier#ifdef INET 6595126258Smlaierint 6596135920Smlaier#ifdef __FreeBSD__ 6597145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0, 6598145836Smlaier struct ether_header *eh, struct inpcb *inp) 6599135920Smlaier#else 6600145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0, 6601145836Smlaier struct ether_header *eh) 6602135920Smlaier#endif 6603126258Smlaier{ 6604130613Smlaier struct pfi_kif *kif; 6605130613Smlaier u_short action, reason = 0, log = 0; 6606130613Smlaier struct mbuf *m = *m0; 6607223637Sbz#ifdef __FreeBSD__ 6608223637Sbz struct ip *h = NULL; 6609223637Sbz struct m_tag *ipfwtag; 6610223637Sbz struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; 6611223637Sbz#else 6612223637Sbz struct ip *h; 6613130613Smlaier struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; 6614223637Sbz#endif 6615130613Smlaier struct pf_state *s = NULL; 6616130613Smlaier struct pf_ruleset *ruleset = NULL; 6617130613Smlaier struct pf_pdesc pd; 6618130613Smlaier int off, dirndx, pqid = 0; 6619126258Smlaier 6620127145Smlaier#ifdef __FreeBSD__ 6621126261Smlaier PF_LOCK(); 6622223637Sbz if (!V_pf_status.running) 6623171168Smlaier { 6624126261Smlaier PF_UNLOCK(); 6625171168Smlaier return (PF_PASS); 6626126261Smlaier } 6627223637Sbz#else 6628223637Sbz if (!pf_status.running) 6629223637Sbz return (PF_PASS); 6630171168Smlaier#endif 6631126258Smlaier 6632171168Smlaier memset(&pd, 0, sizeof(pd)); 6633223637Sbz#ifdef __FreeBSD__ 6634171168Smlaier if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { 6635171168Smlaier PF_UNLOCK(); 6636171168Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6637171168Smlaier ("pf_test: pf_get_mtag returned NULL\n")); 6638171168Smlaier return (PF_DROP); 6639171168Smlaier } 6640171168Smlaier#endif 6641223637Sbz#ifndef __FreeBSD__ 6642145836Smlaier if (ifp->if_type == IFT_CARP && ifp->if_carpdev) 6643223637Sbz kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; 6644223637Sbz else 6645145836Smlaier#endif 6646223637Sbz kif = (struct pfi_kif *)ifp->if_pf_kif; 6647145836Smlaier 6648130613Smlaier if (kif == NULL) { 6649130613Smlaier#ifdef __FreeBSD__ 6650130613Smlaier PF_UNLOCK(); 6651130613Smlaier#endif 6652145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6653145836Smlaier ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname)); 6654130613Smlaier return (PF_DROP); 6655130613Smlaier } 6656223637Sbz if (kif->pfik_flags & PFI_IFLAG_SKIP) 6657145836Smlaier#ifdef __FreeBSD__ 6658223637Sbz { 6659145836Smlaier PF_UNLOCK(); 6660145836Smlaier#endif 6661145836Smlaier return (PF_PASS); 6662223637Sbz#ifdef __FreeBSD__ 6663145836Smlaier } 6664223637Sbz#endif 6665130613Smlaier 6666130613Smlaier#ifdef __FreeBSD__ 6667126261Smlaier M_ASSERTPKTHDR(m); 6668126261Smlaier#else 6669126258Smlaier#ifdef DIAGNOSTIC 6670126258Smlaier if ((m->m_flags & M_PKTHDR) == 0) 6671126258Smlaier panic("non-M_PKTHDR is passed to pf_test"); 6672145836Smlaier#endif /* DIAGNOSTIC */ 6673223637Sbz#endif 6674126258Smlaier 6675126258Smlaier if (m->m_pkthdr.len < (int)sizeof(*h)) { 6676126258Smlaier action = PF_DROP; 6677126258Smlaier REASON_SET(&reason, PFRES_SHORT); 6678126258Smlaier log = 1; 6679126258Smlaier goto done; 6680126258Smlaier } 6681126258Smlaier 6682223637Sbz#ifdef __FreeBSD__ 6683223637Sbz if (m->m_flags & M_SKIP_FIREWALL) { 6684223637Sbz PF_UNLOCK(); 6685223637Sbz return (PF_PASS); 6686223637Sbz } 6687223637Sbz#else 6688223637Sbz if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) 6689223637Sbz return (PF_PASS); 6690223637Sbz#endif 6691223637Sbz 6692223637Sbz#ifdef __FreeBSD__ 6693223637Sbz if (ip_divert_ptr != NULL && 6694223637Sbz ((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) { 6695223637Sbz struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1); 6696223637Sbz if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) { 6697223637Sbz pd.pf_mtag->flags |= PF_PACKET_LOOPED; 6698223637Sbz m_tag_delete(m, ipfwtag); 6699223637Sbz } 6700223637Sbz if (pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) { 6701223637Sbz m->m_flags |= M_FASTFWD_OURS; 6702223637Sbz pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT; 6703223637Sbz } 6704223637Sbz } else 6705223637Sbz#endif 6706126258Smlaier /* We do IP header normalization and packet reassembly here */ 6707145836Smlaier if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) { 6708126258Smlaier action = PF_DROP; 6709126258Smlaier goto done; 6710126258Smlaier } 6711223637Sbz m = *m0; /* pf_normalize messes with m0 */ 6712126258Smlaier h = mtod(m, struct ip *); 6713126258Smlaier 6714126258Smlaier off = h->ip_hl << 2; 6715126258Smlaier if (off < (int)sizeof(*h)) { 6716126258Smlaier action = PF_DROP; 6717126258Smlaier REASON_SET(&reason, PFRES_SHORT); 6718126258Smlaier log = 1; 6719126258Smlaier goto done; 6720126258Smlaier } 6721126258Smlaier 6722126258Smlaier pd.src = (struct pf_addr *)&h->ip_src; 6723126258Smlaier pd.dst = (struct pf_addr *)&h->ip_dst; 6724223637Sbz pd.sport = pd.dport = NULL; 6725126258Smlaier pd.ip_sum = &h->ip_sum; 6726223637Sbz pd.proto_sum = NULL; 6727126258Smlaier pd.proto = h->ip_p; 6728223637Sbz pd.dir = dir; 6729223637Sbz pd.sidx = (dir == PF_IN) ? 0 : 1; 6730223637Sbz pd.didx = (dir == PF_IN) ? 1 : 0; 6731126258Smlaier pd.af = AF_INET; 6732126258Smlaier pd.tos = h->ip_tos; 6733126258Smlaier pd.tot_len = ntohs(h->ip_len); 6734145836Smlaier pd.eh = eh; 6735126258Smlaier 6736126258Smlaier /* handle fragments that didn't get reassembled by normalization */ 6737126258Smlaier if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { 6738130613Smlaier action = pf_test_fragment(&r, dir, kif, m, h, 6739126258Smlaier &pd, &a, &ruleset); 6740126258Smlaier goto done; 6741126258Smlaier } 6742126258Smlaier 6743126258Smlaier switch (h->ip_p) { 6744126258Smlaier 6745126258Smlaier case IPPROTO_TCP: { 6746126258Smlaier struct tcphdr th; 6747126258Smlaier 6748126258Smlaier pd.hdr.tcp = &th; 6749126258Smlaier if (!pf_pull_hdr(m, off, &th, sizeof(th), 6750126258Smlaier &action, &reason, AF_INET)) { 6751126258Smlaier log = action != PF_PASS; 6752126258Smlaier goto done; 6753126258Smlaier } 6754126258Smlaier pd.p_len = pd.tot_len - off - (th.th_off << 2); 6755126258Smlaier if ((th.th_flags & TH_ACK) && pd.p_len == 0) 6756126258Smlaier pqid = 1; 6757130613Smlaier action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); 6758126258Smlaier if (action == PF_DROP) 6759130613Smlaier goto done; 6760130613Smlaier action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, 6761126258Smlaier &reason); 6762126258Smlaier if (action == PF_PASS) { 6763223637Sbz#if NPFSYNC > 0 6764223637Sbz#ifdef __FreeBSD__ 6765223637Sbz if (pfsync_update_state_ptr != NULL) 6766223637Sbz pfsync_update_state_ptr(s); 6767223637Sbz#else 6768130613Smlaier pfsync_update_state(s); 6769223637Sbz#endif 6770145836Smlaier#endif /* NPFSYNC */ 6771126258Smlaier r = s->rule.ptr; 6772130613Smlaier a = s->anchor.ptr; 6773126258Smlaier log = s->log; 6774126258Smlaier } else if (s == NULL) 6775135920Smlaier#ifdef __FreeBSD__ 6776223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6777145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 6778135920Smlaier#else 6779223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6780145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6781135920Smlaier#endif 6782126258Smlaier break; 6783126258Smlaier } 6784126258Smlaier 6785126258Smlaier case IPPROTO_UDP: { 6786126258Smlaier struct udphdr uh; 6787126258Smlaier 6788126258Smlaier pd.hdr.udp = &uh; 6789126258Smlaier if (!pf_pull_hdr(m, off, &uh, sizeof(uh), 6790126258Smlaier &action, &reason, AF_INET)) { 6791126258Smlaier log = action != PF_PASS; 6792126258Smlaier goto done; 6793126258Smlaier } 6794130613Smlaier if (uh.uh_dport == 0 || 6795130613Smlaier ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || 6796130613Smlaier ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { 6797130613Smlaier action = PF_DROP; 6798171168Smlaier REASON_SET(&reason, PFRES_SHORT); 6799130613Smlaier goto done; 6800130613Smlaier } 6801130613Smlaier action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); 6802126258Smlaier if (action == PF_PASS) { 6803223637Sbz#if NPFSYNC > 0 6804223637Sbz#ifdef __FreeBSD__ 6805223637Sbz if (pfsync_update_state_ptr != NULL) 6806223637Sbz pfsync_update_state_ptr(s); 6807223637Sbz#else 6808130613Smlaier pfsync_update_state(s); 6809223637Sbz#endif 6810145836Smlaier#endif /* NPFSYNC */ 6811126258Smlaier r = s->rule.ptr; 6812126258Smlaier a = s->anchor.ptr; 6813126258Smlaier log = s->log; 6814126258Smlaier } else if (s == NULL) 6815135920Smlaier#ifdef __FreeBSD__ 6816223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6817145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 6818135920Smlaier#else 6819223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6820145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6821135920Smlaier#endif 6822126258Smlaier break; 6823126258Smlaier } 6824126258Smlaier 6825126258Smlaier case IPPROTO_ICMP: { 6826126258Smlaier struct icmp ih; 6827126258Smlaier 6828126258Smlaier pd.hdr.icmp = &ih; 6829126258Smlaier if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN, 6830126258Smlaier &action, &reason, AF_INET)) { 6831126258Smlaier log = action != PF_PASS; 6832126258Smlaier goto done; 6833126258Smlaier } 6834145836Smlaier action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, 6835145836Smlaier &reason); 6836126258Smlaier if (action == PF_PASS) { 6837223637Sbz#if NPFSYNC > 0 6838223637Sbz#ifdef __FreeBSD__ 6839223637Sbz if (pfsync_update_state_ptr != NULL) 6840223637Sbz pfsync_update_state_ptr(s); 6841223637Sbz#else 6842130613Smlaier pfsync_update_state(s); 6843223637Sbz#endif 6844145836Smlaier#endif /* NPFSYNC */ 6845126258Smlaier r = s->rule.ptr; 6846126258Smlaier a = s->anchor.ptr; 6847126258Smlaier log = s->log; 6848126258Smlaier } else if (s == NULL) 6849145836Smlaier#ifdef __FreeBSD__ 6850223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6851223637Sbz m, off, h, &pd, &a, &ruleset, NULL, inp); 6852145836Smlaier#else 6853223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6854145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6855145836Smlaier#endif 6856126258Smlaier break; 6857126258Smlaier } 6858126258Smlaier 6859223637Sbz#ifdef INET6 6860223637Sbz case IPPROTO_ICMPV6: { 6861223637Sbz action = PF_DROP; 6862223637Sbz DPFPRINTF(PF_DEBUG_MISC, 6863223637Sbz ("pf: dropping IPv4 packet with ICMPv6 payload\n")); 6864223637Sbz goto done; 6865223637Sbz } 6866223637Sbz#endif 6867223637Sbz 6868126258Smlaier default: 6869223637Sbz action = pf_test_state_other(&s, dir, kif, m, &pd); 6870126258Smlaier if (action == PF_PASS) { 6871223637Sbz#if NPFSYNC > 0 6872223637Sbz#ifdef __FreeBSD__ 6873223637Sbz if (pfsync_update_state_ptr != NULL) 6874223637Sbz pfsync_update_state_ptr(s); 6875223637Sbz#else 6876130613Smlaier pfsync_update_state(s); 6877223637Sbz#endif 6878145836Smlaier#endif /* NPFSYNC */ 6879126258Smlaier r = s->rule.ptr; 6880126258Smlaier a = s->anchor.ptr; 6881126258Smlaier log = s->log; 6882126258Smlaier } else if (s == NULL) 6883145836Smlaier#ifdef __FreeBSD__ 6884223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 6885223637Sbz &pd, &a, &ruleset, NULL, inp); 6886145836Smlaier#else 6887223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 6888145836Smlaier &pd, &a, &ruleset, &ipintrq); 6889145836Smlaier#endif 6890126258Smlaier break; 6891126258Smlaier } 6892126258Smlaier 6893126258Smlaierdone: 6894126258Smlaier if (action == PF_PASS && h->ip_hl > 5 && 6895200930Sdelphij !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { 6896126258Smlaier action = PF_DROP; 6897145836Smlaier REASON_SET(&reason, PFRES_IPOPTIONS); 6898126258Smlaier log = 1; 6899126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 6900126258Smlaier ("pf: dropping packet with ip options\n")); 6901126258Smlaier } 6902126258Smlaier 6903231852Sbz if ((s && s->tag) || r->rtableid >= 0) 6904223637Sbz#ifdef __FreeBSD__ 6905223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); 6906223637Sbz#else 6907223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid); 6908223637Sbz#endif 6909145836Smlaier 6910223637Sbz if (dir == PF_IN && s && s->key[PF_SK_STACK]) 6911223637Sbz#ifdef __FreeBSD__ 6912223637Sbz pd.pf_mtag->statekey = s->key[PF_SK_STACK]; 6913223637Sbz#else 6914223637Sbz m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; 6915223637Sbz#endif 6916223637Sbz 6917126258Smlaier#ifdef ALTQ 6918126258Smlaier if (action == PF_PASS && r->qid) { 6919223637Sbz#ifdef __FreeBSD__ 6920171168Smlaier if (pqid || (pd.tos & IPTOS_LOWDELAY)) 6921171168Smlaier pd.pf_mtag->qid = r->pqid; 6922171168Smlaier else 6923171168Smlaier pd.pf_mtag->qid = r->qid; 6924171168Smlaier /* add hints for ecn */ 6925171168Smlaier pd.pf_mtag->hdr = h; 6926223637Sbz 6927223637Sbz#else 6928223637Sbz if (pqid || (pd.tos & IPTOS_LOWDELAY)) 6929223637Sbz m->m_pkthdr.pf.qid = r->pqid; 6930223637Sbz else 6931223637Sbz m->m_pkthdr.pf.qid = r->qid; 6932223637Sbz /* add hints for ecn */ 6933223637Sbz m->m_pkthdr.pf.hdr = h; 6934223637Sbz#endif 6935126258Smlaier } 6936145836Smlaier#endif /* ALTQ */ 6937126258Smlaier 6938130613Smlaier /* 6939130613Smlaier * connections redirected to loopback should not match sockets 6940130613Smlaier * bound specifically to loopback due to security implications, 6941130613Smlaier * see tcp_input() and in_pcblookup_listen(). 6942130613Smlaier */ 6943130613Smlaier if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 6944130613Smlaier pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 6945130613Smlaier (s->nat_rule.ptr->action == PF_RDR || 6946130613Smlaier s->nat_rule.ptr->action == PF_BINAT) && 6947171168Smlaier (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 6948223637Sbz#ifdef __FreeBSD__ 6949223637Sbz m->m_flags |= M_SKIP_FIREWALL; 6950223637Sbz#else 6951223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; 6952223637Sbz#endif 6953171168Smlaier 6954223637Sbz#ifdef __FreeBSD__ 6955223637Sbz if (action == PF_PASS && r->divert.port && 6956223637Sbz ip_divert_ptr != NULL && !PACKET_LOOPED()) { 6957223637Sbz 6958223637Sbz ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0, 6959223637Sbz sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO); 6960223637Sbz if (ipfwtag != NULL) { 6961225171Sbz ((struct ipfw_rule_ref *)(ipfwtag+1))->info = 6962225171Sbz ntohs(r->divert.port); 6963223637Sbz ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir; 6964223637Sbz 6965223637Sbz m_tag_prepend(m, ipfwtag); 6966223637Sbz 6967223637Sbz PF_UNLOCK(); 6968223637Sbz 6969223637Sbz if (m->m_flags & M_FASTFWD_OURS) { 6970223637Sbz pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT; 6971223637Sbz m->m_flags &= ~M_FASTFWD_OURS; 6972223637Sbz } 6973223637Sbz 6974223637Sbz ip_divert_ptr(*m0, 6975223637Sbz dir == PF_IN ? DIR_IN : DIR_OUT); 6976223637Sbz *m0 = NULL; 6977223637Sbz return (action); 6978223637Sbz } else { 6979223637Sbz /* XXX: ipfw has the same behaviour! */ 6980223637Sbz action = PF_DROP; 6981223637Sbz REASON_SET(&reason, PFRES_MEMORY); 6982223637Sbz log = 1; 6983223637Sbz DPFPRINTF(PF_DEBUG_MISC, 6984223637Sbz ("pf: failed to allocate divert tag\n")); 6985223637Sbz } 6986223637Sbz } 6987223637Sbz#else 6988223637Sbz if (dir == PF_IN && action == PF_PASS && r->divert.port) { 6989223637Sbz struct pf_divert *divert; 6990223637Sbz 6991223637Sbz if ((divert = pf_get_divert(m))) { 6992223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; 6993223637Sbz divert->port = r->divert.port; 6994223637Sbz divert->addr.ipv4 = r->divert.addr.v4; 6995223637Sbz } 6996223637Sbz } 6997223637Sbz#endif 6998223637Sbz 6999171168Smlaier if (log) { 7000171168Smlaier struct pf_rule *lr; 7001171168Smlaier 7002171168Smlaier if (s != NULL && s->nat_rule.ptr != NULL && 7003171168Smlaier s->nat_rule.ptr->log & PF_LOG_ALL) 7004171168Smlaier lr = s->nat_rule.ptr; 7005171168Smlaier else 7006171168Smlaier lr = r; 7007171168Smlaier PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset, 7008171168Smlaier &pd); 7009130613Smlaier } 7010130613Smlaier 7011130613Smlaier kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len; 7012130613Smlaier kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++; 7013130613Smlaier 7014130613Smlaier if (action == PF_PASS || r->action == PF_DROP) { 7015171168Smlaier dirndx = (dir == PF_OUT); 7016171168Smlaier r->packets[dirndx]++; 7017171168Smlaier r->bytes[dirndx] += pd.tot_len; 7018130613Smlaier if (a != NULL) { 7019171168Smlaier a->packets[dirndx]++; 7020171168Smlaier a->bytes[dirndx] += pd.tot_len; 7021130613Smlaier } 7022130613Smlaier if (s != NULL) { 7023130613Smlaier if (s->nat_rule.ptr != NULL) { 7024171168Smlaier s->nat_rule.ptr->packets[dirndx]++; 7025171168Smlaier s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; 7026130613Smlaier } 7027130613Smlaier if (s->src_node != NULL) { 7028171168Smlaier s->src_node->packets[dirndx]++; 7029171168Smlaier s->src_node->bytes[dirndx] += pd.tot_len; 7030130613Smlaier } 7031130613Smlaier if (s->nat_src_node != NULL) { 7032171168Smlaier s->nat_src_node->packets[dirndx]++; 7033171168Smlaier s->nat_src_node->bytes[dirndx] += pd.tot_len; 7034130613Smlaier } 7035171168Smlaier dirndx = (dir == s->direction) ? 0 : 1; 7036171168Smlaier s->packets[dirndx]++; 7037171168Smlaier s->bytes[dirndx] += pd.tot_len; 7038130613Smlaier } 7039130613Smlaier tr = r; 7040130613Smlaier nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; 7041223637Sbz#ifdef __FreeBSD__ 7042223637Sbz if (nr != NULL && r == &V_pf_default_rule) 7043223637Sbz#else 7044223637Sbz if (nr != NULL && r == &pf_default_rule) 7045223637Sbz#endif 7046223637Sbz tr = nr; 7047130613Smlaier if (tr->src.addr.type == PF_ADDR_TABLE) 7048223637Sbz pfr_update_stats(tr->src.addr.p.tbl, 7049223637Sbz (s == NULL) ? pd.src : 7050223637Sbz &s->key[(s->direction == PF_IN)]-> 7051223637Sbz addr[(s->direction == PF_OUT)], 7052223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7053223637Sbz r->action == PF_PASS, tr->src.neg); 7054130613Smlaier if (tr->dst.addr.type == PF_ADDR_TABLE) 7055223637Sbz pfr_update_stats(tr->dst.addr.p.tbl, 7056223637Sbz (s == NULL) ? pd.dst : 7057223637Sbz &s->key[(s->direction == PF_IN)]-> 7058223637Sbz addr[(s->direction == PF_IN)], 7059223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7060223637Sbz r->action == PF_PASS, tr->dst.neg); 7061130613Smlaier } 7062130613Smlaier 7063223637Sbz switch (action) { 7064223637Sbz case PF_SYNPROXY_DROP: 7065126258Smlaier m_freem(*m0); 7066223637Sbz case PF_DEFER: 7067126258Smlaier *m0 = NULL; 7068126258Smlaier action = PF_PASS; 7069223637Sbz break; 7070223637Sbz default: 7071126258Smlaier /* pf_route can free the mbuf causing *m0 to become NULL */ 7072223637Sbz if (r->rt) 7073223637Sbz pf_route(m0, r, dir, kif->pfik_ifp, s, &pd); 7074223637Sbz break; 7075223637Sbz } 7076127145Smlaier#ifdef __FreeBSD__ 7077126261Smlaier PF_UNLOCK(); 7078126261Smlaier#endif 7079126258Smlaier return (action); 7080126258Smlaier} 7081126258Smlaier#endif /* INET */ 7082126258Smlaier 7083126258Smlaier#ifdef INET6 7084126258Smlaierint 7085135920Smlaier#ifdef __FreeBSD__ 7086145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, 7087145836Smlaier struct ether_header *eh, struct inpcb *inp) 7088135920Smlaier#else 7089145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, 7090145836Smlaier struct ether_header *eh) 7091135920Smlaier#endif 7092126258Smlaier{ 7093130613Smlaier struct pfi_kif *kif; 7094130613Smlaier u_short action, reason = 0, log = 0; 7095171168Smlaier struct mbuf *m = *m0, *n = NULL; 7096223637Sbz#ifdef __FreeBSD__ 7097223637Sbz struct ip6_hdr *h = NULL; 7098223637Sbz struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; 7099223637Sbz#else 7100171168Smlaier struct ip6_hdr *h; 7101130613Smlaier struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; 7102223637Sbz#endif 7103130613Smlaier struct pf_state *s = NULL; 7104130613Smlaier struct pf_ruleset *ruleset = NULL; 7105130613Smlaier struct pf_pdesc pd; 7106169843Sdhartmei int off, terminal = 0, dirndx, rh_cnt = 0; 7107126258Smlaier 7108127145Smlaier#ifdef __FreeBSD__ 7109126261Smlaier PF_LOCK(); 7110223637Sbz if (!V_pf_status.running) { 7111126261Smlaier PF_UNLOCK(); 7112126258Smlaier return (PF_PASS); 7113126261Smlaier } 7114223637Sbz#else 7115223637Sbz if (!pf_status.running) 7116223637Sbz return (PF_PASS); 7117171168Smlaier#endif 7118126258Smlaier 7119171168Smlaier memset(&pd, 0, sizeof(pd)); 7120223637Sbz#ifdef __FreeBSD__ 7121171168Smlaier if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { 7122171168Smlaier PF_UNLOCK(); 7123171168Smlaier DPFPRINTF(PF_DEBUG_URGENT, 7124223637Sbz ("pf_test: pf_get_mtag returned NULL\n")); 7125171168Smlaier return (PF_DROP); 7126171168Smlaier } 7127223637Sbz#endif 7128223637Sbz#ifndef __FreeBSD__ 7129145836Smlaier if (ifp->if_type == IFT_CARP && ifp->if_carpdev) 7130223637Sbz kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; 7131223637Sbz else 7132145836Smlaier#endif 7133223637Sbz kif = (struct pfi_kif *)ifp->if_pf_kif; 7134145836Smlaier 7135130613Smlaier if (kif == NULL) { 7136130613Smlaier#ifdef __FreeBSD__ 7137130613Smlaier PF_UNLOCK(); 7138130613Smlaier#endif 7139145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 7140145836Smlaier ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname)); 7141130613Smlaier return (PF_DROP); 7142130613Smlaier } 7143223637Sbz if (kif->pfik_flags & PFI_IFLAG_SKIP) 7144145836Smlaier#ifdef __FreeBSD__ 7145223637Sbz { 7146145836Smlaier PF_UNLOCK(); 7147145836Smlaier#endif 7148145836Smlaier return (PF_PASS); 7149223637Sbz#ifdef __FreeBSD__ 7150145836Smlaier } 7151223637Sbz#endif 7152130613Smlaier 7153130613Smlaier#ifdef __FreeBSD__ 7154126261Smlaier M_ASSERTPKTHDR(m); 7155126261Smlaier#else 7156126258Smlaier#ifdef DIAGNOSTIC 7157126258Smlaier if ((m->m_flags & M_PKTHDR) == 0) 7158145836Smlaier panic("non-M_PKTHDR is passed to pf_test6"); 7159145836Smlaier#endif /* DIAGNOSTIC */ 7160126258Smlaier#endif 7161126258Smlaier 7162126258Smlaier if (m->m_pkthdr.len < (int)sizeof(*h)) { 7163126258Smlaier action = PF_DROP; 7164126258Smlaier REASON_SET(&reason, PFRES_SHORT); 7165126258Smlaier log = 1; 7166126258Smlaier goto done; 7167126258Smlaier } 7168126258Smlaier 7169223637Sbz#ifdef __FreeBSD__ 7170226938Skevlo if (pd.pf_mtag->flags & PF_TAG_GENERATED) { 7171226938Skevlo PF_UNLOCK(); 7172223637Sbz#else 7173223637Sbz if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) 7174223637Sbz#endif 7175223637Sbz return (PF_PASS); 7176226938Skevlo#ifdef __FreeBSD__ 7177226938Skevlo } 7178226938Skevlo#endif 7179223637Sbz 7180126258Smlaier /* We do IP header normalization and packet reassembly here */ 7181145836Smlaier if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) { 7182126258Smlaier action = PF_DROP; 7183126258Smlaier goto done; 7184126258Smlaier } 7185223637Sbz m = *m0; /* pf_normalize messes with m0 */ 7186126258Smlaier h = mtod(m, struct ip6_hdr *); 7187126258Smlaier 7188169843Sdhartmei#if 1 7189169843Sdhartmei /* 7190169843Sdhartmei * we do not support jumbogram yet. if we keep going, zero ip6_plen 7191169843Sdhartmei * will do something bad, so drop the packet for now. 7192169843Sdhartmei */ 7193169843Sdhartmei if (htons(h->ip6_plen) == 0) { 7194169843Sdhartmei action = PF_DROP; 7195169843Sdhartmei REASON_SET(&reason, PFRES_NORM); /*XXX*/ 7196169843Sdhartmei goto done; 7197169843Sdhartmei } 7198169843Sdhartmei#endif 7199169843Sdhartmei 7200126258Smlaier pd.src = (struct pf_addr *)&h->ip6_src; 7201126258Smlaier pd.dst = (struct pf_addr *)&h->ip6_dst; 7202223637Sbz pd.sport = pd.dport = NULL; 7203126258Smlaier pd.ip_sum = NULL; 7204223637Sbz pd.proto_sum = NULL; 7205223637Sbz pd.dir = dir; 7206223637Sbz pd.sidx = (dir == PF_IN) ? 0 : 1; 7207223637Sbz pd.didx = (dir == PF_IN) ? 1 : 0; 7208126258Smlaier pd.af = AF_INET6; 7209126258Smlaier pd.tos = 0; 7210126258Smlaier pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); 7211145836Smlaier pd.eh = eh; 7212126258Smlaier 7213126258Smlaier off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); 7214126258Smlaier pd.proto = h->ip6_nxt; 7215126258Smlaier do { 7216126258Smlaier switch (pd.proto) { 7217126258Smlaier case IPPROTO_FRAGMENT: 7218130613Smlaier action = pf_test_fragment(&r, dir, kif, m, h, 7219126258Smlaier &pd, &a, &ruleset); 7220126258Smlaier if (action == PF_DROP) 7221126258Smlaier REASON_SET(&reason, PFRES_FRAG); 7222126258Smlaier goto done; 7223169843Sdhartmei case IPPROTO_ROUTING: { 7224169843Sdhartmei struct ip6_rthdr rthdr; 7225169843Sdhartmei 7226169843Sdhartmei if (rh_cnt++) { 7227169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7228169843Sdhartmei ("pf: IPv6 more than one rthdr\n")); 7229169843Sdhartmei action = PF_DROP; 7230169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7231169843Sdhartmei log = 1; 7232169843Sdhartmei goto done; 7233169843Sdhartmei } 7234169843Sdhartmei if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, 7235169843Sdhartmei &reason, pd.af)) { 7236169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7237169843Sdhartmei ("pf: IPv6 short rthdr\n")); 7238169843Sdhartmei action = PF_DROP; 7239169843Sdhartmei REASON_SET(&reason, PFRES_SHORT); 7240169843Sdhartmei log = 1; 7241169843Sdhartmei goto done; 7242169843Sdhartmei } 7243169843Sdhartmei if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { 7244169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7245169843Sdhartmei ("pf: IPv6 rthdr0\n")); 7246169843Sdhartmei action = PF_DROP; 7247169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7248169843Sdhartmei log = 1; 7249169843Sdhartmei goto done; 7250169843Sdhartmei } 7251223637Sbz /* FALLTHROUGH */ 7252169843Sdhartmei } 7253126258Smlaier case IPPROTO_AH: 7254126258Smlaier case IPPROTO_HOPOPTS: 7255126258Smlaier case IPPROTO_DSTOPTS: { 7256126258Smlaier /* get next header and header length */ 7257126258Smlaier struct ip6_ext opt6; 7258126258Smlaier 7259126258Smlaier if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6), 7260145836Smlaier NULL, &reason, pd.af)) { 7261126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 7262126258Smlaier ("pf: IPv6 short opt\n")); 7263126258Smlaier action = PF_DROP; 7264126258Smlaier log = 1; 7265126258Smlaier goto done; 7266126258Smlaier } 7267126258Smlaier if (pd.proto == IPPROTO_AH) 7268126258Smlaier off += (opt6.ip6e_len + 2) * 4; 7269126258Smlaier else 7270126258Smlaier off += (opt6.ip6e_len + 1) * 8; 7271126258Smlaier pd.proto = opt6.ip6e_nxt; 7272126258Smlaier /* goto the next header */ 7273126258Smlaier break; 7274126258Smlaier } 7275126258Smlaier default: 7276126258Smlaier terminal++; 7277126258Smlaier break; 7278126258Smlaier } 7279126258Smlaier } while (!terminal); 7280126258Smlaier 7281171168Smlaier /* if there's no routing header, use unmodified mbuf for checksumming */ 7282171168Smlaier if (!n) 7283171168Smlaier n = m; 7284171168Smlaier 7285126258Smlaier switch (pd.proto) { 7286126258Smlaier 7287126258Smlaier case IPPROTO_TCP: { 7288126258Smlaier struct tcphdr th; 7289126258Smlaier 7290126258Smlaier pd.hdr.tcp = &th; 7291126258Smlaier if (!pf_pull_hdr(m, off, &th, sizeof(th), 7292126258Smlaier &action, &reason, AF_INET6)) { 7293126258Smlaier log = action != PF_PASS; 7294126258Smlaier goto done; 7295126258Smlaier } 7296126258Smlaier pd.p_len = pd.tot_len - off - (th.th_off << 2); 7297130613Smlaier action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); 7298126258Smlaier if (action == PF_DROP) 7299130613Smlaier goto done; 7300130613Smlaier action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, 7301126258Smlaier &reason); 7302126258Smlaier if (action == PF_PASS) { 7303223637Sbz#if NPFSYNC > 0 7304223637Sbz#ifdef __FreeBSD__ 7305223637Sbz if (pfsync_update_state_ptr != NULL) 7306223637Sbz pfsync_update_state_ptr(s); 7307223637Sbz#else 7308130613Smlaier pfsync_update_state(s); 7309223637Sbz#endif 7310145836Smlaier#endif /* NPFSYNC */ 7311126258Smlaier r = s->rule.ptr; 7312130613Smlaier a = s->anchor.ptr; 7313126258Smlaier log = s->log; 7314126258Smlaier } else if (s == NULL) 7315135920Smlaier#ifdef __FreeBSD__ 7316223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7317145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 7318135920Smlaier#else 7319223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7320145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7321135920Smlaier#endif 7322126258Smlaier break; 7323126258Smlaier } 7324126258Smlaier 7325126258Smlaier case IPPROTO_UDP: { 7326126258Smlaier struct udphdr uh; 7327126258Smlaier 7328126258Smlaier pd.hdr.udp = &uh; 7329126258Smlaier if (!pf_pull_hdr(m, off, &uh, sizeof(uh), 7330126258Smlaier &action, &reason, AF_INET6)) { 7331126258Smlaier log = action != PF_PASS; 7332126258Smlaier goto done; 7333126258Smlaier } 7334130613Smlaier if (uh.uh_dport == 0 || 7335130613Smlaier ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || 7336130613Smlaier ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { 7337130613Smlaier action = PF_DROP; 7338171168Smlaier REASON_SET(&reason, PFRES_SHORT); 7339130613Smlaier goto done; 7340130613Smlaier } 7341130613Smlaier action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); 7342126258Smlaier if (action == PF_PASS) { 7343223637Sbz#if NPFSYNC > 0 7344223637Sbz#ifdef __FreeBSD__ 7345223637Sbz if (pfsync_update_state_ptr != NULL) 7346223637Sbz pfsync_update_state_ptr(s); 7347223637Sbz#else 7348130613Smlaier pfsync_update_state(s); 7349223637Sbz#endif 7350145836Smlaier#endif /* NPFSYNC */ 7351126258Smlaier r = s->rule.ptr; 7352130613Smlaier a = s->anchor.ptr; 7353126258Smlaier log = s->log; 7354126258Smlaier } else if (s == NULL) 7355135920Smlaier#ifdef __FreeBSD__ 7356223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7357145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 7358135920Smlaier#else 7359223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7360145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7361135920Smlaier#endif 7362126258Smlaier break; 7363126258Smlaier } 7364126258Smlaier 7365223637Sbz case IPPROTO_ICMP: { 7366223637Sbz action = PF_DROP; 7367223637Sbz DPFPRINTF(PF_DEBUG_MISC, 7368223637Sbz ("pf: dropping IPv6 packet with ICMPv4 payload\n")); 7369223637Sbz goto done; 7370223637Sbz } 7371223637Sbz 7372126258Smlaier case IPPROTO_ICMPV6: { 7373126258Smlaier struct icmp6_hdr ih; 7374126258Smlaier 7375126258Smlaier pd.hdr.icmp6 = &ih; 7376126258Smlaier if (!pf_pull_hdr(m, off, &ih, sizeof(ih), 7377126258Smlaier &action, &reason, AF_INET6)) { 7378126258Smlaier log = action != PF_PASS; 7379126258Smlaier goto done; 7380126258Smlaier } 7381130613Smlaier action = pf_test_state_icmp(&s, dir, kif, 7382145836Smlaier m, off, h, &pd, &reason); 7383126258Smlaier if (action == PF_PASS) { 7384223637Sbz#if NPFSYNC > 0 7385223637Sbz#ifdef __FreeBSD__ 7386223637Sbz if (pfsync_update_state_ptr != NULL) 7387223637Sbz pfsync_update_state_ptr(s); 7388223637Sbz#else 7389130613Smlaier pfsync_update_state(s); 7390223637Sbz#endif 7391145836Smlaier#endif /* NPFSYNC */ 7392126258Smlaier r = s->rule.ptr; 7393130613Smlaier a = s->anchor.ptr; 7394126258Smlaier log = s->log; 7395126258Smlaier } else if (s == NULL) 7396145836Smlaier#ifdef __FreeBSD__ 7397223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7398223637Sbz m, off, h, &pd, &a, &ruleset, NULL, inp); 7399145836Smlaier#else 7400223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7401145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7402145836Smlaier#endif 7403126258Smlaier break; 7404126258Smlaier } 7405126258Smlaier 7406126258Smlaier default: 7407223637Sbz action = pf_test_state_other(&s, dir, kif, m, &pd); 7408130613Smlaier if (action == PF_PASS) { 7409223637Sbz#if NPFSYNC > 0 7410223637Sbz#ifdef __FreeBSD__ 7411223637Sbz if (pfsync_update_state_ptr != NULL) 7412223637Sbz pfsync_update_state_ptr(s); 7413223637Sbz#else 7414145836Smlaier pfsync_update_state(s); 7415223637Sbz#endif 7416145836Smlaier#endif /* NPFSYNC */ 7417130613Smlaier r = s->rule.ptr; 7418130613Smlaier a = s->anchor.ptr; 7419130613Smlaier log = s->log; 7420130613Smlaier } else if (s == NULL) 7421145836Smlaier#ifdef __FreeBSD__ 7422223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 7423223637Sbz &pd, &a, &ruleset, NULL, inp); 7424145836Smlaier#else 7425223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 7426145836Smlaier &pd, &a, &ruleset, &ip6intrq); 7427145836Smlaier#endif 7428126258Smlaier break; 7429126258Smlaier } 7430126258Smlaier 7431126258Smlaierdone: 7432223637Sbz if (n != m) { 7433223637Sbz m_freem(n); 7434223637Sbz n = NULL; 7435223637Sbz } 7436223637Sbz 7437169843Sdhartmei /* handle dangerous IPv6 extension headers. */ 7438169843Sdhartmei if (action == PF_PASS && rh_cnt && 7439200930Sdelphij !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { 7440169843Sdhartmei action = PF_DROP; 7441169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7442169843Sdhartmei log = 1; 7443169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7444169843Sdhartmei ("pf: dropping packet with dangerous v6 headers\n")); 7445169843Sdhartmei } 7446126258Smlaier 7447231852Sbz if ((s && s->tag) || r->rtableid >= 0) 7448223637Sbz#ifdef __FreeBSD__ 7449223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); 7450223637Sbz#else 7451223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid); 7452223637Sbz#endif 7453145836Smlaier 7454223637Sbz if (dir == PF_IN && s && s->key[PF_SK_STACK]) 7455223637Sbz#ifdef __FreeBSD__ 7456223637Sbz pd.pf_mtag->statekey = s->key[PF_SK_STACK]; 7457223637Sbz#else 7458223637Sbz m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; 7459223637Sbz#endif 7460223637Sbz 7461126258Smlaier#ifdef ALTQ 7462126258Smlaier if (action == PF_PASS && r->qid) { 7463223637Sbz#ifdef __FreeBSD__ 7464171168Smlaier if (pd.tos & IPTOS_LOWDELAY) 7465171168Smlaier pd.pf_mtag->qid = r->pqid; 7466171168Smlaier else 7467171168Smlaier pd.pf_mtag->qid = r->qid; 7468171168Smlaier /* add hints for ecn */ 7469171168Smlaier pd.pf_mtag->hdr = h; 7470223637Sbz#else 7471223637Sbz if (pd.tos & IPTOS_LOWDELAY) 7472223637Sbz m->m_pkthdr.pf.qid = r->pqid; 7473223637Sbz else 7474223637Sbz m->m_pkthdr.pf.qid = r->qid; 7475223637Sbz /* add hints for ecn */ 7476223637Sbz m->m_pkthdr.pf.hdr = h; 7477223637Sbz#endif 7478126258Smlaier } 7479145836Smlaier#endif /* ALTQ */ 7480126258Smlaier 7481130613Smlaier if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 7482130613Smlaier pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 7483130613Smlaier (s->nat_rule.ptr->action == PF_RDR || 7484130613Smlaier s->nat_rule.ptr->action == PF_BINAT) && 7485171168Smlaier IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) 7486223637Sbz#ifdef __FreeBSD__ 7487223637Sbz m->m_flags |= M_SKIP_FIREWALL; 7488223637Sbz#else 7489223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; 7490223637Sbz#endif 7491171168Smlaier 7492223637Sbz#ifdef __FreeBSD__ 7493223637Sbz /* XXX: Anybody working on it?! */ 7494223637Sbz if (r->divert.port) 7495223637Sbz printf("pf: divert(9) is not supported for IPv6\n"); 7496223637Sbz#else 7497223637Sbz if (dir == PF_IN && action == PF_PASS && r->divert.port) { 7498223637Sbz struct pf_divert *divert; 7499223637Sbz 7500223637Sbz if ((divert = pf_get_divert(m))) { 7501223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; 7502223637Sbz divert->port = r->divert.port; 7503223637Sbz divert->addr.ipv6 = r->divert.addr.v6; 7504223637Sbz } 7505223637Sbz } 7506223637Sbz#endif 7507223637Sbz 7508171168Smlaier if (log) { 7509171168Smlaier struct pf_rule *lr; 7510171168Smlaier 7511171168Smlaier if (s != NULL && s->nat_rule.ptr != NULL && 7512171168Smlaier s->nat_rule.ptr->log & PF_LOG_ALL) 7513171168Smlaier lr = s->nat_rule.ptr; 7514171168Smlaier else 7515171168Smlaier lr = r; 7516171168Smlaier PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset, 7517171168Smlaier &pd); 7518130613Smlaier } 7519130613Smlaier 7520130613Smlaier kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len; 7521130613Smlaier kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++; 7522130613Smlaier 7523130613Smlaier if (action == PF_PASS || r->action == PF_DROP) { 7524171168Smlaier dirndx = (dir == PF_OUT); 7525171168Smlaier r->packets[dirndx]++; 7526171168Smlaier r->bytes[dirndx] += pd.tot_len; 7527130613Smlaier if (a != NULL) { 7528171168Smlaier a->packets[dirndx]++; 7529171168Smlaier a->bytes[dirndx] += pd.tot_len; 7530130613Smlaier } 7531130613Smlaier if (s != NULL) { 7532130613Smlaier if (s->nat_rule.ptr != NULL) { 7533171168Smlaier s->nat_rule.ptr->packets[dirndx]++; 7534171168Smlaier s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; 7535130613Smlaier } 7536130613Smlaier if (s->src_node != NULL) { 7537171168Smlaier s->src_node->packets[dirndx]++; 7538171168Smlaier s->src_node->bytes[dirndx] += pd.tot_len; 7539130613Smlaier } 7540130613Smlaier if (s->nat_src_node != NULL) { 7541171168Smlaier s->nat_src_node->packets[dirndx]++; 7542171168Smlaier s->nat_src_node->bytes[dirndx] += pd.tot_len; 7543130613Smlaier } 7544171168Smlaier dirndx = (dir == s->direction) ? 0 : 1; 7545171168Smlaier s->packets[dirndx]++; 7546171168Smlaier s->bytes[dirndx] += pd.tot_len; 7547130613Smlaier } 7548130613Smlaier tr = r; 7549130613Smlaier nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; 7550223637Sbz#ifdef __FreeBSD__ 7551223637Sbz if (nr != NULL && r == &V_pf_default_rule) 7552223637Sbz#else 7553223637Sbz if (nr != NULL && r == &pf_default_rule) 7554223637Sbz#endif 7555223637Sbz tr = nr; 7556130613Smlaier if (tr->src.addr.type == PF_ADDR_TABLE) 7557223637Sbz pfr_update_stats(tr->src.addr.p.tbl, 7558223637Sbz (s == NULL) ? pd.src : 7559223637Sbz &s->key[(s->direction == PF_IN)]->addr[0], 7560223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7561223637Sbz r->action == PF_PASS, tr->src.neg); 7562130613Smlaier if (tr->dst.addr.type == PF_ADDR_TABLE) 7563223637Sbz pfr_update_stats(tr->dst.addr.p.tbl, 7564223637Sbz (s == NULL) ? pd.dst : 7565223637Sbz &s->key[(s->direction == PF_IN)]->addr[1], 7566223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7567223637Sbz r->action == PF_PASS, tr->dst.neg); 7568130613Smlaier } 7569130613Smlaier 7570223637Sbz switch (action) { 7571223637Sbz case PF_SYNPROXY_DROP: 7572126258Smlaier m_freem(*m0); 7573223637Sbz case PF_DEFER: 7574126258Smlaier *m0 = NULL; 7575126258Smlaier action = PF_PASS; 7576223637Sbz break; 7577223637Sbz default: 7578126258Smlaier /* pf_route6 can free the mbuf causing *m0 to become NULL */ 7579223637Sbz if (r->rt) 7580223637Sbz pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd); 7581223637Sbz break; 7582223637Sbz } 7583126258Smlaier 7584127145Smlaier#ifdef __FreeBSD__ 7585126261Smlaier PF_UNLOCK(); 7586126261Smlaier#endif 7587126258Smlaier return (action); 7588126258Smlaier} 7589126258Smlaier#endif /* INET6 */ 7590145836Smlaier 7591145836Smlaierint 7592145836Smlaierpf_check_congestion(struct ifqueue *ifq) 7593145836Smlaier{ 7594145836Smlaier#ifdef __FreeBSD__ 7595145836Smlaier /* XXX_IMPORT: later */ 7596145836Smlaier return (0); 7597145836Smlaier#else 7598145836Smlaier if (ifq->ifq_congestion) 7599145836Smlaier return (1); 7600145836Smlaier else 7601145836Smlaier return (0); 7602145836Smlaier#endif 7603145836Smlaier} 7604223637Sbz 7605223637Sbz/* 7606223637Sbz * must be called whenever any addressing information such as 7607223637Sbz * address, port, protocol has changed 7608223637Sbz */ 7609223637Sbzvoid 7610223637Sbzpf_pkt_addr_changed(struct mbuf *m) 7611223637Sbz{ 7612223637Sbz#ifdef __FreeBSD__ 7613223637Sbz struct pf_mtag *pf_tag; 7614223637Sbz 7615223637Sbz if ((pf_tag = pf_find_mtag(m)) != NULL) 7616223637Sbz pf_tag->statekey = NULL; 7617223637Sbz#else 7618223637Sbz m->m_pkthdr.pf.statekey = NULL; 7619223637Sbz#endif 7620223637Sbz} 7621