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$"); 44126261Smlaier#endif 45126261Smlaier 46127145Smlaier#ifdef __FreeBSD__ 47126261Smlaier#include "opt_bpf.h" 48126261Smlaier#include "opt_pf.h" 49153110Sru 50230868Sglebius#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> 125243401Sglebius#include <netpfil/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 242293896Sglebiusvoid pf_change_ap(struct mbuf *, 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, 323232292Sbz 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, 646237053Sglebius &sk->addr[1], sk->af)) || 647145836Smlaier ((*state)->direction == PF_IN && 648145836Smlaier PF_AEQ(&(*state)->src_node->addr, 649237053Sglebius &sk->addr[0], 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__ 1329226796Sbz sx_slock(&V_pf_consistency_lock); 1330171168Smlaier PF_LOCK(); 1331226796Sbz locked = 0; 1332126258Smlaier 1333226796Sbz if (V_pf_end_threads) { 1334226796Sbz PF_UNLOCK(); 1335226796Sbz sx_sunlock(&V_pf_consistency_lock); 1336226796Sbz sx_xlock(&V_pf_consistency_lock); 1337226796Sbz PF_LOCK(); 1338171168Smlaier 1339226796Sbz pf_purge_expired_states(V_pf_status.states, 1); 1340226796Sbz pf_purge_expired_fragments(); 1341226796Sbz pf_purge_expired_src_nodes(1); 1342226796Sbz V_pf_end_threads++; 1343226796Sbz 1344226796Sbz sx_xunlock(&V_pf_consistency_lock); 1345226796Sbz PF_UNLOCK(); 1346226796Sbz wakeup(pf_purge_thread); 1347226796Sbz kproc_exit(0); 1348226796Sbz } 1349126261Smlaier#endif 1350171168Smlaier s = splsoftnet(); 1351126258Smlaier 1352171168Smlaier /* process a fraction of the state table every second */ 1353196372Smlaier#ifdef __FreeBSD__ 1354226796Sbz if (!pf_purge_expired_states(1 + (V_pf_status.states / 1355226796Sbz V_pf_default_rule.timeout[PFTM_INTERVAL]), 0)) { 1356226796Sbz PF_UNLOCK(); 1357226796Sbz sx_sunlock(&V_pf_consistency_lock); 1358226796Sbz sx_xlock(&V_pf_consistency_lock); 1359226796Sbz PF_LOCK(); 1360226796Sbz locked = 1; 1361196372Smlaier 1362226796Sbz pf_purge_expired_states(1 + (V_pf_status.states / 1363226796Sbz V_pf_default_rule.timeout[PFTM_INTERVAL]), 1); 1364226796Sbz } 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__ 1613226796Sbz if (pfsync_state_in_use_ptr != NULL && 1614226796Sbz 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 2010293896Sglebius/** 2011293896Sglebius * Checksum updates are a little complicated because the checksum in the TCP/UDP 2012293896Sglebius * header isn't always a full checksum. In some cases (i.e. output) it's a 2013293896Sglebius * pseudo-header checksum, which is a partial checksum over src/dst IP 2014293896Sglebius * addresses, protocol number and length. 2015293896Sglebius * 2016293896Sglebius * That means we have the following cases: 2017293896Sglebius * * Input or forwarding: we don't have TSO, the checksum fields are full 2018293896Sglebius * checksums, we need to update the checksum whenever we change anything. 2019293896Sglebius * * Output (i.e. the checksum is a pseudo-header checksum): 2020293896Sglebius * x The field being updated is src/dst address or affects the length of 2021293896Sglebius * the packet. We need to update the pseudo-header checksum (note that this 2022293896Sglebius * checksum is not ones' complement). 2023293896Sglebius * x Some other field is being modified (e.g. src/dst port numbers): We 2024293896Sglebius * don't have to update anything. 2025293896Sglebius **/ 2026126258Smlaieru_int16_t 2027126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp) 2028126258Smlaier{ 2029126258Smlaier u_int32_t l; 2030126258Smlaier 2031126258Smlaier if (udp && !cksum) 2032126258Smlaier return (0x0000); 2033126258Smlaier l = cksum + old - new; 2034126258Smlaier l = (l >> 16) + (l & 65535); 2035126258Smlaier l = l & 65535; 2036126258Smlaier if (udp && !l) 2037126258Smlaier return (0xFFFF); 2038126258Smlaier return (l); 2039126258Smlaier} 2040126258Smlaier 2041293896Sglebiusu_int16_t 2042293896Sglebiuspf_proto_cksum_fixup(struct mbuf *m, u_int16_t cksum, u_int16_t old, 2043293896Sglebius u_int16_t new, u_int8_t udp) 2044293896Sglebius{ 2045293896Sglebius if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) 2046293896Sglebius return (cksum); 2047293896Sglebius 2048293896Sglebius return (pf_cksum_fixup(cksum, old, new, udp)); 2049293896Sglebius} 2050293896Sglebius 2051126258Smlaiervoid 2052293896Sglebiuspf_change_ap(struct mbuf *m, struct pf_addr *a, u_int16_t *p, u_int16_t *ic, 2053293896Sglebius u_int16_t *pc, struct pf_addr *an, u_int16_t pn, u_int8_t u, 2054293896Sglebius sa_family_t af) 2055126258Smlaier{ 2056126258Smlaier struct pf_addr ao; 2057126258Smlaier u_int16_t po = *p; 2058126258Smlaier 2059126258Smlaier PF_ACPY(&ao, a, af); 2060126258Smlaier PF_ACPY(a, an, af); 2061126258Smlaier 2062293896Sglebius if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) 2063293896Sglebius *pc = ~*pc; 2064293896Sglebius 2065126258Smlaier *p = pn; 2066126258Smlaier 2067126258Smlaier switch (af) { 2068126258Smlaier#ifdef INET 2069126258Smlaier case AF_INET: 2070126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, 2071126258Smlaier ao.addr16[0], an->addr16[0], 0), 2072126258Smlaier ao.addr16[1], an->addr16[1], 0); 2073126258Smlaier *p = pn; 2074293896Sglebius 2075293896Sglebius *pc = pf_cksum_fixup(pf_cksum_fixup(*pc, 2076126258Smlaier ao.addr16[0], an->addr16[0], u), 2077293896Sglebius ao.addr16[1], an->addr16[1], u); 2078293896Sglebius 2079293896Sglebius *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u); 2080126258Smlaier break; 2081126258Smlaier#endif /* INET */ 2082126258Smlaier#ifdef INET6 2083126258Smlaier case AF_INET6: 2084126258Smlaier *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2085126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2086293896Sglebius pf_cksum_fixup(pf_cksum_fixup(*pc, 2087126258Smlaier ao.addr16[0], an->addr16[0], u), 2088126258Smlaier ao.addr16[1], an->addr16[1], u), 2089126258Smlaier ao.addr16[2], an->addr16[2], u), 2090126258Smlaier ao.addr16[3], an->addr16[3], u), 2091126258Smlaier ao.addr16[4], an->addr16[4], u), 2092126258Smlaier ao.addr16[5], an->addr16[5], u), 2093126258Smlaier ao.addr16[6], an->addr16[6], u), 2094293896Sglebius ao.addr16[7], an->addr16[7], u); 2095293896Sglebius 2096293896Sglebius *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u); 2097126258Smlaier break; 2098126258Smlaier#endif /* INET6 */ 2099126258Smlaier } 2100293896Sglebius 2101293896Sglebius if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | 2102293896Sglebius CSUM_DELAY_DATA_IPV6)) { 2103293896Sglebius *pc = ~*pc; 2104293896Sglebius if (! *pc) 2105293896Sglebius *pc = 0xffff; 2106293896Sglebius } 2107126258Smlaier} 2108126258Smlaier 2109126258Smlaier/* Changes a u_int32_t. Uses a void * so there are no align restrictions */ 2110126258Smlaiervoid 2111126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u) 2112126258Smlaier{ 2113126258Smlaier u_int32_t ao; 2114126258Smlaier 2115126258Smlaier memcpy(&ao, a, sizeof(ao)); 2116126258Smlaier memcpy(a, &an, sizeof(u_int32_t)); 2117126258Smlaier *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u), 2118126258Smlaier ao % 65536, an % 65536, u); 2119126258Smlaier} 2120126258Smlaier 2121293896Sglebiusvoid 2122293896Sglebiuspf_change_proto_a(struct mbuf *m, void *a, u_int16_t *c, u_int32_t an, u_int8_t udp) 2123293896Sglebius{ 2124293896Sglebius u_int32_t ao; 2125293896Sglebius 2126293896Sglebius memcpy(&ao, a, sizeof(ao)); 2127293896Sglebius memcpy(a, &an, sizeof(u_int32_t)); 2128293896Sglebius 2129293896Sglebius *c = pf_proto_cksum_fixup(m, 2130293896Sglebius pf_proto_cksum_fixup(m, *c, ao / 65536, an / 65536, udp), 2131293896Sglebius ao % 65536, an % 65536, udp); 2132293896Sglebius} 2133293896Sglebius 2134126258Smlaier#ifdef INET6 2135126258Smlaiervoid 2136126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) 2137126258Smlaier{ 2138126258Smlaier struct pf_addr ao; 2139126258Smlaier 2140126258Smlaier PF_ACPY(&ao, a, AF_INET6); 2141126258Smlaier PF_ACPY(a, an, AF_INET6); 2142126258Smlaier 2143126258Smlaier *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2144126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2145126258Smlaier pf_cksum_fixup(pf_cksum_fixup(*c, 2146126258Smlaier ao.addr16[0], an->addr16[0], u), 2147126258Smlaier ao.addr16[1], an->addr16[1], u), 2148126258Smlaier ao.addr16[2], an->addr16[2], u), 2149126258Smlaier ao.addr16[3], an->addr16[3], u), 2150126258Smlaier ao.addr16[4], an->addr16[4], u), 2151126258Smlaier ao.addr16[5], an->addr16[5], u), 2152126258Smlaier ao.addr16[6], an->addr16[6], u), 2153126258Smlaier ao.addr16[7], an->addr16[7], u); 2154126258Smlaier} 2155126258Smlaier#endif /* INET6 */ 2156126258Smlaier 2157126258Smlaiervoid 2158126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, 2159126258Smlaier struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c, 2160126258Smlaier u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af) 2161126258Smlaier{ 2162126258Smlaier struct pf_addr oia, ooa; 2163126258Smlaier 2164126258Smlaier PF_ACPY(&oia, ia, af); 2165223637Sbz if (oa) 2166223637Sbz PF_ACPY(&ooa, oa, af); 2167126258Smlaier 2168126258Smlaier /* Change inner protocol port, fix inner protocol checksum. */ 2169126258Smlaier if (ip != NULL) { 2170126258Smlaier u_int16_t oip = *ip; 2171223637Sbz u_int32_t opc; 2172126258Smlaier 2173126258Smlaier if (pc != NULL) 2174126258Smlaier opc = *pc; 2175126258Smlaier *ip = np; 2176126258Smlaier if (pc != NULL) 2177126258Smlaier *pc = pf_cksum_fixup(*pc, oip, *ip, u); 2178126258Smlaier *ic = pf_cksum_fixup(*ic, oip, *ip, 0); 2179126258Smlaier if (pc != NULL) 2180126258Smlaier *ic = pf_cksum_fixup(*ic, opc, *pc, 0); 2181126258Smlaier } 2182126258Smlaier /* Change inner ip address, fix inner ip and icmp checksums. */ 2183126258Smlaier PF_ACPY(ia, na, af); 2184126258Smlaier switch (af) { 2185126258Smlaier#ifdef INET 2186126258Smlaier case AF_INET: { 2187126258Smlaier u_int32_t oh2c = *h2c; 2188126258Smlaier 2189126258Smlaier *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c, 2190126258Smlaier oia.addr16[0], ia->addr16[0], 0), 2191126258Smlaier oia.addr16[1], ia->addr16[1], 0); 2192126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, 2193126258Smlaier oia.addr16[0], ia->addr16[0], 0), 2194126258Smlaier oia.addr16[1], ia->addr16[1], 0); 2195126258Smlaier *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0); 2196126258Smlaier break; 2197126258Smlaier } 2198126258Smlaier#endif /* INET */ 2199126258Smlaier#ifdef INET6 2200126258Smlaier case AF_INET6: 2201126258Smlaier *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2202126258Smlaier pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2203126258Smlaier pf_cksum_fixup(pf_cksum_fixup(*ic, 2204126258Smlaier oia.addr16[0], ia->addr16[0], u), 2205126258Smlaier oia.addr16[1], ia->addr16[1], u), 2206126258Smlaier oia.addr16[2], ia->addr16[2], u), 2207126258Smlaier oia.addr16[3], ia->addr16[3], u), 2208126258Smlaier oia.addr16[4], ia->addr16[4], u), 2209126258Smlaier oia.addr16[5], ia->addr16[5], u), 2210126258Smlaier oia.addr16[6], ia->addr16[6], u), 2211126258Smlaier oia.addr16[7], ia->addr16[7], u); 2212126258Smlaier break; 2213126258Smlaier#endif /* INET6 */ 2214126258Smlaier } 2215223637Sbz /* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */ 2216223637Sbz if (oa) { 2217223637Sbz PF_ACPY(oa, na, af); 2218223637Sbz switch (af) { 2219126258Smlaier#ifdef INET 2220223637Sbz case AF_INET: 2221223637Sbz *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, 2222223637Sbz ooa.addr16[0], oa->addr16[0], 0), 2223223637Sbz ooa.addr16[1], oa->addr16[1], 0); 2224223637Sbz break; 2225126258Smlaier#endif /* INET */ 2226126258Smlaier#ifdef INET6 2227223637Sbz case AF_INET6: 2228223637Sbz *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2229223637Sbz pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( 2230223637Sbz pf_cksum_fixup(pf_cksum_fixup(*ic, 2231223637Sbz ooa.addr16[0], oa->addr16[0], u), 2232223637Sbz ooa.addr16[1], oa->addr16[1], u), 2233223637Sbz ooa.addr16[2], oa->addr16[2], u), 2234223637Sbz ooa.addr16[3], oa->addr16[3], u), 2235223637Sbz ooa.addr16[4], oa->addr16[4], u), 2236223637Sbz ooa.addr16[5], oa->addr16[5], u), 2237223637Sbz ooa.addr16[6], oa->addr16[6], u), 2238223637Sbz ooa.addr16[7], oa->addr16[7], u); 2239223637Sbz break; 2240126258Smlaier#endif /* INET6 */ 2241223637Sbz } 2242126258Smlaier } 2243126258Smlaier} 2244126258Smlaier 2245171168Smlaier 2246171168Smlaier/* 2247171168Smlaier * Need to modulate the sequence numbers in the TCP SACK option 2248171168Smlaier * (credits to Krzysztof Pfaff for report and patch) 2249171168Smlaier */ 2250171168Smlaierint 2251171168Smlaierpf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd, 2252171168Smlaier struct tcphdr *th, struct pf_state_peer *dst) 2253171168Smlaier{ 2254171168Smlaier int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen; 2255171168Smlaier#ifdef __FreeBSD__ 2256171168Smlaier u_int8_t opts[TCP_MAXOLEN], *opt = opts; 2257171168Smlaier#else 2258171168Smlaier u_int8_t opts[MAX_TCPOPTLEN], *opt = opts; 2259171168Smlaier#endif 2260171168Smlaier int copyback = 0, i, olen; 2261171168Smlaier struct sackblk sack; 2262171168Smlaier 2263223637Sbz#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) 2264171168Smlaier if (hlen < TCPOLEN_SACKLEN || 2265171168Smlaier !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af)) 2266171168Smlaier return 0; 2267171168Smlaier 2268171168Smlaier while (hlen >= TCPOLEN_SACKLEN) { 2269171168Smlaier olen = opt[1]; 2270171168Smlaier switch (*opt) { 2271171168Smlaier case TCPOPT_EOL: /* FALLTHROUGH */ 2272171168Smlaier case TCPOPT_NOP: 2273171168Smlaier opt++; 2274171168Smlaier hlen--; 2275171168Smlaier break; 2276171168Smlaier case TCPOPT_SACK: 2277171168Smlaier if (olen > hlen) 2278171168Smlaier olen = hlen; 2279171168Smlaier if (olen >= TCPOLEN_SACKLEN) { 2280171168Smlaier for (i = 2; i + TCPOLEN_SACK <= olen; 2281171168Smlaier i += TCPOLEN_SACK) { 2282171168Smlaier memcpy(&sack, &opt[i], sizeof(sack)); 2283293896Sglebius pf_change_proto_a(m, &sack.start, &th->th_sum, 2284293896Sglebius htonl(ntohl(sack.start) - dst->seqdiff), 0); 2285293896Sglebius pf_change_proto_a(m, &sack.end, &th->th_sum, 2286293896Sglebius htonl(ntohl(sack.end) - dst->seqdiff), 0); 2287171168Smlaier memcpy(&opt[i], &sack, sizeof(sack)); 2288171168Smlaier } 2289171168Smlaier copyback = 1; 2290171168Smlaier } 2291171168Smlaier /* FALLTHROUGH */ 2292171168Smlaier default: 2293171168Smlaier if (olen < 2) 2294171168Smlaier olen = 2; 2295171168Smlaier hlen -= olen; 2296171168Smlaier opt += olen; 2297171168Smlaier } 2298171168Smlaier } 2299171168Smlaier 2300171168Smlaier if (copyback) 2301171168Smlaier#ifdef __FreeBSD__ 2302171168Smlaier m_copyback(m, off + sizeof(*th), thoptlen, (caddr_t)opts); 2303171168Smlaier#else 2304171168Smlaier m_copyback(m, off + sizeof(*th), thoptlen, opts); 2305171168Smlaier#endif 2306171168Smlaier return (copyback); 2307171168Smlaier} 2308171168Smlaier 2309126258Smlaiervoid 2310162238Scsjp#ifdef __FreeBSD__ 2311162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, 2312162238Scsjp#else 2313126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af, 2314162238Scsjp#endif 2315126258Smlaier const struct pf_addr *saddr, const struct pf_addr *daddr, 2316126258Smlaier u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, 2317145836Smlaier u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag, 2318171168Smlaier u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp) 2319126258Smlaier{ 2320126258Smlaier struct mbuf *m; 2321171168Smlaier int len, tlen; 2322126258Smlaier#ifdef INET 2323171168Smlaier struct ip *h; 2324126258Smlaier#endif /* INET */ 2325126258Smlaier#ifdef INET6 2326171168Smlaier struct ip6_hdr *h6; 2327126258Smlaier#endif /* INET6 */ 2328171168Smlaier struct tcphdr *th; 2329171168Smlaier char *opt; 2330223637Sbz#ifdef __FreeBSD__ 2331223637Sbz struct pf_mtag *pf_mtag; 2332126258Smlaier 2333171168Smlaier KASSERT( 2334171168Smlaier#ifdef INET 2335171168Smlaier af == AF_INET 2336171168Smlaier#else 2337171168Smlaier 0 2338171168Smlaier#endif 2339171168Smlaier || 2340171168Smlaier#ifdef INET6 2341171168Smlaier af == AF_INET6 2342171168Smlaier#else 2343171168Smlaier 0 2344171168Smlaier#endif 2345171168Smlaier , ("Unsupported AF %d", af)); 2346171168Smlaier len = 0; 2347171168Smlaier th = NULL; 2348171168Smlaier#ifdef INET 2349171168Smlaier h = NULL; 2350171168Smlaier#endif 2351171168Smlaier#ifdef INET6 2352171168Smlaier h6 = NULL; 2353171168Smlaier#endif 2354223637Sbz#endif /* __FreeBSD__ */ 2355171168Smlaier 2356126258Smlaier /* maximum segment size tcp option */ 2357126258Smlaier tlen = sizeof(struct tcphdr); 2358126258Smlaier if (mss) 2359126258Smlaier tlen += 4; 2360126258Smlaier 2361126258Smlaier switch (af) { 2362126258Smlaier#ifdef INET 2363126258Smlaier case AF_INET: 2364126258Smlaier len = sizeof(struct ip) + tlen; 2365126258Smlaier break; 2366126258Smlaier#endif /* INET */ 2367126258Smlaier#ifdef INET6 2368126258Smlaier case AF_INET6: 2369126258Smlaier len = sizeof(struct ip6_hdr) + tlen; 2370126258Smlaier break; 2371126258Smlaier#endif /* INET6 */ 2372126258Smlaier } 2373126258Smlaier 2374126258Smlaier /* create outgoing mbuf */ 2375132280Smlaier m = m_gethdr(M_DONTWAIT, MT_HEADER); 2376132280Smlaier if (m == NULL) 2377132280Smlaier return; 2378162238Scsjp#ifdef __FreeBSD__ 2379162238Scsjp#ifdef MAC 2380223637Sbz mac_netinet_firewall_send(m); 2381162238Scsjp#endif 2382171168Smlaier if ((pf_mtag = pf_get_mtag(m)) == NULL) { 2383171168Smlaier m_freem(m); 2384171168Smlaier return; 2385171168Smlaier } 2386223637Sbz#endif 2387171168Smlaier if (tag) 2388145836Smlaier#ifdef __FreeBSD__ 2389145836Smlaier m->m_flags |= M_SKIP_FIREWALL; 2390223637Sbz pf_mtag->tag = rtag; 2391132280Smlaier#else 2392223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2393223637Sbz m->m_pkthdr.pf.tag = rtag; 2394171168Smlaier#endif 2395145836Smlaier 2396171168Smlaier if (r != NULL && r->rtableid >= 0) 2397178888Sjulian#ifdef __FreeBSD__ 2398178888Sjulian { 2399178888Sjulian M_SETFIB(m, r->rtableid); 2400223637Sbz pf_mtag->rtableid = r->rtableid; 2401223637Sbz#else 2402223637Sbz m->m_pkthdr.pf.rtableid = r->rtableid; 2403178888Sjulian#endif 2404178888Sjulian#ifdef __FreeBSD__ 2405178888Sjulian } 2406178888Sjulian#endif 2407223637Sbz 2408126258Smlaier#ifdef ALTQ 2409126258Smlaier if (r != NULL && r->qid) { 2410223637Sbz#ifdef __FreeBSD__ 2411171168Smlaier pf_mtag->qid = r->qid; 2412223637Sbz 2413171168Smlaier /* add hints for ecn */ 2414171168Smlaier pf_mtag->hdr = mtod(m, struct ip *); 2415223637Sbz#else 2416223637Sbz m->m_pkthdr.pf.qid = r->qid; 2417223637Sbz /* add hints for ecn */ 2418223637Sbz m->m_pkthdr.pf.hdr = mtod(m, struct ip *); 2419223637Sbz#endif 2420126258Smlaier } 2421145836Smlaier#endif /* ALTQ */ 2422126258Smlaier m->m_data += max_linkhdr; 2423126258Smlaier m->m_pkthdr.len = m->m_len = len; 2424126258Smlaier m->m_pkthdr.rcvif = NULL; 2425126258Smlaier bzero(m->m_data, len); 2426126258Smlaier switch (af) { 2427126258Smlaier#ifdef INET 2428126258Smlaier case AF_INET: 2429126258Smlaier h = mtod(m, struct ip *); 2430126258Smlaier 2431126258Smlaier /* IP header fields included in the TCP checksum */ 2432126258Smlaier h->ip_p = IPPROTO_TCP; 2433126258Smlaier h->ip_len = htons(tlen); 2434126258Smlaier h->ip_src.s_addr = saddr->v4.s_addr; 2435126258Smlaier h->ip_dst.s_addr = daddr->v4.s_addr; 2436126258Smlaier 2437126258Smlaier th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip)); 2438126258Smlaier break; 2439126258Smlaier#endif /* INET */ 2440126258Smlaier#ifdef INET6 2441126258Smlaier case AF_INET6: 2442126258Smlaier h6 = mtod(m, struct ip6_hdr *); 2443126258Smlaier 2444126258Smlaier /* IP header fields included in the TCP checksum */ 2445126258Smlaier h6->ip6_nxt = IPPROTO_TCP; 2446126258Smlaier h6->ip6_plen = htons(tlen); 2447126258Smlaier memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr)); 2448126258Smlaier memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr)); 2449126258Smlaier 2450126258Smlaier th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr)); 2451126258Smlaier break; 2452126258Smlaier#endif /* INET6 */ 2453126258Smlaier } 2454126258Smlaier 2455126258Smlaier /* TCP header */ 2456126258Smlaier th->th_sport = sport; 2457126258Smlaier th->th_dport = dport; 2458126258Smlaier th->th_seq = htonl(seq); 2459126258Smlaier th->th_ack = htonl(ack); 2460126258Smlaier th->th_off = tlen >> 2; 2461126258Smlaier th->th_flags = flags; 2462126258Smlaier th->th_win = htons(win); 2463126258Smlaier 2464126258Smlaier if (mss) { 2465126258Smlaier opt = (char *)(th + 1); 2466126258Smlaier opt[0] = TCPOPT_MAXSEG; 2467126258Smlaier opt[1] = 4; 2468126258Smlaier HTONS(mss); 2469126258Smlaier bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2); 2470126258Smlaier } 2471126258Smlaier 2472126258Smlaier switch (af) { 2473126258Smlaier#ifdef INET 2474126258Smlaier case AF_INET: 2475126258Smlaier /* TCP checksum */ 2476126258Smlaier th->th_sum = in_cksum(m, len); 2477126258Smlaier 2478126258Smlaier /* Finish the IP header */ 2479126258Smlaier h->ip_v = 4; 2480126258Smlaier h->ip_hl = sizeof(*h) >> 2; 2481126258Smlaier h->ip_tos = IPTOS_LOWDELAY; 2482127145Smlaier#ifdef __FreeBSD__ 2483181803Sbz h->ip_off = V_path_mtu_discovery ? IP_DF : 0; 2484130613Smlaier h->ip_len = len; 2485223637Sbz h->ip_ttl = ttl ? ttl : V_ip_defttl; 2486126261Smlaier#else 2487223637Sbz h->ip_len = htons(len); 2488126261Smlaier h->ip_off = htons(ip_mtudisc ? IP_DF : 0); 2489223637Sbz h->ip_ttl = ttl ? ttl : ip_defttl; 2490126261Smlaier#endif 2491126258Smlaier h->ip_sum = 0; 2492145836Smlaier if (eh == NULL) { 2493127145Smlaier#ifdef __FreeBSD__ 2494223637Sbz PF_UNLOCK(); 2495223637Sbz ip_output(m, (void *)NULL, (void *)NULL, 0, 2496223637Sbz (void *)NULL, (void *)NULL); 2497223637Sbz PF_LOCK(); 2498126261Smlaier#else /* ! __FreeBSD__ */ 2499145836Smlaier ip_output(m, (void *)NULL, (void *)NULL, 0, 2500145836Smlaier (void *)NULL, (void *)NULL); 2501126261Smlaier#endif 2502145836Smlaier } else { 2503145836Smlaier struct route ro; 2504145836Smlaier struct rtentry rt; 2505145836Smlaier struct ether_header *e = (void *)ro.ro_dst.sa_data; 2506145836Smlaier 2507145836Smlaier if (ifp == NULL) { 2508145836Smlaier m_freem(m); 2509145836Smlaier return; 2510145836Smlaier } 2511145836Smlaier rt.rt_ifp = ifp; 2512145836Smlaier ro.ro_rt = &rt; 2513145836Smlaier ro.ro_dst.sa_len = sizeof(ro.ro_dst); 2514145836Smlaier ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT; 2515145836Smlaier bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN); 2516145836Smlaier bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN); 2517145836Smlaier e->ether_type = eh->ether_type; 2518145836Smlaier#ifdef __FreeBSD__ 2519145836Smlaier PF_UNLOCK(); 2520145836Smlaier /* XXX_IMPORT: later */ 2521145836Smlaier ip_output(m, (void *)NULL, &ro, 0, 2522145836Smlaier (void *)NULL, (void *)NULL); 2523145836Smlaier PF_LOCK(); 2524145836Smlaier#else /* ! __FreeBSD__ */ 2525145836Smlaier ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER, 2526145836Smlaier (void *)NULL, (void *)NULL); 2527145836Smlaier#endif 2528145836Smlaier } 2529126258Smlaier break; 2530126258Smlaier#endif /* INET */ 2531126258Smlaier#ifdef INET6 2532126258Smlaier case AF_INET6: 2533126258Smlaier /* TCP checksum */ 2534126258Smlaier th->th_sum = in6_cksum(m, IPPROTO_TCP, 2535126258Smlaier sizeof(struct ip6_hdr), tlen); 2536126258Smlaier 2537126258Smlaier h6->ip6_vfc |= IPV6_VERSION; 2538126258Smlaier h6->ip6_hlim = IPV6_DEFHLIM; 2539126258Smlaier 2540127145Smlaier#ifdef __FreeBSD__ 2541126261Smlaier PF_UNLOCK(); 2542126261Smlaier ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 2543126261Smlaier PF_LOCK(); 2544126261Smlaier#else 2545223637Sbz ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 2546126261Smlaier#endif 2547126258Smlaier break; 2548126258Smlaier#endif /* INET6 */ 2549126258Smlaier } 2550126258Smlaier} 2551126258Smlaier 2552223637Sbzstatic void 2553126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, 2554126258Smlaier struct pf_rule *r) 2555126258Smlaier{ 2556126258Smlaier struct mbuf *m0; 2557127145Smlaier#ifdef __FreeBSD__ 2558221132Sbz#ifdef INET 2559126261Smlaier struct ip *ip; 2560126261Smlaier#endif 2561223637Sbz struct pf_mtag *pf_mtag; 2562221132Sbz#endif 2563126258Smlaier 2564132280Smlaier#ifdef __FreeBSD__ 2565132280Smlaier m0 = m_copypacket(m, M_DONTWAIT); 2566132280Smlaier if (m0 == NULL) 2567132280Smlaier return; 2568132280Smlaier#else 2569223637Sbz if ((m0 = m_copy(m, 0, M_COPYALL)) == NULL) 2570223637Sbz return; 2571171168Smlaier#endif 2572223637Sbz 2573223637Sbz#ifdef __FreeBSD__ 2574171168Smlaier if ((pf_mtag = pf_get_mtag(m0)) == NULL) 2575126258Smlaier return; 2576171168Smlaier /* XXX: revisit */ 2577171168Smlaier m0->m_flags |= M_SKIP_FIREWALL; 2578171168Smlaier#else 2579223637Sbz m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2580132280Smlaier#endif 2581126258Smlaier 2582171168Smlaier if (r->rtableid >= 0) 2583178888Sjulian#ifdef __FreeBSD__ 2584178888Sjulian { 2585178888Sjulian M_SETFIB(m0, r->rtableid); 2586223637Sbz pf_mtag->rtableid = r->rtableid; 2587223637Sbz#else 2588223637Sbz m0->m_pkthdr.pf.rtableid = r->rtableid; 2589178888Sjulian#endif 2590178888Sjulian#ifdef __FreeBSD__ 2591178888Sjulian } 2592178888Sjulian#endif 2593171168Smlaier 2594126258Smlaier#ifdef ALTQ 2595126258Smlaier if (r->qid) { 2596223637Sbz#ifdef __FreeBSD__ 2597171168Smlaier pf_mtag->qid = r->qid; 2598171168Smlaier /* add hints for ecn */ 2599171168Smlaier pf_mtag->hdr = mtod(m0, struct ip *); 2600223637Sbz#else 2601223637Sbz m0->m_pkthdr.pf.qid = r->qid; 2602223637Sbz /* add hints for ecn */ 2603223637Sbz m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *); 2604223637Sbz#endif 2605126258Smlaier } 2606145836Smlaier#endif /* ALTQ */ 2607126258Smlaier 2608126258Smlaier switch (af) { 2609126258Smlaier#ifdef INET 2610126258Smlaier case AF_INET: 2611127145Smlaier#ifdef __FreeBSD__ 2612126261Smlaier /* icmp_error() expects host byte ordering */ 2613126261Smlaier ip = mtod(m0, struct ip *); 2614126261Smlaier NTOHS(ip->ip_len); 2615126261Smlaier NTOHS(ip->ip_off); 2616126261Smlaier PF_UNLOCK(); 2617145863Sandre icmp_error(m0, type, code, 0, 0); 2618126261Smlaier PF_LOCK(); 2619145874Smlaier#else 2620171168Smlaier icmp_error(m0, type, code, 0, 0); 2621126261Smlaier#endif 2622126258Smlaier break; 2623126258Smlaier#endif /* INET */ 2624126258Smlaier#ifdef INET6 2625126258Smlaier case AF_INET6: 2626127145Smlaier#ifdef __FreeBSD__ 2627126261Smlaier PF_UNLOCK(); 2628126261Smlaier#endif 2629126258Smlaier icmp6_error(m0, type, code, 0); 2630127145Smlaier#ifdef __FreeBSD__ 2631126261Smlaier PF_LOCK(); 2632126261Smlaier#endif 2633126258Smlaier break; 2634126258Smlaier#endif /* INET6 */ 2635126258Smlaier } 2636126258Smlaier} 2637126258Smlaier 2638126258Smlaier/* 2639126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0. 2640126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they 2641126258Smlaier * are different. 2642126258Smlaier */ 2643126258Smlaierint 2644126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m, 2645126258Smlaier struct pf_addr *b, sa_family_t af) 2646126258Smlaier{ 2647126258Smlaier int match = 0; 2648126258Smlaier 2649126258Smlaier switch (af) { 2650126258Smlaier#ifdef INET 2651126258Smlaier case AF_INET: 2652126258Smlaier if ((a->addr32[0] & m->addr32[0]) == 2653126258Smlaier (b->addr32[0] & m->addr32[0])) 2654126258Smlaier match++; 2655126258Smlaier break; 2656126258Smlaier#endif /* INET */ 2657126258Smlaier#ifdef INET6 2658126258Smlaier case AF_INET6: 2659126258Smlaier if (((a->addr32[0] & m->addr32[0]) == 2660126258Smlaier (b->addr32[0] & m->addr32[0])) && 2661126258Smlaier ((a->addr32[1] & m->addr32[1]) == 2662126258Smlaier (b->addr32[1] & m->addr32[1])) && 2663126258Smlaier ((a->addr32[2] & m->addr32[2]) == 2664126258Smlaier (b->addr32[2] & m->addr32[2])) && 2665126258Smlaier ((a->addr32[3] & m->addr32[3]) == 2666126258Smlaier (b->addr32[3] & m->addr32[3]))) 2667126258Smlaier match++; 2668126258Smlaier break; 2669126258Smlaier#endif /* INET6 */ 2670126258Smlaier } 2671126258Smlaier if (match) { 2672126258Smlaier if (n) 2673126258Smlaier return (0); 2674126258Smlaier else 2675126258Smlaier return (1); 2676126258Smlaier } else { 2677126258Smlaier if (n) 2678126258Smlaier return (1); 2679126258Smlaier else 2680126258Smlaier return (0); 2681126258Smlaier } 2682126258Smlaier} 2683126258Smlaier 2684223637Sbz/* 2685223637Sbz * Return 1 if b <= a <= e, otherwise return 0. 2686223637Sbz */ 2687126258Smlaierint 2688223637Sbzpf_match_addr_range(struct pf_addr *b, struct pf_addr *e, 2689223637Sbz struct pf_addr *a, sa_family_t af) 2690223637Sbz{ 2691223637Sbz switch (af) { 2692223637Sbz#ifdef INET 2693223637Sbz case AF_INET: 2694223637Sbz if ((a->addr32[0] < b->addr32[0]) || 2695223637Sbz (a->addr32[0] > e->addr32[0])) 2696223637Sbz return (0); 2697223637Sbz break; 2698223637Sbz#endif /* INET */ 2699223637Sbz#ifdef INET6 2700223637Sbz case AF_INET6: { 2701223637Sbz int i; 2702223637Sbz 2703223637Sbz /* check a >= b */ 2704223637Sbz for (i = 0; i < 4; ++i) 2705223637Sbz if (a->addr32[i] > b->addr32[i]) 2706223637Sbz break; 2707223637Sbz else if (a->addr32[i] < b->addr32[i]) 2708223637Sbz return (0); 2709223637Sbz /* check a <= e */ 2710223637Sbz for (i = 0; i < 4; ++i) 2711223637Sbz if (a->addr32[i] < e->addr32[i]) 2712223637Sbz break; 2713223637Sbz else if (a->addr32[i] > e->addr32[i]) 2714223637Sbz return (0); 2715223637Sbz break; 2716223637Sbz } 2717223637Sbz#endif /* INET6 */ 2718223637Sbz } 2719223637Sbz return (1); 2720223637Sbz} 2721223637Sbz 2722223637Sbzint 2723126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p) 2724126258Smlaier{ 2725126258Smlaier switch (op) { 2726126258Smlaier case PF_OP_IRG: 2727126258Smlaier return ((p > a1) && (p < a2)); 2728126258Smlaier case PF_OP_XRG: 2729126258Smlaier return ((p < a1) || (p > a2)); 2730126258Smlaier case PF_OP_RRG: 2731126258Smlaier return ((p >= a1) && (p <= a2)); 2732126258Smlaier case PF_OP_EQ: 2733126258Smlaier return (p == a1); 2734126258Smlaier case PF_OP_NE: 2735126258Smlaier return (p != a1); 2736126258Smlaier case PF_OP_LT: 2737126258Smlaier return (p < a1); 2738126258Smlaier case PF_OP_LE: 2739126258Smlaier return (p <= a1); 2740126258Smlaier case PF_OP_GT: 2741126258Smlaier return (p > a1); 2742126258Smlaier case PF_OP_GE: 2743126258Smlaier return (p >= a1); 2744126258Smlaier } 2745126258Smlaier return (0); /* never reached */ 2746126258Smlaier} 2747126258Smlaier 2748126258Smlaierint 2749126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p) 2750126258Smlaier{ 2751126258Smlaier NTOHS(a1); 2752126258Smlaier NTOHS(a2); 2753126258Smlaier NTOHS(p); 2754126258Smlaier return (pf_match(op, a1, a2, p)); 2755126258Smlaier} 2756126258Smlaier 2757126258Smlaierint 2758126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u) 2759126258Smlaier{ 2760126258Smlaier if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE) 2761126258Smlaier return (0); 2762126258Smlaier return (pf_match(op, a1, a2, u)); 2763126258Smlaier} 2764126258Smlaier 2765126258Smlaierint 2766126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) 2767126258Smlaier{ 2768126258Smlaier if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE) 2769126258Smlaier return (0); 2770126258Smlaier return (pf_match(op, a1, a2, g)); 2771126258Smlaier} 2772126258Smlaier 2773223637Sbzint 2774223637Sbz#ifdef __FreeBSD__ 2775223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag, 2776223637Sbz struct pf_mtag *pf_mtag) 2777223637Sbz#else 2778223637Sbzpf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag) 2779171168Smlaier#endif 2780171168Smlaier{ 2781171168Smlaier if (*tag == -1) 2782223637Sbz#ifdef __FreeBSD__ 2783171168Smlaier *tag = pf_mtag->tag; 2784223637Sbz#else 2785223637Sbz *tag = m->m_pkthdr.pf.tag; 2786223637Sbz#endif 2787171168Smlaier 2788126258Smlaier return ((!r->match_tag_not && r->match_tag == *tag) || 2789126258Smlaier (r->match_tag_not && r->match_tag != *tag)); 2790126258Smlaier} 2791126258Smlaier 2792126258Smlaierint 2793223637Sbz#ifdef __FreeBSD__ 2794223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid, 2795223637Sbz struct pf_mtag *pf_mtag) 2796223637Sbz#else 2797223637Sbzpf_tag_packet(struct mbuf *m, int tag, int rtableid) 2798223637Sbz#endif 2799126258Smlaier{ 2800171168Smlaier if (tag <= 0 && rtableid < 0) 2801126258Smlaier return (0); 2802126258Smlaier 2803171168Smlaier if (tag > 0) 2804223637Sbz#ifdef __FreeBSD__ 2805171168Smlaier pf_mtag->tag = tag; 2806223637Sbz#else 2807223637Sbz m->m_pkthdr.pf.tag = tag; 2808223637Sbz#endif 2809171168Smlaier if (rtableid >= 0) 2810178888Sjulian#ifdef __FreeBSD__ 2811178888Sjulian { 2812178888Sjulian M_SETFIB(m, rtableid); 2813178888Sjulian } 2814223637Sbz#else 2815223637Sbz m->m_pkthdr.pf.rtableid = rtableid; 2816178888Sjulian#endif 2817126258Smlaier 2818126258Smlaier return (0); 2819126258Smlaier} 2820126258Smlaier 2821223637Sbzvoid 2822145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, 2823223637Sbz struct pf_rule **r, struct pf_rule **a, int *match) 2824145836Smlaier{ 2825145836Smlaier struct pf_anchor_stackframe *f; 2826126258Smlaier 2827171168Smlaier (*r)->anchor->match = 0; 2828171168Smlaier if (match) 2829171168Smlaier *match = 0; 2830223637Sbz#ifdef __FreeBSD__ 2831223637Sbz if (*depth >= sizeof(V_pf_anchor_stack) / 2832223637Sbz sizeof(V_pf_anchor_stack[0])) { 2833223637Sbz#else 2834145836Smlaier if (*depth >= sizeof(pf_anchor_stack) / 2835145836Smlaier sizeof(pf_anchor_stack[0])) { 2836223637Sbz#endif 2837145836Smlaier printf("pf_step_into_anchor: stack overflow\n"); 2838145836Smlaier *r = TAILQ_NEXT(*r, entries); 2839145836Smlaier return; 2840145836Smlaier } else if (*depth == 0 && a != NULL) 2841145836Smlaier *a = *r; 2842223637Sbz#ifdef __FreeBSD__ 2843223637Sbz f = V_pf_anchor_stack + (*depth)++; 2844223637Sbz#else 2845145836Smlaier f = pf_anchor_stack + (*depth)++; 2846223637Sbz#endif 2847145836Smlaier f->rs = *rs; 2848145836Smlaier f->r = *r; 2849145836Smlaier if ((*r)->anchor_wildcard) { 2850145836Smlaier f->parent = &(*r)->anchor->children; 2851145836Smlaier if ((f->child = RB_MIN(pf_anchor_node, f->parent)) == 2852145836Smlaier NULL) { 2853145836Smlaier *r = NULL; 2854145836Smlaier return; 2855145836Smlaier } 2856145836Smlaier *rs = &f->child->ruleset; 2857145836Smlaier } else { 2858145836Smlaier f->parent = NULL; 2859145836Smlaier f->child = NULL; 2860145836Smlaier *rs = &(*r)->anchor->ruleset; 2861145836Smlaier } 2862145836Smlaier *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); 2863145836Smlaier} 2864126258Smlaier 2865171168Smlaierint 2866145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, 2867171168Smlaier struct pf_rule **r, struct pf_rule **a, int *match) 2868145836Smlaier{ 2869145836Smlaier struct pf_anchor_stackframe *f; 2870171168Smlaier int quick = 0; 2871145836Smlaier 2872145836Smlaier do { 2873145836Smlaier if (*depth <= 0) 2874145836Smlaier break; 2875223637Sbz#ifdef __FreeBSD__ 2876223637Sbz f = V_pf_anchor_stack + *depth - 1; 2877223637Sbz#else 2878145836Smlaier f = pf_anchor_stack + *depth - 1; 2879223637Sbz#endif 2880145836Smlaier if (f->parent != NULL && f->child != NULL) { 2881171168Smlaier if (f->child->match || 2882171168Smlaier (match != NULL && *match)) { 2883171168Smlaier f->r->anchor->match = 1; 2884171168Smlaier *match = 0; 2885171168Smlaier } 2886145836Smlaier f->child = RB_NEXT(pf_anchor_node, f->parent, f->child); 2887145836Smlaier if (f->child != NULL) { 2888145836Smlaier *rs = &f->child->ruleset; 2889145836Smlaier *r = TAILQ_FIRST((*rs)->rules[n].active.ptr); 2890145836Smlaier if (*r == NULL) 2891145836Smlaier continue; 2892145836Smlaier else 2893145836Smlaier break; 2894145836Smlaier } 2895145836Smlaier } 2896145836Smlaier (*depth)--; 2897145836Smlaier if (*depth == 0 && a != NULL) 2898145836Smlaier *a = NULL; 2899145836Smlaier *rs = f->rs; 2900223637Sbz if (f->r->anchor->match || (match != NULL && *match)) 2901171168Smlaier quick = f->r->quick; 2902145836Smlaier *r = TAILQ_NEXT(f->r, entries); 2903145836Smlaier } while (*r == NULL); 2904171168Smlaier 2905171168Smlaier return (quick); 2906145836Smlaier} 2907145836Smlaier 2908126258Smlaier#ifdef INET6 2909126258Smlaiervoid 2910126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr, 2911126258Smlaier struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af) 2912126258Smlaier{ 2913126258Smlaier switch (af) { 2914126258Smlaier#ifdef INET 2915126258Smlaier case AF_INET: 2916126258Smlaier naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) | 2917126258Smlaier ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]); 2918126258Smlaier break; 2919126258Smlaier#endif /* INET */ 2920126258Smlaier case AF_INET6: 2921126258Smlaier naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) | 2922126258Smlaier ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]); 2923126258Smlaier naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) | 2924126258Smlaier ((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]); 2925126258Smlaier naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) | 2926126258Smlaier ((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]); 2927126258Smlaier naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) | 2928126258Smlaier ((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]); 2929126258Smlaier break; 2930126258Smlaier } 2931126258Smlaier} 2932126258Smlaier 2933126258Smlaiervoid 2934130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af) 2935126258Smlaier{ 2936126258Smlaier switch (af) { 2937126258Smlaier#ifdef INET 2938126258Smlaier case AF_INET: 2939126258Smlaier addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1); 2940126258Smlaier break; 2941126258Smlaier#endif /* INET */ 2942126258Smlaier case AF_INET6: 2943126258Smlaier if (addr->addr32[3] == 0xffffffff) { 2944126258Smlaier addr->addr32[3] = 0; 2945126258Smlaier if (addr->addr32[2] == 0xffffffff) { 2946126258Smlaier addr->addr32[2] = 0; 2947126258Smlaier if (addr->addr32[1] == 0xffffffff) { 2948126258Smlaier addr->addr32[1] = 0; 2949126258Smlaier addr->addr32[0] = 2950126258Smlaier htonl(ntohl(addr->addr32[0]) + 1); 2951126258Smlaier } else 2952126258Smlaier addr->addr32[1] = 2953126258Smlaier htonl(ntohl(addr->addr32[1]) + 1); 2954126258Smlaier } else 2955126258Smlaier addr->addr32[2] = 2956126258Smlaier htonl(ntohl(addr->addr32[2]) + 1); 2957126258Smlaier } else 2958126258Smlaier addr->addr32[3] = 2959126258Smlaier htonl(ntohl(addr->addr32[3]) + 1); 2960126258Smlaier break; 2961126258Smlaier } 2962126258Smlaier} 2963126258Smlaier#endif /* INET6 */ 2964126258Smlaier 2965126258Smlaierint 2966135920Smlaier#ifdef __FreeBSD__ 2967171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg) 2968135920Smlaier#else 2969171168Smlaierpf_socket_lookup(int direction, struct pf_pdesc *pd) 2970135920Smlaier#endif 2971126258Smlaier{ 2972126258Smlaier struct pf_addr *saddr, *daddr; 2973126258Smlaier u_int16_t sport, dport; 2974127145Smlaier#ifdef __FreeBSD__ 2975126261Smlaier struct inpcbinfo *pi; 2976126261Smlaier#else 2977126258Smlaier struct inpcbtable *tb; 2978126261Smlaier#endif 2979126258Smlaier struct inpcb *inp; 2980126258Smlaier 2981171168Smlaier if (pd == NULL) 2982171168Smlaier return (-1); 2983171168Smlaier pd->lookup.uid = UID_MAX; 2984171168Smlaier pd->lookup.gid = GID_MAX; 2985223637Sbz pd->lookup.pid = NO_PID; 2986223637Sbz 2987135920Smlaier#ifdef __FreeBSD__ 2988135920Smlaier if (inp_arg != NULL) { 2989178325Srwatson INP_LOCK_ASSERT(inp_arg); 2990183606Sbz pd->lookup.uid = inp_arg->inp_cred->cr_uid; 2991183606Sbz pd->lookup.gid = inp_arg->inp_cred->cr_groups[0]; 2992183606Sbz return (1); 2993135920Smlaier } 2994135920Smlaier#endif 2995223637Sbz 2996130613Smlaier switch (pd->proto) { 2997126258Smlaier case IPPROTO_TCP: 2998171168Smlaier if (pd->hdr.tcp == NULL) 2999171168Smlaier return (-1); 3000126258Smlaier sport = pd->hdr.tcp->th_sport; 3001126258Smlaier dport = pd->hdr.tcp->th_dport; 3002127145Smlaier#ifdef __FreeBSD__ 3003181803Sbz pi = &V_tcbinfo; 3004126261Smlaier#else 3005126258Smlaier tb = &tcbtable; 3006126261Smlaier#endif 3007126258Smlaier break; 3008126258Smlaier case IPPROTO_UDP: 3009171168Smlaier if (pd->hdr.udp == NULL) 3010171168Smlaier return (-1); 3011126258Smlaier sport = pd->hdr.udp->uh_sport; 3012126258Smlaier dport = pd->hdr.udp->uh_dport; 3013127145Smlaier#ifdef __FreeBSD__ 3014181803Sbz pi = &V_udbinfo; 3015126261Smlaier#else 3016126258Smlaier tb = &udbtable; 3017126261Smlaier#endif 3018126258Smlaier break; 3019126258Smlaier default: 3020171168Smlaier return (-1); 3021126258Smlaier } 3022126258Smlaier if (direction == PF_IN) { 3023126258Smlaier saddr = pd->src; 3024126258Smlaier daddr = pd->dst; 3025126258Smlaier } else { 3026126258Smlaier u_int16_t p; 3027126258Smlaier 3028126258Smlaier p = sport; 3029126258Smlaier sport = dport; 3030126258Smlaier dport = p; 3031126258Smlaier saddr = pd->dst; 3032126258Smlaier daddr = pd->src; 3033126258Smlaier } 3034130613Smlaier switch (pd->af) { 3035145836Smlaier#ifdef INET 3036126258Smlaier case AF_INET: 3037127145Smlaier#ifdef __FreeBSD__ 3038222691Srwatson /* 3039222691Srwatson * XXXRW: would be nice if we had an mbuf here so that we 3040222691Srwatson * could use in_pcblookup_mbuf(). 3041222691Srwatson */ 3042222488Srwatson inp = in_pcblookup(pi, saddr->v4, sport, daddr->v4, 3043222488Srwatson dport, INPLOOKUP_RLOCKPCB, NULL); 3044126261Smlaier if (inp == NULL) { 3045222488Srwatson inp = in_pcblookup(pi, saddr->v4, sport, 3046222488Srwatson daddr->v4, dport, INPLOOKUP_WILDCARD | 3047222488Srwatson INPLOOKUP_RLOCKPCB, NULL); 3048222488Srwatson if (inp == NULL) 3049171168Smlaier return (-1); 3050126261Smlaier } 3051126261Smlaier#else 3052126258Smlaier inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); 3053126258Smlaier if (inp == NULL) { 3054223637Sbz inp = in_pcblookup_listen(tb, daddr->v4, dport, 0, 3055223637Sbz NULL); 3056126258Smlaier if (inp == NULL) 3057171168Smlaier return (-1); 3058126258Smlaier } 3059126261Smlaier#endif 3060126258Smlaier break; 3061145836Smlaier#endif /* INET */ 3062126258Smlaier#ifdef INET6 3063126258Smlaier case AF_INET6: 3064127145Smlaier#ifdef __FreeBSD__ 3065222691Srwatson /* 3066222691Srwatson * XXXRW: would be nice if we had an mbuf here so that we 3067222691Srwatson * could use in6_pcblookup_mbuf(). 3068222691Srwatson */ 3069222488Srwatson inp = in6_pcblookup(pi, &saddr->v6, sport, 3070222488Srwatson &daddr->v6, dport, INPLOOKUP_RLOCKPCB, NULL); 3071126261Smlaier if (inp == NULL) { 3072222488Srwatson inp = in6_pcblookup(pi, &saddr->v6, sport, 3073222488Srwatson &daddr->v6, dport, INPLOOKUP_WILDCARD | 3074222488Srwatson INPLOOKUP_RLOCKPCB, NULL); 3075222488Srwatson if (inp == NULL) 3076171168Smlaier return (-1); 3077126261Smlaier } 3078126261Smlaier#else 3079126258Smlaier inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6, 3080126258Smlaier dport); 3081126258Smlaier if (inp == NULL) { 3082223637Sbz inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0, 3083223637Sbz NULL); 3084126258Smlaier if (inp == NULL) 3085171168Smlaier return (-1); 3086126258Smlaier } 3087126261Smlaier#endif 3088126258Smlaier break; 3089126258Smlaier#endif /* INET6 */ 3090126258Smlaier 3091126258Smlaier default: 3092171168Smlaier return (-1); 3093126258Smlaier } 3094127145Smlaier#ifdef __FreeBSD__ 3095222488Srwatson INP_RLOCK_ASSERT(inp); 3096183606Sbz pd->lookup.uid = inp->inp_cred->cr_uid; 3097183606Sbz pd->lookup.gid = inp->inp_cred->cr_groups[0]; 3098222488Srwatson INP_RUNLOCK(inp); 3099126261Smlaier#else 3100171168Smlaier pd->lookup.uid = inp->inp_socket->so_euid; 3101171168Smlaier pd->lookup.gid = inp->inp_socket->so_egid; 3102171168Smlaier pd->lookup.pid = inp->inp_socket->so_cpid; 3103126261Smlaier#endif 3104126258Smlaier return (1); 3105126258Smlaier} 3106126258Smlaier 3107126258Smlaieru_int8_t 3108126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) 3109126258Smlaier{ 3110126258Smlaier int hlen; 3111126258Smlaier u_int8_t hdr[60]; 3112126258Smlaier u_int8_t *opt, optlen; 3113126258Smlaier u_int8_t wscale = 0; 3114126258Smlaier 3115126258Smlaier hlen = th_off << 2; /* hlen <= sizeof(hdr) */ 3116126258Smlaier if (hlen <= sizeof(struct tcphdr)) 3117126258Smlaier return (0); 3118126258Smlaier if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af)) 3119126258Smlaier return (0); 3120126258Smlaier opt = hdr + sizeof(struct tcphdr); 3121126258Smlaier hlen -= sizeof(struct tcphdr); 3122126258Smlaier while (hlen >= 3) { 3123126258Smlaier switch (*opt) { 3124126258Smlaier case TCPOPT_EOL: 3125126258Smlaier case TCPOPT_NOP: 3126126258Smlaier ++opt; 3127126258Smlaier --hlen; 3128126258Smlaier break; 3129126258Smlaier case TCPOPT_WINDOW: 3130126258Smlaier wscale = opt[2]; 3131126258Smlaier if (wscale > TCP_MAX_WINSHIFT) 3132126258Smlaier wscale = TCP_MAX_WINSHIFT; 3133126258Smlaier wscale |= PF_WSCALE_FLAG; 3134130613Smlaier /* FALLTHROUGH */ 3135126258Smlaier default: 3136126258Smlaier optlen = opt[1]; 3137126258Smlaier if (optlen < 2) 3138126258Smlaier optlen = 2; 3139126258Smlaier hlen -= optlen; 3140126258Smlaier opt += optlen; 3141130613Smlaier break; 3142126258Smlaier } 3143126258Smlaier } 3144126258Smlaier return (wscale); 3145126258Smlaier} 3146126258Smlaier 3147126258Smlaieru_int16_t 3148126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) 3149126258Smlaier{ 3150126258Smlaier int hlen; 3151126258Smlaier u_int8_t hdr[60]; 3152126258Smlaier u_int8_t *opt, optlen; 3153223637Sbz#ifdef __FreeBSD__ 3154181803Sbz u_int16_t mss = V_tcp_mssdflt; 3155223637Sbz#else 3156223637Sbz u_int16_t mss = tcp_mssdflt; 3157223637Sbz#endif 3158126258Smlaier 3159126258Smlaier hlen = th_off << 2; /* hlen <= sizeof(hdr) */ 3160126258Smlaier if (hlen <= sizeof(struct tcphdr)) 3161126258Smlaier return (0); 3162126258Smlaier if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af)) 3163126258Smlaier return (0); 3164126258Smlaier opt = hdr + sizeof(struct tcphdr); 3165126258Smlaier hlen -= sizeof(struct tcphdr); 3166126258Smlaier while (hlen >= TCPOLEN_MAXSEG) { 3167126258Smlaier switch (*opt) { 3168126258Smlaier case TCPOPT_EOL: 3169126258Smlaier case TCPOPT_NOP: 3170126258Smlaier ++opt; 3171126258Smlaier --hlen; 3172126258Smlaier break; 3173126258Smlaier case TCPOPT_MAXSEG: 3174126258Smlaier bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2); 3175145030Sglebius NTOHS(mss); 3176130613Smlaier /* FALLTHROUGH */ 3177126258Smlaier default: 3178126258Smlaier optlen = opt[1]; 3179126258Smlaier if (optlen < 2) 3180126258Smlaier optlen = 2; 3181126258Smlaier hlen -= optlen; 3182126258Smlaier opt += optlen; 3183130613Smlaier break; 3184126258Smlaier } 3185126258Smlaier } 3186126258Smlaier return (mss); 3187126258Smlaier} 3188126258Smlaier 3189126258Smlaieru_int16_t 3190232292Sbzpf_calc_mss(struct pf_addr *addr, sa_family_t af, int rtableid, u_int16_t offer) 3191126258Smlaier{ 3192126258Smlaier#ifdef INET 3193126258Smlaier struct sockaddr_in *dst; 3194126258Smlaier struct route ro; 3195126258Smlaier#endif /* INET */ 3196126258Smlaier#ifdef INET6 3197126258Smlaier struct sockaddr_in6 *dst6; 3198126258Smlaier struct route_in6 ro6; 3199126258Smlaier#endif /* INET6 */ 3200126258Smlaier struct rtentry *rt = NULL; 3201223637Sbz#ifdef __FreeBSD__ 3202223637Sbz int hlen = 0; 3203181803Sbz u_int16_t mss = V_tcp_mssdflt; 3204223637Sbz#else 3205223637Sbz int hlen; 3206223637Sbz u_int16_t mss = tcp_mssdflt; 3207223637Sbz#endif 3208126258Smlaier 3209126258Smlaier switch (af) { 3210126258Smlaier#ifdef INET 3211126258Smlaier case AF_INET: 3212126258Smlaier hlen = sizeof(struct ip); 3213126258Smlaier bzero(&ro, sizeof(ro)); 3214126258Smlaier dst = (struct sockaddr_in *)&ro.ro_dst; 3215126258Smlaier dst->sin_family = AF_INET; 3216126258Smlaier dst->sin_len = sizeof(*dst); 3217126258Smlaier dst->sin_addr = addr->v4; 3218127145Smlaier#ifdef __FreeBSD__ 3219232292Sbz in_rtalloc_ign(&ro, 0, rtableid); 3220126261Smlaier#else /* ! __FreeBSD__ */ 3221126258Smlaier rtalloc_noclone(&ro, NO_CLONING); 3222126261Smlaier#endif 3223126258Smlaier rt = ro.ro_rt; 3224126258Smlaier break; 3225126258Smlaier#endif /* INET */ 3226126258Smlaier#ifdef INET6 3227126258Smlaier case AF_INET6: 3228126258Smlaier hlen = sizeof(struct ip6_hdr); 3229126258Smlaier bzero(&ro6, sizeof(ro6)); 3230126258Smlaier dst6 = (struct sockaddr_in6 *)&ro6.ro_dst; 3231126258Smlaier dst6->sin6_family = AF_INET6; 3232126258Smlaier dst6->sin6_len = sizeof(*dst6); 3233126258Smlaier dst6->sin6_addr = addr->v6; 3234127145Smlaier#ifdef __FreeBSD__ 3235232292Sbz in6_rtalloc_ign(&ro6, 0, rtableid); 3236126261Smlaier#else /* ! __FreeBSD__ */ 3237126258Smlaier rtalloc_noclone((struct route *)&ro6, NO_CLONING); 3238126261Smlaier#endif 3239126258Smlaier rt = ro6.ro_rt; 3240126258Smlaier break; 3241126258Smlaier#endif /* INET6 */ 3242126258Smlaier } 3243126258Smlaier 3244126258Smlaier if (rt && rt->rt_ifp) { 3245126258Smlaier mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr); 3246223637Sbz#ifdef __FreeBSD__ 3247181803Sbz mss = max(V_tcp_mssdflt, mss); 3248223637Sbz#else 3249223637Sbz mss = max(tcp_mssdflt, mss); 3250223637Sbz#endif 3251126258Smlaier RTFREE(rt); 3252126258Smlaier } 3253126258Smlaier mss = min(mss, offer); 3254126258Smlaier mss = max(mss, 64); /* sanity - at least max opt space */ 3255126258Smlaier return (mss); 3256126258Smlaier} 3257126258Smlaier 3258126258Smlaiervoid 3259126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) 3260126258Smlaier{ 3261126258Smlaier struct pf_rule *r = s->rule.ptr; 3262223637Sbz struct pf_src_node *sn = NULL; 3263126258Smlaier 3264130613Smlaier s->rt_kif = NULL; 3265126258Smlaier if (!r->rt || r->rt == PF_FASTROUTE) 3266126258Smlaier return; 3267223637Sbz switch (s->key[PF_SK_WIRE]->af) { 3268126258Smlaier#ifdef INET 3269126258Smlaier case AF_INET: 3270223637Sbz pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); 3271130613Smlaier s->rt_kif = r->rpool.cur->kif; 3272126258Smlaier break; 3273126258Smlaier#endif /* INET */ 3274126258Smlaier#ifdef INET6 3275126258Smlaier case AF_INET6: 3276223637Sbz pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); 3277130613Smlaier s->rt_kif = r->rpool.cur->kif; 3278126258Smlaier break; 3279126258Smlaier#endif /* INET6 */ 3280126258Smlaier } 3281126258Smlaier} 3282126258Smlaier 3283223637Sbzu_int32_t 3284223637Sbzpf_tcp_iss(struct pf_pdesc *pd) 3285223637Sbz{ 3286223637Sbz MD5_CTX ctx; 3287223637Sbz u_int32_t digest[4]; 3288223637Sbz 3289223637Sbz#ifdef __FreeBSD__ 3290223637Sbz if (V_pf_tcp_secret_init == 0) { 3291223637Sbz read_random(&V_pf_tcp_secret, sizeof(V_pf_tcp_secret)); 3292223637Sbz MD5Init(&V_pf_tcp_secret_ctx); 3293223637Sbz MD5Update(&V_pf_tcp_secret_ctx, V_pf_tcp_secret, 3294223637Sbz sizeof(V_pf_tcp_secret)); 3295223637Sbz V_pf_tcp_secret_init = 1; 3296223637Sbz } 3297223637Sbz 3298223637Sbz ctx = V_pf_tcp_secret_ctx; 3299223637Sbz#else 3300223637Sbz if (pf_tcp_secret_init == 0) { 3301223637Sbz arc4random_buf(pf_tcp_secret, sizeof(pf_tcp_secret)); 3302223637Sbz MD5Init(&pf_tcp_secret_ctx); 3303223637Sbz MD5Update(&pf_tcp_secret_ctx, pf_tcp_secret, 3304223637Sbz sizeof(pf_tcp_secret)); 3305223637Sbz pf_tcp_secret_init = 1; 3306223637Sbz } 3307223637Sbz 3308223637Sbz ctx = pf_tcp_secret_ctx; 3309223637Sbz#endif 3310223637Sbz 3311223637Sbz MD5Update(&ctx, (char *)&pd->hdr.tcp->th_sport, sizeof(u_short)); 3312223637Sbz MD5Update(&ctx, (char *)&pd->hdr.tcp->th_dport, sizeof(u_short)); 3313223637Sbz if (pd->af == AF_INET6) { 3314223637Sbz MD5Update(&ctx, (char *)&pd->src->v6, sizeof(struct in6_addr)); 3315223637Sbz MD5Update(&ctx, (char *)&pd->dst->v6, sizeof(struct in6_addr)); 3316223637Sbz } else { 3317223637Sbz MD5Update(&ctx, (char *)&pd->src->v4, sizeof(struct in_addr)); 3318223637Sbz MD5Update(&ctx, (char *)&pd->dst->v4, sizeof(struct in_addr)); 3319223637Sbz } 3320223637Sbz MD5Final((u_char *)digest, &ctx); 3321223637Sbz#ifdef __FreeBSD__ 3322223637Sbz V_pf_tcp_iss_off += 4096; 3323223637Sbz#define ISN_RANDOM_INCREMENT (4096 - 1) 3324223637Sbz return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) + 3325223637Sbz V_pf_tcp_iss_off); 3326223637Sbz#undef ISN_RANDOM_INCREMENT 3327223637Sbz#else 3328223637Sbz pf_tcp_iss_off += 4096; 3329223637Sbz return (digest[0] + tcp_iss + pf_tcp_iss_off); 3330223637Sbz#endif 3331223637Sbz} 3332223637Sbz 3333126258Smlaierint 3334223637Sbzpf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, 3335130613Smlaier struct pfi_kif *kif, struct mbuf *m, int off, void *h, 3336223637Sbz struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, 3337135920Smlaier#ifdef __FreeBSD__ 3338145836Smlaier struct ifqueue *ifq, struct inpcb *inp) 3339135920Smlaier#else 3340145836Smlaier struct ifqueue *ifq) 3341135920Smlaier#endif 3342126258Smlaier{ 3343130613Smlaier struct pf_rule *nr = NULL; 3344126258Smlaier struct pf_addr *saddr = pd->src, *daddr = pd->dst; 3345126258Smlaier sa_family_t af = pd->af; 3346126258Smlaier struct pf_rule *r, *a = NULL; 3347126258Smlaier struct pf_ruleset *ruleset = NULL; 3348130613Smlaier struct pf_src_node *nsn = NULL; 3349223637Sbz struct tcphdr *th = pd->hdr.tcp; 3350223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 3351223637Sbz struct pf_state_key *sk = NULL, *nk = NULL; 3352126258Smlaier u_short reason; 3353223637Sbz int rewrite = 0, hdrlen = 0; 3354171168Smlaier int tag = -1, rtableid = -1; 3355145836Smlaier int asd = 0; 3356171168Smlaier int match = 0; 3357223637Sbz int state_icmp = 0; 3358223637Sbz#ifdef __FreeBSD__ 3359223637Sbz u_int16_t sport = 0, dport = 0; 3360223637Sbz u_int16_t bproto_sum = 0, bip_sum = 0; 3361223637Sbz#else 3362223637Sbz u_int16_t sport, dport; 3363223637Sbz u_int16_t bproto_sum = 0, bip_sum; 3364223637Sbz#endif 3365223637Sbz u_int8_t icmptype = 0, icmpcode = 0; 3366126258Smlaier 3367223637Sbz 3368223637Sbz if (direction == PF_IN && pf_check_congestion(ifq)) { 3369145836Smlaier REASON_SET(&reason, PFRES_CONGEST); 3370145836Smlaier return (PF_DROP); 3371145836Smlaier } 3372145836Smlaier 3373171168Smlaier#ifdef __FreeBSD__ 3374171168Smlaier if (inp != NULL) 3375171168Smlaier pd->lookup.done = pf_socket_lookup(direction, pd, inp); 3376223637Sbz else if (V_debug_pfugidhack) { 3377171168Smlaier PF_UNLOCK(); 3378171168Smlaier DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n")); 3379223637Sbz pd->lookup.done = pf_socket_lookup(direction, pd, inp); 3380171168Smlaier PF_LOCK(); 3381171168Smlaier } 3382165631Smlaier#endif 3383165631Smlaier 3384223637Sbz switch (pd->proto) { 3385223637Sbz case IPPROTO_TCP: 3386223637Sbz sport = th->th_sport; 3387223637Sbz dport = th->th_dport; 3388223637Sbz hdrlen = sizeof(*th); 3389223637Sbz break; 3390223637Sbz case IPPROTO_UDP: 3391223637Sbz sport = pd->hdr.udp->uh_sport; 3392223637Sbz dport = pd->hdr.udp->uh_dport; 3393223637Sbz hdrlen = sizeof(*pd->hdr.udp); 3394223637Sbz break; 3395223637Sbz#ifdef INET 3396223637Sbz case IPPROTO_ICMP: 3397223637Sbz if (pd->af != AF_INET) 3398223637Sbz break; 3399223637Sbz sport = dport = pd->hdr.icmp->icmp_id; 3400223637Sbz hdrlen = sizeof(*pd->hdr.icmp); 3401223637Sbz icmptype = pd->hdr.icmp->icmp_type; 3402223637Sbz icmpcode = pd->hdr.icmp->icmp_code; 3403223637Sbz 3404223637Sbz if (icmptype == ICMP_UNREACH || 3405223637Sbz icmptype == ICMP_SOURCEQUENCH || 3406223637Sbz icmptype == ICMP_REDIRECT || 3407223637Sbz icmptype == ICMP_TIMXCEED || 3408223637Sbz icmptype == ICMP_PARAMPROB) 3409223637Sbz state_icmp++; 3410223637Sbz break; 3411223637Sbz#endif /* INET */ 3412223637Sbz#ifdef INET6 3413223637Sbz case IPPROTO_ICMPV6: 3414223637Sbz if (af != AF_INET6) 3415223637Sbz break; 3416223637Sbz sport = dport = pd->hdr.icmp6->icmp6_id; 3417223637Sbz hdrlen = sizeof(*pd->hdr.icmp6); 3418223637Sbz icmptype = pd->hdr.icmp6->icmp6_type; 3419223637Sbz icmpcode = pd->hdr.icmp6->icmp6_code; 3420223637Sbz 3421223637Sbz if (icmptype == ICMP6_DST_UNREACH || 3422223637Sbz icmptype == ICMP6_PACKET_TOO_BIG || 3423223637Sbz icmptype == ICMP6_TIME_EXCEEDED || 3424223637Sbz icmptype == ICMP6_PARAM_PROB) 3425223637Sbz state_icmp++; 3426223637Sbz break; 3427223637Sbz#endif /* INET6 */ 3428223637Sbz default: 3429223637Sbz sport = dport = hdrlen = 0; 3430223637Sbz break; 3431223637Sbz } 3432223637Sbz 3433126258Smlaier r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 3434126258Smlaier 3435223637Sbz /* check packet for BINAT/NAT/RDR */ 3436223637Sbz if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, 3437223637Sbz &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) != NULL) { 3438223637Sbz if (nk == NULL || sk == NULL) { 3439223637Sbz REASON_SET(&reason, PFRES_MEMORY); 3440223637Sbz goto cleanup; 3441126258Smlaier } 3442223637Sbz 3443223637Sbz if (pd->ip_sum) 3444223637Sbz bip_sum = *pd->ip_sum; 3445223637Sbz 3446223637Sbz switch (pd->proto) { 3447223637Sbz case IPPROTO_TCP: 3448223637Sbz bproto_sum = th->th_sum; 3449223637Sbz pd->proto_sum = &th->th_sum; 3450223637Sbz 3451223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || 3452223637Sbz nk->port[pd->sidx] != sport) { 3453293896Sglebius pf_change_ap(m, saddr, &th->th_sport, pd->ip_sum, 3454223637Sbz &th->th_sum, &nk->addr[pd->sidx], 3455223637Sbz nk->port[pd->sidx], 0, af); 3456223637Sbz pd->sport = &th->th_sport; 3457223637Sbz sport = th->th_sport; 3458223637Sbz } 3459223637Sbz 3460223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || 3461223637Sbz nk->port[pd->didx] != dport) { 3462293896Sglebius pf_change_ap(m, daddr, &th->th_dport, pd->ip_sum, 3463223637Sbz &th->th_sum, &nk->addr[pd->didx], 3464223637Sbz nk->port[pd->didx], 0, af); 3465223637Sbz dport = th->th_dport; 3466223637Sbz pd->dport = &th->th_dport; 3467223637Sbz } 3468126258Smlaier rewrite++; 3469223637Sbz break; 3470223637Sbz case IPPROTO_UDP: 3471223637Sbz bproto_sum = pd->hdr.udp->uh_sum; 3472223637Sbz pd->proto_sum = &pd->hdr.udp->uh_sum; 3473223637Sbz 3474223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || 3475223637Sbz nk->port[pd->sidx] != sport) { 3476293896Sglebius pf_change_ap(m, saddr, &pd->hdr.udp->uh_sport, 3477223637Sbz pd->ip_sum, &pd->hdr.udp->uh_sum, 3478223637Sbz &nk->addr[pd->sidx], 3479223637Sbz nk->port[pd->sidx], 1, af); 3480223637Sbz sport = pd->hdr.udp->uh_sport; 3481223637Sbz pd->sport = &pd->hdr.udp->uh_sport; 3482223637Sbz } 3483223637Sbz 3484223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || 3485223637Sbz nk->port[pd->didx] != dport) { 3486293896Sglebius pf_change_ap(m, daddr, &pd->hdr.udp->uh_dport, 3487223637Sbz pd->ip_sum, &pd->hdr.udp->uh_sum, 3488223637Sbz &nk->addr[pd->didx], 3489223637Sbz nk->port[pd->didx], 1, af); 3490223637Sbz dport = pd->hdr.udp->uh_dport; 3491223637Sbz pd->dport = &pd->hdr.udp->uh_dport; 3492223637Sbz } 3493223637Sbz rewrite++; 3494223637Sbz break; 3495223637Sbz#ifdef INET 3496223637Sbz case IPPROTO_ICMP: 3497223637Sbz nk->port[0] = nk->port[1]; 3498223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) 3499223637Sbz pf_change_a(&saddr->v4.s_addr, pd->ip_sum, 3500223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 3501223637Sbz 3502223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET)) 3503223637Sbz pf_change_a(&daddr->v4.s_addr, pd->ip_sum, 3504223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 3505223637Sbz 3506223637Sbz if (nk->port[1] != pd->hdr.icmp->icmp_id) { 3507223637Sbz pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( 3508223637Sbz pd->hdr.icmp->icmp_cksum, sport, 3509223637Sbz nk->port[1], 0); 3510223637Sbz pd->hdr.icmp->icmp_id = nk->port[1]; 3511223637Sbz pd->sport = &pd->hdr.icmp->icmp_id; 3512223637Sbz } 3513223637Sbz m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); 3514223637Sbz break; 3515223637Sbz#endif /* INET */ 3516223637Sbz#ifdef INET6 3517223637Sbz case IPPROTO_ICMPV6: 3518223637Sbz nk->port[0] = nk->port[1]; 3519223637Sbz if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) 3520223637Sbz pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, 3521223637Sbz &nk->addr[pd->sidx], 0); 3522223637Sbz 3523223637Sbz if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) 3524223637Sbz pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, 3525223637Sbz &nk->addr[pd->didx], 0); 3526223637Sbz rewrite++; 3527223637Sbz break; 3528223637Sbz#endif /* INET */ 3529223637Sbz default: 3530223637Sbz switch (af) { 3531223637Sbz#ifdef INET 3532223637Sbz case AF_INET: 3533223637Sbz if (PF_ANEQ(saddr, 3534223637Sbz &nk->addr[pd->sidx], AF_INET)) 3535223637Sbz pf_change_a(&saddr->v4.s_addr, 3536223637Sbz pd->ip_sum, 3537223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 3538223637Sbz 3539223637Sbz if (PF_ANEQ(daddr, 3540223637Sbz &nk->addr[pd->didx], AF_INET)) 3541223637Sbz pf_change_a(&daddr->v4.s_addr, 3542223637Sbz pd->ip_sum, 3543223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 3544223637Sbz break; 3545223637Sbz#endif /* INET */ 3546223637Sbz#ifdef INET6 3547223637Sbz case AF_INET6: 3548223637Sbz if (PF_ANEQ(saddr, 3549223637Sbz &nk->addr[pd->sidx], AF_INET6)) 3550223637Sbz PF_ACPY(saddr, &nk->addr[pd->sidx], af); 3551223637Sbz 3552223637Sbz if (PF_ANEQ(daddr, 3553223637Sbz &nk->addr[pd->didx], AF_INET6)) 3554223637Sbz PF_ACPY(saddr, &nk->addr[pd->didx], af); 3555223637Sbz break; 3556223637Sbz#endif /* INET */ 3557223637Sbz } 3558223637Sbz break; 3559126258Smlaier } 3560223637Sbz if (nr->natpass) 3561223637Sbz r = NULL; 3562223637Sbz pd->nat_rule = nr; 3563126258Smlaier } 3564126258Smlaier 3565126258Smlaier while (r != NULL) { 3566126258Smlaier r->evaluations++; 3567171168Smlaier if (pfi_kif_match(r->kif, kif) == r->ifnot) 3568126258Smlaier r = r->skip[PF_SKIP_IFP].ptr; 3569126258Smlaier else if (r->direction && r->direction != direction) 3570126258Smlaier r = r->skip[PF_SKIP_DIR].ptr; 3571126258Smlaier else if (r->af && r->af != af) 3572126258Smlaier r = r->skip[PF_SKIP_AF].ptr; 3573223637Sbz else if (r->proto && r->proto != pd->proto) 3574126258Smlaier r = r->skip[PF_SKIP_PROTO].ptr; 3575171168Smlaier else if (PF_MISMATCHAW(&r->src.addr, saddr, af, 3576232292Sbz r->src.neg, kif, M_GETFIB(m))) 3577126258Smlaier r = r->skip[PF_SKIP_SRC_ADDR].ptr; 3578223637Sbz /* tcp/udp only. port_op always 0 in other cases */ 3579126258Smlaier else if (r->src.port_op && !pf_match_port(r->src.port_op, 3580223637Sbz r->src.port[0], r->src.port[1], sport)) 3581126258Smlaier r = r->skip[PF_SKIP_SRC_PORT].ptr; 3582171168Smlaier else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, 3583232292Sbz r->dst.neg, NULL, M_GETFIB(m))) 3584126258Smlaier r = r->skip[PF_SKIP_DST_ADDR].ptr; 3585223637Sbz /* tcp/udp only. port_op always 0 in other cases */ 3586126258Smlaier else if (r->dst.port_op && !pf_match_port(r->dst.port_op, 3587223637Sbz r->dst.port[0], r->dst.port[1], dport)) 3588126258Smlaier r = r->skip[PF_SKIP_DST_PORT].ptr; 3589223637Sbz /* icmp only. type always 0 in other cases */ 3590223637Sbz else if (r->type && r->type != icmptype + 1) 3591223637Sbz r = TAILQ_NEXT(r, entries); 3592223637Sbz /* icmp only. type always 0 in other cases */ 3593223637Sbz else if (r->code && r->code != icmpcode + 1) 3594223637Sbz r = TAILQ_NEXT(r, entries); 3595171168Smlaier else if (r->tos && !(r->tos == pd->tos)) 3596126258Smlaier r = TAILQ_NEXT(r, entries); 3597126258Smlaier else if (r->rule_flag & PFRULE_FRAGMENT) 3598126258Smlaier r = TAILQ_NEXT(r, entries); 3599223637Sbz else if (pd->proto == IPPROTO_TCP && 3600223637Sbz (r->flagset & th->th_flags) != r->flags) 3601126258Smlaier r = TAILQ_NEXT(r, entries); 3602223637Sbz /* tcp/udp only. uid.op always 0 in other cases */ 3603171168Smlaier else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = 3604135920Smlaier#ifdef __FreeBSD__ 3605171168Smlaier pf_socket_lookup(direction, pd, inp), 1)) && 3606135920Smlaier#else 3607171168Smlaier pf_socket_lookup(direction, pd), 1)) && 3608135920Smlaier#endif 3609126258Smlaier !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], 3610171168Smlaier pd->lookup.uid)) 3611126258Smlaier r = TAILQ_NEXT(r, entries); 3612223637Sbz /* tcp/udp only. gid.op always 0 in other cases */ 3613171168Smlaier else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = 3614135920Smlaier#ifdef __FreeBSD__ 3615171168Smlaier pf_socket_lookup(direction, pd, inp), 1)) && 3616135920Smlaier#else 3617171168Smlaier pf_socket_lookup(direction, pd), 1)) && 3618135920Smlaier#endif 3619126258Smlaier !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], 3620171168Smlaier pd->lookup.gid)) 3621126258Smlaier r = TAILQ_NEXT(r, entries); 3622223637Sbz else if (r->prob && 3623223637Sbz#ifdef __FreeBSD__ 3624223637Sbz r->prob <= arc4random()) 3625223637Sbz#else 3626223637Sbz r->prob <= arc4random_uniform(UINT_MAX - 1) + 1) 3627223637Sbz#endif 3628126258Smlaier r = TAILQ_NEXT(r, entries); 3629223637Sbz#ifdef __FreeBSD__ 3630223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) 3631223637Sbz#else 3632223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag)) 3633223637Sbz#endif 3634126258Smlaier r = TAILQ_NEXT(r, entries); 3635223637Sbz else if (r->os_fingerprint != PF_OSFP_ANY && 3636223637Sbz (pd->proto != IPPROTO_TCP || !pf_osfp_match( 3637223637Sbz pf_osfp_fingerprint(pd, m, off, th), 3638223637Sbz r->os_fingerprint))) 3639126258Smlaier r = TAILQ_NEXT(r, entries); 3640126258Smlaier else { 3641126258Smlaier if (r->tag) 3642126258Smlaier tag = r->tag; 3643171168Smlaier if (r->rtableid >= 0) 3644171168Smlaier rtableid = r->rtableid; 3645126258Smlaier if (r->anchor == NULL) { 3646171168Smlaier match = 1; 3647126258Smlaier *rm = r; 3648126258Smlaier *am = a; 3649126258Smlaier *rsm = ruleset; 3650126258Smlaier if ((*rm)->quick) 3651126258Smlaier break; 3652126258Smlaier r = TAILQ_NEXT(r, entries); 3653126258Smlaier } else 3654145836Smlaier pf_step_into_anchor(&asd, &ruleset, 3655171168Smlaier PF_RULESET_FILTER, &r, &a, &match); 3656126258Smlaier } 3657171168Smlaier if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, 3658171168Smlaier PF_RULESET_FILTER, &r, &a, &match)) 3659171168Smlaier break; 3660126258Smlaier } 3661126258Smlaier r = *rm; 3662126258Smlaier a = *am; 3663126258Smlaier ruleset = *rsm; 3664126258Smlaier 3665126258Smlaier REASON_SET(&reason, PFRES_MATCH); 3666126258Smlaier 3667223637Sbz if (r->log || (nr != NULL && nr->log)) { 3668126258Smlaier if (rewrite) 3669223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3670171168Smlaier PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, 3671171168Smlaier a, ruleset, pd); 3672126258Smlaier } 3673126258Smlaier 3674126258Smlaier if ((r->action == PF_DROP) && 3675126258Smlaier ((r->rule_flag & PFRULE_RETURNRST) || 3676126258Smlaier (r->rule_flag & PFRULE_RETURNICMP) || 3677126258Smlaier (r->rule_flag & PFRULE_RETURN))) { 3678126258Smlaier /* undo NAT changes, if they have taken place */ 3679130613Smlaier if (nr != NULL) { 3680223637Sbz PF_ACPY(saddr, &sk->addr[pd->sidx], af); 3681223637Sbz PF_ACPY(daddr, &sk->addr[pd->didx], af); 3682223637Sbz if (pd->sport) 3683223637Sbz *pd->sport = sk->port[pd->sidx]; 3684223637Sbz if (pd->dport) 3685223637Sbz *pd->dport = sk->port[pd->didx]; 3686223637Sbz if (pd->proto_sum) 3687223637Sbz *pd->proto_sum = bproto_sum; 3688223637Sbz if (pd->ip_sum) 3689223637Sbz *pd->ip_sum = bip_sum; 3690223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3691126258Smlaier } 3692223637Sbz if (pd->proto == IPPROTO_TCP && 3693223637Sbz ((r->rule_flag & PFRULE_RETURNRST) || 3694126258Smlaier (r->rule_flag & PFRULE_RETURN)) && 3695126258Smlaier !(th->th_flags & TH_RST)) { 3696223637Sbz u_int32_t ack = ntohl(th->th_seq) + pd->p_len; 3697223637Sbz int len = 0; 3698223637Sbz#ifdef INET 3699223637Sbz struct ip *h4; 3700223637Sbz#endif 3701223637Sbz#ifdef INET6 3702223637Sbz struct ip6_hdr *h6; 3703223637Sbz#endif 3704126258Smlaier 3705223637Sbz switch (af) { 3706223637Sbz#ifdef INET 3707223637Sbz case AF_INET: 3708223637Sbz h4 = mtod(m, struct ip *); 3709223637Sbz len = ntohs(h4->ip_len) - off; 3710223637Sbz break; 3711223637Sbz#endif 3712223637Sbz#ifdef INET6 3713223637Sbz case AF_INET6: 3714223637Sbz h6 = mtod(m, struct ip6_hdr *); 3715223637Sbz len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); 3716223637Sbz break; 3717223637Sbz#endif 3718223637Sbz } 3719223637Sbz 3720223637Sbz if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) 3721223637Sbz REASON_SET(&reason, PFRES_PROTCKSUM); 3722223637Sbz else { 3723223637Sbz if (th->th_flags & TH_SYN) 3724223637Sbz ack++; 3725223637Sbz if (th->th_flags & TH_FIN) 3726223637Sbz ack++; 3727162238Scsjp#ifdef __FreeBSD__ 3728223637Sbz pf_send_tcp(m, r, af, pd->dst, 3729162238Scsjp#else 3730223637Sbz pf_send_tcp(r, af, pd->dst, 3731162238Scsjp#endif 3732223637Sbz pd->src, th->th_dport, th->th_sport, 3733223637Sbz ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, 3734223637Sbz r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); 3735223637Sbz } 3736223637Sbz } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && 3737223637Sbz r->return_icmp) 3738126258Smlaier pf_send_icmp(m, r->return_icmp >> 8, 3739126258Smlaier r->return_icmp & 255, af, r); 3740223637Sbz else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && 3741223637Sbz r->return_icmp6) 3742126258Smlaier pf_send_icmp(m, r->return_icmp6 >> 8, 3743126258Smlaier r->return_icmp6 & 255, af, r); 3744126258Smlaier } 3745126258Smlaier 3746126258Smlaier if (r->action == PF_DROP) 3747223637Sbz goto cleanup; 3748126258Smlaier 3749223637Sbz#ifdef __FreeBSD__ 3750223637Sbz if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag)) { 3751223637Sbz#else 3752223637Sbz if (pf_tag_packet(m, tag, rtableid)) { 3753223637Sbz#endif 3754126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 3755223637Sbz goto cleanup; 3756126258Smlaier } 3757126258Smlaier 3758223637Sbz if (!state_icmp && (r->keep_state || nr != NULL || 3759223637Sbz (pd->flags & PFDESC_TCP_NORM))) { 3760223637Sbz int action; 3761223637Sbz action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m, 3762223637Sbz off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, 3763223637Sbz bip_sum, hdrlen); 3764223637Sbz if (action != PF_PASS) 3765223637Sbz return (action); 3766223637Sbz } else { 3767223637Sbz#ifdef __FreeBSD__ 3768223637Sbz if (sk != NULL) 3769223637Sbz pool_put(&V_pf_state_key_pl, sk); 3770223637Sbz if (nk != NULL) 3771223637Sbz pool_put(&V_pf_state_key_pl, nk); 3772223637Sbz#else 3773223637Sbz if (sk != NULL) 3774223637Sbz pool_put(&pf_state_key_pl, sk); 3775223637Sbz if (nk != NULL) 3776223637Sbz pool_put(&pf_state_key_pl, nk); 3777223637Sbz#endif 3778223637Sbz } 3779126258Smlaier 3780223637Sbz /* copy back packet headers if we performed NAT operations */ 3781223637Sbz if (rewrite) 3782223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 3783130613Smlaier 3784223637Sbz#if NPFSYNC > 0 3785223637Sbz if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) && 3786223637Sbz#ifdef __FreeBSD__ 3787223637Sbz direction == PF_OUT && pfsync_up_ptr != NULL && pfsync_up_ptr()) { 3788223637Sbz#else 3789223637Sbz direction == PF_OUT && pfsync_up()) { 3790223637Sbz#endif 3791223637Sbz /* 3792223637Sbz * We want the state created, but we dont 3793223637Sbz * want to send this in case a partner 3794223637Sbz * firewall has to know about it to allow 3795223637Sbz * replies through it. 3796223637Sbz */ 3797223637Sbz#ifdef __FreeBSD__ 3798228182Sglebius if (pfsync_defer_ptr != NULL && 3799228182Sglebius pfsync_defer_ptr(*sm, m)) 3800223637Sbz#else 3801223637Sbz if (pfsync_defer(*sm, m)) 3802223637Sbz#endif 3803223637Sbz return (PF_DEFER); 3804223637Sbz } 3805223637Sbz#endif 3806223637Sbz 3807223637Sbz return (PF_PASS); 3808223637Sbz 3809130613Smlaiercleanup: 3810223637Sbz#ifdef __FreeBSD__ 3811223637Sbz if (sk != NULL) 3812223637Sbz pool_put(&V_pf_state_key_pl, sk); 3813223637Sbz if (nk != NULL) 3814223637Sbz pool_put(&V_pf_state_key_pl, nk); 3815223637Sbz#else 3816223637Sbz if (sk != NULL) 3817223637Sbz pool_put(&pf_state_key_pl, sk); 3818223637Sbz if (nk != NULL) 3819223637Sbz pool_put(&pf_state_key_pl, nk); 3820223637Sbz#endif 3821223637Sbz return (PF_DROP); 3822223637Sbz} 3823126258Smlaier 3824223637Sbzstatic __inline int 3825223637Sbzpf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, 3826223637Sbz struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw, 3827223637Sbz struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk, 3828223637Sbz struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite, 3829223637Sbz struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum, 3830223637Sbz u_int16_t bip_sum, int hdrlen) 3831223637Sbz{ 3832223637Sbz struct pf_state *s = NULL; 3833223637Sbz struct pf_src_node *sn = NULL; 3834223637Sbz struct tcphdr *th = pd->hdr.tcp; 3835223637Sbz#ifdef __FreeBSD__ 3836223637Sbz u_int16_t mss = V_tcp_mssdflt; 3837223637Sbz#else 3838223637Sbz u_int16_t mss = tcp_mssdflt; 3839223637Sbz#endif 3840223637Sbz u_short reason; 3841223637Sbz 3842223637Sbz /* check maximums */ 3843223637Sbz if (r->max_states && (r->states_cur >= r->max_states)) { 3844223637Sbz#ifdef __FreeBSD__ 3845223637Sbz V_pf_status.lcounters[LCNT_STATES]++; 3846223637Sbz#else 3847223637Sbz pf_status.lcounters[LCNT_STATES]++; 3848223637Sbz#endif 3849223637Sbz REASON_SET(&reason, PFRES_MAXSTATES); 3850223637Sbz return (PF_DROP); 3851223637Sbz } 3852223637Sbz /* src node for filter rule */ 3853223637Sbz if ((r->rule_flag & PFRULE_SRCTRACK || 3854223637Sbz r->rpool.opts & PF_POOL_STICKYADDR) && 3855223637Sbz pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) { 3856223637Sbz REASON_SET(&reason, PFRES_SRCLIMIT); 3857223637Sbz goto csfailed; 3858223637Sbz } 3859223637Sbz /* src node for translation rule */ 3860223637Sbz if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && 3861223637Sbz pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) { 3862223637Sbz REASON_SET(&reason, PFRES_SRCLIMIT); 3863223637Sbz goto csfailed; 3864223637Sbz } 3865223637Sbz#ifdef __FreeBSD__ 3866223637Sbz s = pool_get(&V_pf_state_pl, PR_NOWAIT | PR_ZERO); 3867223637Sbz#else 3868223637Sbz s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO); 3869223637Sbz#endif 3870223637Sbz if (s == NULL) { 3871223637Sbz REASON_SET(&reason, PFRES_MEMORY); 3872223637Sbz goto csfailed; 3873223637Sbz } 3874223637Sbz s->rule.ptr = r; 3875223637Sbz s->nat_rule.ptr = nr; 3876223637Sbz s->anchor.ptr = a; 3877223637Sbz STATE_INC_COUNTERS(s); 3878223637Sbz if (r->allow_opts) 3879223637Sbz s->state_flags |= PFSTATE_ALLOWOPTS; 3880223637Sbz if (r->rule_flag & PFRULE_STATESLOPPY) 3881223637Sbz s->state_flags |= PFSTATE_SLOPPY; 3882223637Sbz if (r->rule_flag & PFRULE_PFLOW) 3883223637Sbz s->state_flags |= PFSTATE_PFLOW; 3884223637Sbz s->log = r->log & PF_LOG_ALL; 3885223637Sbz s->sync_state = PFSYNC_S_NONE; 3886223637Sbz if (nr != NULL) 3887223637Sbz s->log |= nr->log & PF_LOG_ALL; 3888223637Sbz switch (pd->proto) { 3889223637Sbz case IPPROTO_TCP: 3890126258Smlaier s->src.seqlo = ntohl(th->th_seq); 3891223637Sbz s->src.seqhi = s->src.seqlo + pd->p_len + 1; 3892126258Smlaier if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && 3893126258Smlaier r->keep_state == PF_STATE_MODULATE) { 3894126258Smlaier /* Generate sequence number modulator */ 3895223637Sbz if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) == 3896223637Sbz 0) 3897223637Sbz s->src.seqdiff = 1; 3898293896Sglebius pf_change_proto_a(m, &th->th_seq, &th->th_sum, 3899126258Smlaier htonl(s->src.seqlo + s->src.seqdiff), 0); 3900223637Sbz *rewrite = 1; 3901126258Smlaier } else 3902126258Smlaier s->src.seqdiff = 0; 3903126258Smlaier if (th->th_flags & TH_SYN) { 3904126258Smlaier s->src.seqhi++; 3905223637Sbz s->src.wscale = pf_get_wscale(m, off, 3906223637Sbz th->th_off, pd->af); 3907126258Smlaier } 3908126258Smlaier s->src.max_win = MAX(ntohs(th->th_win), 1); 3909126258Smlaier if (s->src.wscale & PF_WSCALE_MASK) { 3910126258Smlaier /* Remove scale factor from initial window */ 3911126258Smlaier int win = s->src.max_win; 3912126258Smlaier win += 1 << (s->src.wscale & PF_WSCALE_MASK); 3913126258Smlaier s->src.max_win = (win - 1) >> 3914126258Smlaier (s->src.wscale & PF_WSCALE_MASK); 3915126258Smlaier } 3916126258Smlaier if (th->th_flags & TH_FIN) 3917126258Smlaier s->src.seqhi++; 3918126258Smlaier s->dst.seqhi = 1; 3919126258Smlaier s->dst.max_win = 1; 3920126258Smlaier s->src.state = TCPS_SYN_SENT; 3921126258Smlaier s->dst.state = TCPS_CLOSED; 3922126258Smlaier s->timeout = PFTM_TCP_FIRST_PACKET; 3923223637Sbz break; 3924223637Sbz case IPPROTO_UDP: 3925223637Sbz s->src.state = PFUDPS_SINGLE; 3926223637Sbz s->dst.state = PFUDPS_NO_TRAFFIC; 3927223637Sbz s->timeout = PFTM_UDP_FIRST_PACKET; 3928223637Sbz break; 3929223637Sbz case IPPROTO_ICMP: 3930223637Sbz#ifdef INET6 3931223637Sbz case IPPROTO_ICMPV6: 3932223637Sbz#endif 3933223637Sbz s->timeout = PFTM_ICMP_FIRST_PACKET; 3934223637Sbz break; 3935223637Sbz default: 3936223637Sbz s->src.state = PFOTHERS_SINGLE; 3937223637Sbz s->dst.state = PFOTHERS_NO_TRAFFIC; 3938223637Sbz s->timeout = PFTM_OTHER_FIRST_PACKET; 3939223637Sbz } 3940223637Sbz 3941223637Sbz s->creation = time_second; 3942223637Sbz s->expire = time_second; 3943223637Sbz 3944223637Sbz if (sn != NULL) { 3945223637Sbz s->src_node = sn; 3946223637Sbz s->src_node->states++; 3947223637Sbz } 3948223637Sbz if (nsn != NULL) { 3949223637Sbz /* XXX We only modify one side for now. */ 3950223637Sbz PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); 3951223637Sbz s->nat_src_node = nsn; 3952223637Sbz s->nat_src_node->states++; 3953223637Sbz } 3954223637Sbz if (pd->proto == IPPROTO_TCP) { 3955126258Smlaier if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, 3956126258Smlaier off, pd, th, &s->src, &s->dst)) { 3957126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 3958130613Smlaier pf_src_tree_remove_state(s); 3959145836Smlaier STATE_DEC_COUNTERS(s); 3960223637Sbz#ifdef __FreeBSD__ 3961223637Sbz pool_put(&V_pf_state_pl, s); 3962223637Sbz#else 3963126258Smlaier pool_put(&pf_state_pl, s); 3964223637Sbz#endif 3965126258Smlaier return (PF_DROP); 3966126258Smlaier } 3967126258Smlaier if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub && 3968145836Smlaier pf_normalize_tcp_stateful(m, off, pd, &reason, th, s, 3969223637Sbz &s->src, &s->dst, rewrite)) { 3970145836Smlaier /* This really shouldn't happen!!! */ 3971145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 3972145836Smlaier ("pf_normalize_tcp_stateful failed on first pkt")); 3973126258Smlaier pf_normalize_tcp_cleanup(s); 3974130613Smlaier pf_src_tree_remove_state(s); 3975145836Smlaier STATE_DEC_COUNTERS(s); 3976162238Scsjp#ifdef __FreeBSD__ 3977223637Sbz pool_put(&V_pf_state_pl, s); 3978162238Scsjp#else 3979223637Sbz pool_put(&pf_state_pl, s); 3980162238Scsjp#endif 3981223637Sbz return (PF_DROP); 3982126258Smlaier } 3983126258Smlaier } 3984223637Sbz s->direction = pd->dir; 3985126258Smlaier 3986223637Sbz if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk, 3987223637Sbz pd->src, pd->dst, sport, dport)) 3988223637Sbz goto csfailed; 3989126258Smlaier 3990223637Sbz if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) { 3991223637Sbz if (pd->proto == IPPROTO_TCP) 3992223637Sbz pf_normalize_tcp_cleanup(s); 3993223637Sbz REASON_SET(&reason, PFRES_STATEINS); 3994223637Sbz pf_src_tree_remove_state(s); 3995223637Sbz STATE_DEC_COUNTERS(s); 3996135920Smlaier#ifdef __FreeBSD__ 3997223637Sbz pool_put(&V_pf_state_pl, s); 3998135920Smlaier#else 3999223637Sbz pool_put(&pf_state_pl, s); 4000135920Smlaier#endif 4001223637Sbz return (PF_DROP); 4002223637Sbz } else 4003223637Sbz *sm = s; 4004126258Smlaier 4005223637Sbz pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */ 4006223637Sbz if (tag > 0) { 4007223637Sbz pf_tag_ref(tag); 4008223637Sbz s->tag = tag; 4009145836Smlaier } 4010223637Sbz if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == 4011223637Sbz TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { 4012223637Sbz s->src.state = PF_TCPS_PROXY_SRC; 4013223637Sbz /* undo NAT changes, if they have taken place */ 4014223637Sbz if (nr != NULL) { 4015223637Sbz struct pf_state_key *skt = s->key[PF_SK_WIRE]; 4016223637Sbz if (pd->dir == PF_OUT) 4017223637Sbz skt = s->key[PF_SK_STACK]; 4018223637Sbz PF_ACPY(pd->src, &skt->addr[pd->sidx], pd->af); 4019223637Sbz PF_ACPY(pd->dst, &skt->addr[pd->didx], pd->af); 4020223637Sbz if (pd->sport) 4021223637Sbz *pd->sport = skt->port[pd->sidx]; 4022223637Sbz if (pd->dport) 4023223637Sbz *pd->dport = skt->port[pd->didx]; 4024223637Sbz if (pd->proto_sum) 4025223637Sbz *pd->proto_sum = bproto_sum; 4026223637Sbz if (pd->ip_sum) 4027223637Sbz *pd->ip_sum = bip_sum; 4028223637Sbz m_copyback(m, off, hdrlen, pd->hdr.any); 4029223637Sbz } 4030223637Sbz s->src.seqhi = htonl(arc4random()); 4031223637Sbz /* Find mss option */ 4032232292Sbz int rtid = M_GETFIB(m); 4033223637Sbz mss = pf_get_mss(m, off, th->th_off, pd->af); 4034232292Sbz mss = pf_calc_mss(pd->src, pd->af, rtid, mss); 4035232292Sbz mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); 4036223637Sbz s->src.mss = mss; 4037171168Smlaier#ifdef __FreeBSD__ 4038223637Sbz pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport, 4039223637Sbz#else 4040223637Sbz pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, 4041223637Sbz#endif 4042223637Sbz th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, 4043223637Sbz TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); 4044223637Sbz REASON_SET(&reason, PFRES_SYNPROXY); 4045223637Sbz return (PF_SYNPROXY_DROP); 4046171168Smlaier } 4047165631Smlaier 4048223637Sbz return (PF_PASS); 4049126258Smlaier 4050223637Sbzcsfailed: 4051135920Smlaier#ifdef __FreeBSD__ 4052223637Sbz if (sk != NULL) 4053223637Sbz pool_put(&V_pf_state_key_pl, sk); 4054223637Sbz if (nk != NULL) 4055223637Sbz pool_put(&V_pf_state_key_pl, nk); 4056135920Smlaier#else 4057223637Sbz if (sk != NULL) 4058223637Sbz pool_put(&pf_state_key_pl, sk); 4059223637Sbz if (nk != NULL) 4060223637Sbz pool_put(&pf_state_key_pl, nk); 4061135920Smlaier#endif 4062223637Sbz 4063223637Sbz if (sn != NULL && sn->states == 0 && sn->expire == 0) { 4064135920Smlaier#ifdef __FreeBSD__ 4065223637Sbz RB_REMOVE(pf_src_tree, &V_tree_src_tracking, sn); 4066223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4067223637Sbz V_pf_status.src_nodes--; 4068223637Sbz pool_put(&V_pf_src_tree_pl, sn); 4069135920Smlaier#else 4070223637Sbz RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); 4071223637Sbz pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4072223637Sbz pf_status.src_nodes--; 4073223637Sbz pool_put(&pf_src_tree_pl, sn); 4074135920Smlaier#endif 4075126258Smlaier } 4076223637Sbz if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { 4077171168Smlaier#ifdef __FreeBSD__ 4078223637Sbz RB_REMOVE(pf_src_tree, &V_tree_src_tracking, nsn); 4079223637Sbz V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4080223637Sbz V_pf_status.src_nodes--; 4081223637Sbz pool_put(&V_pf_src_tree_pl, nsn); 4082171168Smlaier#else 4083223637Sbz RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); 4084223637Sbz pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; 4085223637Sbz pf_status.src_nodes--; 4086223637Sbz pool_put(&pf_src_tree_pl, nsn); 4087171168Smlaier#endif 4088126258Smlaier } 4089223637Sbz return (PF_DROP); 4090126258Smlaier} 4091126258Smlaier 4092126258Smlaierint 4093130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, 4094126258Smlaier struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, 4095126258Smlaier struct pf_ruleset **rsm) 4096126258Smlaier{ 4097126258Smlaier struct pf_rule *r, *a = NULL; 4098126258Smlaier struct pf_ruleset *ruleset = NULL; 4099126258Smlaier sa_family_t af = pd->af; 4100126258Smlaier u_short reason; 4101126258Smlaier int tag = -1; 4102145836Smlaier int asd = 0; 4103171168Smlaier int match = 0; 4104126258Smlaier 4105126258Smlaier r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); 4106126258Smlaier while (r != NULL) { 4107126258Smlaier r->evaluations++; 4108171168Smlaier if (pfi_kif_match(r->kif, kif) == r->ifnot) 4109126258Smlaier r = r->skip[PF_SKIP_IFP].ptr; 4110126258Smlaier else if (r->direction && r->direction != direction) 4111126258Smlaier r = r->skip[PF_SKIP_DIR].ptr; 4112126258Smlaier else if (r->af && r->af != af) 4113126258Smlaier r = r->skip[PF_SKIP_AF].ptr; 4114126258Smlaier else if (r->proto && r->proto != pd->proto) 4115126258Smlaier r = r->skip[PF_SKIP_PROTO].ptr; 4116171168Smlaier else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, 4117232292Sbz r->src.neg, kif, M_GETFIB(m))) 4118126258Smlaier r = r->skip[PF_SKIP_SRC_ADDR].ptr; 4119171168Smlaier else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, 4120232292Sbz r->dst.neg, NULL, M_GETFIB(m))) 4121126258Smlaier r = r->skip[PF_SKIP_DST_ADDR].ptr; 4122171168Smlaier else if (r->tos && !(r->tos == pd->tos)) 4123126258Smlaier r = TAILQ_NEXT(r, entries); 4124173815Smlaier else if (r->os_fingerprint != PF_OSFP_ANY) 4125126258Smlaier r = TAILQ_NEXT(r, entries); 4126173815Smlaier else if (pd->proto == IPPROTO_UDP && 4127173815Smlaier (r->src.port_op || r->dst.port_op)) 4128173815Smlaier r = TAILQ_NEXT(r, entries); 4129173815Smlaier else if (pd->proto == IPPROTO_TCP && 4130173815Smlaier (r->src.port_op || r->dst.port_op || r->flagset)) 4131173815Smlaier r = TAILQ_NEXT(r, entries); 4132173815Smlaier else if ((pd->proto == IPPROTO_ICMP || 4133173815Smlaier pd->proto == IPPROTO_ICMPV6) && 4134173815Smlaier (r->type || r->code)) 4135173815Smlaier r = TAILQ_NEXT(r, entries); 4136223637Sbz else if (r->prob && r->prob <= 4137223637Sbz (arc4random() % (UINT_MAX - 1) + 1)) 4138126258Smlaier r = TAILQ_NEXT(r, entries); 4139223637Sbz#ifdef __FreeBSD__ 4140223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) 4141223637Sbz#else 4142223637Sbz else if (r->match_tag && !pf_match_tag(m, r, &tag)) 4143223637Sbz#endif 4144126258Smlaier r = TAILQ_NEXT(r, entries); 4145126258Smlaier else { 4146126258Smlaier if (r->anchor == NULL) { 4147171168Smlaier match = 1; 4148126258Smlaier *rm = r; 4149126258Smlaier *am = a; 4150126258Smlaier *rsm = ruleset; 4151126258Smlaier if ((*rm)->quick) 4152126258Smlaier break; 4153126258Smlaier r = TAILQ_NEXT(r, entries); 4154126258Smlaier } else 4155145836Smlaier pf_step_into_anchor(&asd, &ruleset, 4156171168Smlaier PF_RULESET_FILTER, &r, &a, &match); 4157126258Smlaier } 4158171168Smlaier if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, 4159171168Smlaier PF_RULESET_FILTER, &r, &a, &match)) 4160171168Smlaier break; 4161126258Smlaier } 4162126258Smlaier r = *rm; 4163126258Smlaier a = *am; 4164126258Smlaier ruleset = *rsm; 4165126258Smlaier 4166126258Smlaier REASON_SET(&reason, PFRES_MATCH); 4167130613Smlaier 4168126258Smlaier if (r->log) 4169171168Smlaier PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset, 4170171168Smlaier pd); 4171126258Smlaier 4172126258Smlaier if (r->action != PF_PASS) 4173126258Smlaier return (PF_DROP); 4174126258Smlaier 4175223637Sbz#ifdef __FreeBSD__ 4176223637Sbz if (pf_tag_packet(m, tag, -1, pd->pf_mtag)) { 4177223637Sbz#else 4178223637Sbz if (pf_tag_packet(m, tag, -1)) { 4179223637Sbz#endif 4180126258Smlaier REASON_SET(&reason, PFRES_MEMORY); 4181126258Smlaier return (PF_DROP); 4182126258Smlaier } 4183126258Smlaier 4184126258Smlaier return (PF_PASS); 4185126258Smlaier} 4186126258Smlaier 4187126258Smlaierint 4188200930Sdelphijpf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, 4189200930Sdelphij struct pf_state **state, struct pfi_kif *kif, struct mbuf *m, int off, 4190200930Sdelphij struct pf_pdesc *pd, u_short *reason, int *copyback) 4191126258Smlaier{ 4192223637Sbz struct tcphdr *th = pd->hdr.tcp; 4193223637Sbz u_int16_t win = ntohs(th->th_win); 4194223637Sbz u_int32_t ack, end, seq, orig_seq; 4195223637Sbz u_int8_t sws, dws; 4196223637Sbz int ackskew; 4197126258Smlaier 4198126258Smlaier if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) { 4199126258Smlaier sws = src->wscale & PF_WSCALE_MASK; 4200126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 4201126258Smlaier } else 4202126258Smlaier sws = dws = 0; 4203126258Smlaier 4204126258Smlaier /* 4205126258Smlaier * Sequence tracking algorithm from Guido van Rooij's paper: 4206126258Smlaier * http://www.madison-gurkha.com/publications/tcp_filtering/ 4207126258Smlaier * tcp_filtering.ps 4208126258Smlaier */ 4209126258Smlaier 4210145836Smlaier orig_seq = seq = ntohl(th->th_seq); 4211126258Smlaier if (src->seqlo == 0) { 4212126258Smlaier /* First packet from this end. Set its state */ 4213126258Smlaier 4214126258Smlaier if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) && 4215126258Smlaier src->scrub == NULL) { 4216126258Smlaier if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) { 4217126258Smlaier REASON_SET(reason, PFRES_MEMORY); 4218126258Smlaier return (PF_DROP); 4219126258Smlaier } 4220126258Smlaier } 4221126258Smlaier 4222126258Smlaier /* Deferred generation of sequence number modulator */ 4223126258Smlaier if (dst->seqdiff && !src->seqdiff) { 4224223637Sbz /* use random iss for the TCP server */ 4225223637Sbz while ((src->seqdiff = arc4random() - seq) == 0) 4226126258Smlaier ; 4227126258Smlaier ack = ntohl(th->th_ack) - dst->seqdiff; 4228293896Sglebius pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq + 4229126258Smlaier src->seqdiff), 0); 4230293896Sglebius pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0); 4231200930Sdelphij *copyback = 1; 4232126258Smlaier } else { 4233126258Smlaier ack = ntohl(th->th_ack); 4234126258Smlaier } 4235126258Smlaier 4236126258Smlaier end = seq + pd->p_len; 4237126258Smlaier if (th->th_flags & TH_SYN) { 4238126258Smlaier end++; 4239126258Smlaier if (dst->wscale & PF_WSCALE_FLAG) { 4240126258Smlaier src->wscale = pf_get_wscale(m, off, th->th_off, 4241126258Smlaier pd->af); 4242126258Smlaier if (src->wscale & PF_WSCALE_FLAG) { 4243126258Smlaier /* Remove scale factor from initial 4244126258Smlaier * window */ 4245126258Smlaier sws = src->wscale & PF_WSCALE_MASK; 4246126258Smlaier win = ((u_int32_t)win + (1 << sws) - 1) 4247126258Smlaier >> sws; 4248126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 4249126258Smlaier } else { 4250126258Smlaier /* fixup other window */ 4251126258Smlaier dst->max_win <<= dst->wscale & 4252126258Smlaier PF_WSCALE_MASK; 4253126258Smlaier /* in case of a retrans SYN|ACK */ 4254126258Smlaier dst->wscale = 0; 4255126258Smlaier } 4256126258Smlaier } 4257126258Smlaier } 4258126258Smlaier if (th->th_flags & TH_FIN) 4259126258Smlaier end++; 4260126258Smlaier 4261126258Smlaier src->seqlo = seq; 4262126258Smlaier if (src->state < TCPS_SYN_SENT) 4263126258Smlaier src->state = TCPS_SYN_SENT; 4264126258Smlaier 4265126258Smlaier /* 4266126258Smlaier * May need to slide the window (seqhi may have been set by 4267126258Smlaier * the crappy stack check or if we picked up the connection 4268126258Smlaier * after establishment) 4269126258Smlaier */ 4270126258Smlaier if (src->seqhi == 1 || 4271126258Smlaier SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi)) 4272126258Smlaier src->seqhi = end + MAX(1, dst->max_win << dws); 4273126258Smlaier if (win > src->max_win) 4274126258Smlaier src->max_win = win; 4275126258Smlaier 4276126258Smlaier } else { 4277126258Smlaier ack = ntohl(th->th_ack) - dst->seqdiff; 4278126258Smlaier if (src->seqdiff) { 4279126258Smlaier /* Modulate sequence numbers */ 4280293896Sglebius pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq + 4281126258Smlaier src->seqdiff), 0); 4282293896Sglebius pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0); 4283200930Sdelphij *copyback = 1; 4284126258Smlaier } 4285126258Smlaier end = seq + pd->p_len; 4286126258Smlaier if (th->th_flags & TH_SYN) 4287126258Smlaier end++; 4288126258Smlaier if (th->th_flags & TH_FIN) 4289126258Smlaier end++; 4290126258Smlaier } 4291126258Smlaier 4292126258Smlaier if ((th->th_flags & TH_ACK) == 0) { 4293126258Smlaier /* Let it pass through the ack skew check */ 4294126258Smlaier ack = dst->seqlo; 4295126258Smlaier } else if ((ack == 0 && 4296126258Smlaier (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) || 4297126258Smlaier /* broken tcp stacks do not set ack */ 4298126258Smlaier (dst->state < TCPS_SYN_SENT)) { 4299126258Smlaier /* 4300126258Smlaier * Many stacks (ours included) will set the ACK number in an 4301126258Smlaier * FIN|ACK if the SYN times out -- no sequence to ACK. 4302126258Smlaier */ 4303126258Smlaier ack = dst->seqlo; 4304126258Smlaier } 4305126258Smlaier 4306126258Smlaier if (seq == end) { 4307126258Smlaier /* Ease sequencing restrictions on no data packets */ 4308126258Smlaier seq = src->seqlo; 4309126258Smlaier end = seq; 4310126258Smlaier } 4311126258Smlaier 4312126258Smlaier ackskew = dst->seqlo - ack; 4313126258Smlaier 4314171168Smlaier 4315171168Smlaier /* 4316171168Smlaier * Need to demodulate the sequence numbers in any TCP SACK options 4317171168Smlaier * (Selective ACK). We could optionally validate the SACK values 4318171168Smlaier * against the current ACK window, either forwards or backwards, but 4319171168Smlaier * I'm not confident that SACK has been implemented properly 4320171168Smlaier * everywhere. It wouldn't surprise me if several stacks accidently 4321171168Smlaier * SACK too far backwards of previously ACKed data. There really aren't 4322171168Smlaier * any security implications of bad SACKing unless the target stack 4323171168Smlaier * doesn't validate the option length correctly. Someone trying to 4324171168Smlaier * spoof into a TCP connection won't bother blindly sending SACK 4325171168Smlaier * options anyway. 4326171168Smlaier */ 4327171168Smlaier if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) { 4328171168Smlaier if (pf_modulate_sack(m, off, pd, th, dst)) 4329200930Sdelphij *copyback = 1; 4330171168Smlaier } 4331171168Smlaier 4332171168Smlaier 4333223637Sbz#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ 4334126258Smlaier if (SEQ_GEQ(src->seqhi, end) && 4335126258Smlaier /* Last octet inside other's window space */ 4336126258Smlaier SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) && 4337126258Smlaier /* Retrans: not more than one window back */ 4338126258Smlaier (ackskew >= -MAXACKWINDOW) && 4339126258Smlaier /* Acking not more than one reassembled fragment backwards */ 4340145836Smlaier (ackskew <= (MAXACKWINDOW << sws)) && 4341126258Smlaier /* Acking not more than one window forward */ 4342145836Smlaier ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo || 4343223637Sbz (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo) || 4344223637Sbz (pd->flags & PFDESC_IP_REAS) == 0)) { 4345171168Smlaier /* Require an exact/+1 sequence match on resets when possible */ 4346126258Smlaier 4347145836Smlaier if (dst->scrub || src->scrub) { 4348145836Smlaier if (pf_normalize_tcp_stateful(m, off, pd, reason, th, 4349200930Sdelphij *state, src, dst, copyback)) 4350145836Smlaier return (PF_DROP); 4351145836Smlaier } 4352145836Smlaier 4353126258Smlaier /* update max window */ 4354126258Smlaier if (src->max_win < win) 4355126258Smlaier src->max_win = win; 4356126258Smlaier /* synchronize sequencing */ 4357126258Smlaier if (SEQ_GT(end, src->seqlo)) 4358126258Smlaier src->seqlo = end; 4359126258Smlaier /* slide the window of what the other end can send */ 4360126258Smlaier if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) 4361126258Smlaier dst->seqhi = ack + MAX((win << sws), 1); 4362126258Smlaier 4363126258Smlaier 4364126258Smlaier /* update states */ 4365126258Smlaier if (th->th_flags & TH_SYN) 4366126258Smlaier if (src->state < TCPS_SYN_SENT) 4367126258Smlaier src->state = TCPS_SYN_SENT; 4368126258Smlaier if (th->th_flags & TH_FIN) 4369126258Smlaier if (src->state < TCPS_CLOSING) 4370126258Smlaier src->state = TCPS_CLOSING; 4371126258Smlaier if (th->th_flags & TH_ACK) { 4372145836Smlaier if (dst->state == TCPS_SYN_SENT) { 4373126258Smlaier dst->state = TCPS_ESTABLISHED; 4374145836Smlaier if (src->state == TCPS_ESTABLISHED && 4375145836Smlaier (*state)->src_node != NULL && 4376145836Smlaier pf_src_connlimit(state)) { 4377145836Smlaier REASON_SET(reason, PFRES_SRCLIMIT); 4378145836Smlaier return (PF_DROP); 4379145836Smlaier } 4380145836Smlaier } else if (dst->state == TCPS_CLOSING) 4381126258Smlaier dst->state = TCPS_FIN_WAIT_2; 4382126258Smlaier } 4383126258Smlaier if (th->th_flags & TH_RST) 4384126258Smlaier src->state = dst->state = TCPS_TIME_WAIT; 4385126258Smlaier 4386126258Smlaier /* update expire time */ 4387126261Smlaier (*state)->expire = time_second; 4388126258Smlaier if (src->state >= TCPS_FIN_WAIT_2 && 4389126258Smlaier dst->state >= TCPS_FIN_WAIT_2) 4390126258Smlaier (*state)->timeout = PFTM_TCP_CLOSED; 4391171168Smlaier else if (src->state >= TCPS_CLOSING && 4392171168Smlaier dst->state >= TCPS_CLOSING) 4393126258Smlaier (*state)->timeout = PFTM_TCP_FIN_WAIT; 4394126258Smlaier else if (src->state < TCPS_ESTABLISHED || 4395126258Smlaier dst->state < TCPS_ESTABLISHED) 4396126258Smlaier (*state)->timeout = PFTM_TCP_OPENING; 4397126258Smlaier else if (src->state >= TCPS_CLOSING || 4398126258Smlaier dst->state >= TCPS_CLOSING) 4399126258Smlaier (*state)->timeout = PFTM_TCP_CLOSING; 4400126258Smlaier else 4401126258Smlaier (*state)->timeout = PFTM_TCP_ESTABLISHED; 4402126258Smlaier 4403126258Smlaier /* Fall through to PASS packet */ 4404126258Smlaier 4405126258Smlaier } else if ((dst->state < TCPS_SYN_SENT || 4406126258Smlaier dst->state >= TCPS_FIN_WAIT_2 || 4407126258Smlaier src->state >= TCPS_FIN_WAIT_2) && 4408126258Smlaier SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) && 4409126258Smlaier /* Within a window forward of the originating packet */ 4410126258Smlaier SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) { 4411126258Smlaier /* Within a window backward of the originating packet */ 4412126258Smlaier 4413126258Smlaier /* 4414126258Smlaier * This currently handles three situations: 4415126258Smlaier * 1) Stupid stacks will shotgun SYNs before their peer 4416126258Smlaier * replies. 4417126258Smlaier * 2) When PF catches an already established stream (the 4418126258Smlaier * firewall rebooted, the state table was flushed, routes 4419126258Smlaier * changed...) 4420126258Smlaier * 3) Packets get funky immediately after the connection 4421126258Smlaier * closes (this should catch Solaris spurious ACK|FINs 4422126258Smlaier * that web servers like to spew after a close) 4423126258Smlaier * 4424126258Smlaier * This must be a little more careful than the above code 4425126258Smlaier * since packet floods will also be caught here. We don't 4426126258Smlaier * update the TTL here to mitigate the damage of a packet 4427126258Smlaier * flood and so the same code can handle awkward establishment 4428126258Smlaier * and a loosened connection close. 4429126258Smlaier * In the establishment case, a correct peer response will 4430126258Smlaier * validate the connection, go through the normal state code 4431126258Smlaier * and keep updating the state TTL. 4432126258Smlaier */ 4433126258Smlaier 4434223637Sbz#ifdef __FreeBSD__ 4435223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 4436223637Sbz#else 4437126258Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 4438223637Sbz#endif 4439126258Smlaier printf("pf: loose state match: "); 4440126258Smlaier pf_print_state(*state); 4441126258Smlaier pf_print_flags(th->th_flags); 4442171168Smlaier printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " 4443223637Sbz "pkts=%llu:%llu dir=%s,%s\n", seq, orig_seq, ack, 4444171168Smlaier#ifdef __FreeBSD__ 4445223637Sbz pd->p_len, ackskew, (unsigned long long)(*state)->packets[0], 4446223637Sbz (unsigned long long)(*state)->packets[1], 4447171168Smlaier#else 4448223637Sbz pd->p_len, ackskew, (*state)->packets[0], 4449223637Sbz (*state)->packets[1], 4450171168Smlaier#endif 4451223637Sbz pd->dir == PF_IN ? "in" : "out", 4452223637Sbz pd->dir == (*state)->direction ? "fwd" : "rev"); 4453126258Smlaier } 4454126258Smlaier 4455145836Smlaier if (dst->scrub || src->scrub) { 4456145836Smlaier if (pf_normalize_tcp_stateful(m, off, pd, reason, th, 4457200930Sdelphij *state, src, dst, copyback)) 4458145836Smlaier return (PF_DROP); 4459145836Smlaier } 4460145836Smlaier 4461126258Smlaier /* update max window */ 4462126258Smlaier if (src->max_win < win) 4463126258Smlaier src->max_win = win; 4464126258Smlaier /* synchronize sequencing */ 4465126258Smlaier if (SEQ_GT(end, src->seqlo)) 4466126258Smlaier src->seqlo = end; 4467126258Smlaier /* slide the window of what the other end can send */ 4468126258Smlaier if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) 4469126258Smlaier dst->seqhi = ack + MAX((win << sws), 1); 4470126258Smlaier 4471126258Smlaier /* 4472126258Smlaier * Cannot set dst->seqhi here since this could be a shotgunned 4473126258Smlaier * SYN and not an already established connection. 4474126258Smlaier */ 4475126258Smlaier 4476126258Smlaier if (th->th_flags & TH_FIN) 4477126258Smlaier if (src->state < TCPS_CLOSING) 4478126258Smlaier src->state = TCPS_CLOSING; 4479126258Smlaier if (th->th_flags & TH_RST) 4480126258Smlaier src->state = dst->state = TCPS_TIME_WAIT; 4481126258Smlaier 4482126258Smlaier /* Fall through to PASS packet */ 4483126258Smlaier 4484126258Smlaier } else { 4485126258Smlaier if ((*state)->dst.state == TCPS_SYN_SENT && 4486126258Smlaier (*state)->src.state == TCPS_SYN_SENT) { 4487126258Smlaier /* Send RST for state mismatches during handshake */ 4488145836Smlaier if (!(th->th_flags & TH_RST)) 4489162238Scsjp#ifdef __FreeBSD__ 4490223637Sbz pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4491162238Scsjp#else 4492126258Smlaier pf_send_tcp((*state)->rule.ptr, pd->af, 4493162238Scsjp#endif 4494126258Smlaier pd->dst, pd->src, th->th_dport, 4495145836Smlaier th->th_sport, ntohl(th->th_ack), 0, 4496145836Smlaier TH_RST, 0, 0, 4497171168Smlaier (*state)->rule.ptr->return_ttl, 1, 0, 4498145836Smlaier pd->eh, kif->pfik_ifp); 4499126258Smlaier src->seqlo = 0; 4500126258Smlaier src->seqhi = 1; 4501126258Smlaier src->max_win = 1; 4502223637Sbz#ifdef __FreeBSD__ 4503223637Sbz } else if (V_pf_status.debug >= PF_DEBUG_MISC) { 4504223637Sbz#else 4505126258Smlaier } else if (pf_status.debug >= PF_DEBUG_MISC) { 4506223637Sbz#endif 4507126258Smlaier printf("pf: BAD state: "); 4508126258Smlaier pf_print_state(*state); 4509126258Smlaier pf_print_flags(th->th_flags); 4510171168Smlaier printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " 4511171168Smlaier "pkts=%llu:%llu dir=%s,%s\n", 4512171168Smlaier seq, orig_seq, ack, pd->p_len, ackskew, 4513171168Smlaier#ifdef __FreeBSD__ 4514171168Smlaier (unsigned long long)(*state)->packets[0], 4515171168Smlaier (unsigned long long)(*state)->packets[1], 4516171168Smlaier#else 4517126258Smlaier (*state)->packets[0], (*state)->packets[1], 4518171168Smlaier#endif 4519223637Sbz pd->dir == PF_IN ? "in" : "out", 4520223637Sbz pd->dir == (*state)->direction ? "fwd" : "rev"); 4521126258Smlaier printf("pf: State failure on: %c %c %c %c | %c %c\n", 4522126258Smlaier SEQ_GEQ(src->seqhi, end) ? ' ' : '1', 4523126258Smlaier SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ? 4524126258Smlaier ' ': '2', 4525126258Smlaier (ackskew >= -MAXACKWINDOW) ? ' ' : '3', 4526126258Smlaier (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4', 4527126258Smlaier SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5', 4528126258Smlaier SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6'); 4529126258Smlaier } 4530145836Smlaier REASON_SET(reason, PFRES_BADSTATE); 4531126258Smlaier return (PF_DROP); 4532126258Smlaier } 4533126258Smlaier 4534200930Sdelphij return (PF_PASS); 4535200930Sdelphij} 4536126258Smlaier 4537200930Sdelphijint 4538200930Sdelphijpf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst, 4539200930Sdelphij struct pf_state **state, struct pf_pdesc *pd, u_short *reason) 4540200930Sdelphij{ 4541200930Sdelphij struct tcphdr *th = pd->hdr.tcp; 4542200930Sdelphij 4543200930Sdelphij if (th->th_flags & TH_SYN) 4544200930Sdelphij if (src->state < TCPS_SYN_SENT) 4545200930Sdelphij src->state = TCPS_SYN_SENT; 4546200930Sdelphij if (th->th_flags & TH_FIN) 4547200930Sdelphij if (src->state < TCPS_CLOSING) 4548200930Sdelphij src->state = TCPS_CLOSING; 4549200930Sdelphij if (th->th_flags & TH_ACK) { 4550200930Sdelphij if (dst->state == TCPS_SYN_SENT) { 4551200930Sdelphij dst->state = TCPS_ESTABLISHED; 4552200930Sdelphij if (src->state == TCPS_ESTABLISHED && 4553200930Sdelphij (*state)->src_node != NULL && 4554200930Sdelphij pf_src_connlimit(state)) { 4555200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4556200930Sdelphij return (PF_DROP); 4557200930Sdelphij } 4558200930Sdelphij } else if (dst->state == TCPS_CLOSING) { 4559200930Sdelphij dst->state = TCPS_FIN_WAIT_2; 4560200930Sdelphij } else if (src->state == TCPS_SYN_SENT && 4561200930Sdelphij dst->state < TCPS_SYN_SENT) { 4562200930Sdelphij /* 4563200930Sdelphij * Handle a special sloppy case where we only see one 4564200930Sdelphij * half of the connection. If there is a ACK after 4565200930Sdelphij * the initial SYN without ever seeing a packet from 4566200930Sdelphij * the destination, set the connection to established. 4567200930Sdelphij */ 4568200930Sdelphij dst->state = src->state = TCPS_ESTABLISHED; 4569200930Sdelphij if ((*state)->src_node != NULL && 4570200930Sdelphij pf_src_connlimit(state)) { 4571200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4572200930Sdelphij return (PF_DROP); 4573200930Sdelphij } 4574200930Sdelphij } else if (src->state == TCPS_CLOSING && 4575200930Sdelphij dst->state == TCPS_ESTABLISHED && 4576200930Sdelphij dst->seqlo == 0) { 4577200930Sdelphij /* 4578200930Sdelphij * Handle the closing of half connections where we 4579200930Sdelphij * don't see the full bidirectional FIN/ACK+ACK 4580200930Sdelphij * handshake. 4581200930Sdelphij */ 4582200930Sdelphij dst->state = TCPS_CLOSING; 4583200930Sdelphij } 4584200930Sdelphij } 4585200930Sdelphij if (th->th_flags & TH_RST) 4586200930Sdelphij src->state = dst->state = TCPS_TIME_WAIT; 4587200930Sdelphij 4588200930Sdelphij /* update expire time */ 4589200930Sdelphij (*state)->expire = time_second; 4590200930Sdelphij if (src->state >= TCPS_FIN_WAIT_2 && 4591200930Sdelphij dst->state >= TCPS_FIN_WAIT_2) 4592200930Sdelphij (*state)->timeout = PFTM_TCP_CLOSED; 4593200930Sdelphij else if (src->state >= TCPS_CLOSING && 4594200930Sdelphij dst->state >= TCPS_CLOSING) 4595200930Sdelphij (*state)->timeout = PFTM_TCP_FIN_WAIT; 4596200930Sdelphij else if (src->state < TCPS_ESTABLISHED || 4597200930Sdelphij dst->state < TCPS_ESTABLISHED) 4598200930Sdelphij (*state)->timeout = PFTM_TCP_OPENING; 4599200930Sdelphij else if (src->state >= TCPS_CLOSING || 4600200930Sdelphij dst->state >= TCPS_CLOSING) 4601200930Sdelphij (*state)->timeout = PFTM_TCP_CLOSING; 4602200930Sdelphij else 4603200930Sdelphij (*state)->timeout = PFTM_TCP_ESTABLISHED; 4604200930Sdelphij 4605200930Sdelphij return (PF_PASS); 4606200930Sdelphij} 4607200930Sdelphij 4608200930Sdelphijint 4609200930Sdelphijpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, 4610200930Sdelphij struct mbuf *m, int off, void *h, struct pf_pdesc *pd, 4611200930Sdelphij u_short *reason) 4612200930Sdelphij{ 4613223637Sbz struct pf_state_key_cmp key; 4614200930Sdelphij struct tcphdr *th = pd->hdr.tcp; 4615200930Sdelphij int copyback = 0; 4616200930Sdelphij struct pf_state_peer *src, *dst; 4617223637Sbz struct pf_state_key *sk; 4618200930Sdelphij 4619200930Sdelphij key.af = pd->af; 4620200930Sdelphij key.proto = IPPROTO_TCP; 4621223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4622223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4623223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4624223637Sbz key.port[0] = th->th_sport; 4625223637Sbz key.port[1] = th->th_dport; 4626223637Sbz } else { /* stack side, reverse */ 4627223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4628223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4629223637Sbz key.port[1] = th->th_sport; 4630223637Sbz key.port[0] = th->th_dport; 4631200930Sdelphij } 4632200930Sdelphij 4633223637Sbz#ifdef __FreeBSD__ 4634223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4635223637Sbz#else 4636223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4637223637Sbz#endif 4638200930Sdelphij 4639200930Sdelphij if (direction == (*state)->direction) { 4640200930Sdelphij src = &(*state)->src; 4641200930Sdelphij dst = &(*state)->dst; 4642200930Sdelphij } else { 4643200930Sdelphij src = &(*state)->dst; 4644200930Sdelphij dst = &(*state)->src; 4645200930Sdelphij } 4646200930Sdelphij 4647223637Sbz sk = (*state)->key[pd->didx]; 4648223637Sbz 4649200930Sdelphij if ((*state)->src.state == PF_TCPS_PROXY_SRC) { 4650200930Sdelphij if (direction != (*state)->direction) { 4651200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4652200930Sdelphij return (PF_SYNPROXY_DROP); 4653200930Sdelphij } 4654200930Sdelphij if (th->th_flags & TH_SYN) { 4655200930Sdelphij if (ntohl(th->th_seq) != (*state)->src.seqlo) { 4656200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4657200930Sdelphij return (PF_DROP); 4658200930Sdelphij } 4659200930Sdelphij#ifdef __FreeBSD__ 4660200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, 4661200930Sdelphij#else 4662200930Sdelphij pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, 4663200930Sdelphij#endif 4664200930Sdelphij pd->src, th->th_dport, th->th_sport, 4665200930Sdelphij (*state)->src.seqhi, ntohl(th->th_seq) + 1, 4666200930Sdelphij TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 4667200930Sdelphij 0, NULL, NULL); 4668200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4669200930Sdelphij return (PF_SYNPROXY_DROP); 4670200930Sdelphij } else if (!(th->th_flags & TH_ACK) || 4671200930Sdelphij (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || 4672200930Sdelphij (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { 4673200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4674200930Sdelphij return (PF_DROP); 4675200930Sdelphij } else if ((*state)->src_node != NULL && 4676200930Sdelphij pf_src_connlimit(state)) { 4677200930Sdelphij REASON_SET(reason, PFRES_SRCLIMIT); 4678200930Sdelphij return (PF_DROP); 4679200930Sdelphij } else 4680200930Sdelphij (*state)->src.state = PF_TCPS_PROXY_DST; 4681200930Sdelphij } 4682200930Sdelphij if ((*state)->src.state == PF_TCPS_PROXY_DST) { 4683200930Sdelphij if (direction == (*state)->direction) { 4684200930Sdelphij if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || 4685200930Sdelphij (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || 4686200930Sdelphij (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { 4687200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4688200930Sdelphij return (PF_DROP); 4689200930Sdelphij } 4690200930Sdelphij (*state)->src.max_win = MAX(ntohs(th->th_win), 1); 4691200930Sdelphij if ((*state)->dst.seqhi == 1) 4692200930Sdelphij (*state)->dst.seqhi = htonl(arc4random()); 4693200930Sdelphij#ifdef __FreeBSD__ 4694200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4695200930Sdelphij#else 4696223637Sbz pf_send_tcp((*state)->rule.ptr, pd->af, 4697200930Sdelphij#endif 4698223637Sbz &sk->addr[pd->sidx], &sk->addr[pd->didx], 4699223637Sbz sk->port[pd->sidx], sk->port[pd->didx], 4700200930Sdelphij (*state)->dst.seqhi, 0, TH_SYN, 0, 4701200930Sdelphij (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); 4702200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4703200930Sdelphij return (PF_SYNPROXY_DROP); 4704200930Sdelphij } else if (((th->th_flags & (TH_SYN|TH_ACK)) != 4705200930Sdelphij (TH_SYN|TH_ACK)) || 4706200930Sdelphij (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) { 4707200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4708200930Sdelphij return (PF_DROP); 4709200930Sdelphij } else { 4710200930Sdelphij (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); 4711200930Sdelphij (*state)->dst.seqlo = ntohl(th->th_seq); 4712200930Sdelphij#ifdef __FreeBSD__ 4713200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst, 4714200930Sdelphij#else 4715200930Sdelphij pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst, 4716200930Sdelphij#endif 4717200930Sdelphij pd->src, th->th_dport, th->th_sport, 4718200930Sdelphij ntohl(th->th_ack), ntohl(th->th_seq) + 1, 4719200930Sdelphij TH_ACK, (*state)->src.max_win, 0, 0, 0, 4720200930Sdelphij (*state)->tag, NULL, NULL); 4721200930Sdelphij#ifdef __FreeBSD__ 4722200930Sdelphij pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, 4723200930Sdelphij#else 4724223637Sbz pf_send_tcp((*state)->rule.ptr, pd->af, 4725200930Sdelphij#endif 4726223637Sbz &sk->addr[pd->sidx], &sk->addr[pd->didx], 4727223637Sbz sk->port[pd->sidx], sk->port[pd->didx], 4728200930Sdelphij (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, 4729200930Sdelphij TH_ACK, (*state)->dst.max_win, 0, 0, 1, 4730200930Sdelphij 0, NULL, NULL); 4731200930Sdelphij (*state)->src.seqdiff = (*state)->dst.seqhi - 4732200930Sdelphij (*state)->src.seqlo; 4733200930Sdelphij (*state)->dst.seqdiff = (*state)->src.seqhi - 4734200930Sdelphij (*state)->dst.seqlo; 4735200930Sdelphij (*state)->src.seqhi = (*state)->src.seqlo + 4736200930Sdelphij (*state)->dst.max_win; 4737200930Sdelphij (*state)->dst.seqhi = (*state)->dst.seqlo + 4738200930Sdelphij (*state)->src.max_win; 4739200930Sdelphij (*state)->src.wscale = (*state)->dst.wscale = 0; 4740200930Sdelphij (*state)->src.state = (*state)->dst.state = 4741200930Sdelphij TCPS_ESTABLISHED; 4742200930Sdelphij REASON_SET(reason, PFRES_SYNPROXY); 4743200930Sdelphij return (PF_SYNPROXY_DROP); 4744200930Sdelphij } 4745200930Sdelphij } 4746200930Sdelphij 4747200930Sdelphij if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) && 4748200930Sdelphij dst->state >= TCPS_FIN_WAIT_2 && 4749200930Sdelphij src->state >= TCPS_FIN_WAIT_2) { 4750223637Sbz#ifdef __FreeBSD__ 4751223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 4752223637Sbz#else 4753200930Sdelphij if (pf_status.debug >= PF_DEBUG_MISC) { 4754223637Sbz#endif 4755200930Sdelphij printf("pf: state reuse "); 4756200930Sdelphij pf_print_state(*state); 4757200930Sdelphij pf_print_flags(th->th_flags); 4758200930Sdelphij printf("\n"); 4759200930Sdelphij } 4760200930Sdelphij /* XXX make sure it's the same direction ?? */ 4761200930Sdelphij (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; 4762200930Sdelphij pf_unlink_state(*state); 4763200930Sdelphij *state = NULL; 4764200930Sdelphij return (PF_DROP); 4765200930Sdelphij } 4766200930Sdelphij 4767200930Sdelphij if ((*state)->state_flags & PFSTATE_SLOPPY) { 4768200930Sdelphij if (pf_tcp_track_sloppy(src, dst, state, pd, reason) == PF_DROP) 4769200930Sdelphij return (PF_DROP); 4770200930Sdelphij } else { 4771200930Sdelphij if (pf_tcp_track_full(src, dst, state, kif, m, off, pd, reason, 4772200930Sdelphij ©back) == PF_DROP) 4773200930Sdelphij return (PF_DROP); 4774200930Sdelphij } 4775200930Sdelphij 4776126258Smlaier /* translate source/destination address, if necessary */ 4777223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4778223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4779223637Sbz 4780223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || 4781223637Sbz nk->port[pd->sidx] != th->th_sport) 4782293896Sglebius pf_change_ap(m, pd->src, &th->th_sport, 4783293896Sglebius pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx], 4784223637Sbz nk->port[pd->sidx], 0, pd->af); 4785223637Sbz 4786223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || 4787223637Sbz nk->port[pd->didx] != th->th_dport) 4788293896Sglebius pf_change_ap(m, pd->dst, &th->th_dport, 4789293896Sglebius pd->ip_sum, &th->th_sum, &nk->addr[pd->didx], 4790223637Sbz nk->port[pd->didx], 0, pd->af); 4791223637Sbz copyback = 1; 4792126258Smlaier } 4793126258Smlaier 4794223637Sbz /* Copyback sequence modulation or stateful scrub changes if needed */ 4795223637Sbz if (copyback) 4796223637Sbz#ifdef __FreeBSD__ 4797223637Sbz m_copyback(m, off, sizeof(*th), (caddr_t)th); 4798223637Sbz#else 4799223637Sbz m_copyback(m, off, sizeof(*th), th); 4800223637Sbz#endif 4801223637Sbz 4802126258Smlaier return (PF_PASS); 4803126258Smlaier} 4804126258Smlaier 4805126258Smlaierint 4806130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, 4807130613Smlaier struct mbuf *m, int off, void *h, struct pf_pdesc *pd) 4808126258Smlaier{ 4809126258Smlaier struct pf_state_peer *src, *dst; 4810223637Sbz struct pf_state_key_cmp key; 4811126258Smlaier struct udphdr *uh = pd->hdr.udp; 4812126258Smlaier 4813126258Smlaier key.af = pd->af; 4814126258Smlaier key.proto = IPPROTO_UDP; 4815223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4816223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4817223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4818223637Sbz key.port[0] = uh->uh_sport; 4819223637Sbz key.port[1] = uh->uh_dport; 4820223637Sbz } else { /* stack side, reverse */ 4821223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4822223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4823223637Sbz key.port[1] = uh->uh_sport; 4824223637Sbz key.port[0] = uh->uh_dport; 4825130613Smlaier } 4826126258Smlaier 4827223637Sbz#ifdef __FreeBSD__ 4828223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4829223637Sbz#else 4830223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4831223637Sbz#endif 4832126258Smlaier 4833126258Smlaier if (direction == (*state)->direction) { 4834126258Smlaier src = &(*state)->src; 4835126258Smlaier dst = &(*state)->dst; 4836126258Smlaier } else { 4837126258Smlaier src = &(*state)->dst; 4838126258Smlaier dst = &(*state)->src; 4839126258Smlaier } 4840126258Smlaier 4841126258Smlaier /* update states */ 4842126258Smlaier if (src->state < PFUDPS_SINGLE) 4843126258Smlaier src->state = PFUDPS_SINGLE; 4844126258Smlaier if (dst->state == PFUDPS_SINGLE) 4845126258Smlaier dst->state = PFUDPS_MULTIPLE; 4846126258Smlaier 4847126258Smlaier /* update expire time */ 4848126261Smlaier (*state)->expire = time_second; 4849126258Smlaier if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE) 4850126258Smlaier (*state)->timeout = PFTM_UDP_MULTIPLE; 4851126258Smlaier else 4852126258Smlaier (*state)->timeout = PFTM_UDP_SINGLE; 4853126258Smlaier 4854126258Smlaier /* translate source/destination address, if necessary */ 4855223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4856223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4857223637Sbz 4858223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || 4859223637Sbz nk->port[pd->sidx] != uh->uh_sport) 4860293896Sglebius pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum, 4861223637Sbz &uh->uh_sum, &nk->addr[pd->sidx], 4862223637Sbz nk->port[pd->sidx], 1, pd->af); 4863223637Sbz 4864223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || 4865223637Sbz nk->port[pd->didx] != uh->uh_dport) 4866293896Sglebius pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum, 4867223637Sbz &uh->uh_sum, &nk->addr[pd->didx], 4868223637Sbz nk->port[pd->didx], 1, pd->af); 4869223637Sbz#ifdef __FreeBSD__ 4870126261Smlaier m_copyback(m, off, sizeof(*uh), (caddr_t)uh); 4871223637Sbz#else 4872223637Sbz m_copyback(m, off, sizeof(*uh), uh); 4873223637Sbz#endif 4874126258Smlaier } 4875126258Smlaier 4876126258Smlaier return (PF_PASS); 4877126258Smlaier} 4878126258Smlaier 4879126258Smlaierint 4880130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, 4881145836Smlaier struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) 4882126258Smlaier{ 4883223637Sbz struct pf_addr *saddr = pd->src, *daddr = pd->dst; 4884223637Sbz#ifdef __FreeBSD__ 4885223637Sbz u_int16_t icmpid = 0, *icmpsum; 4886223637Sbz#else 4887223637Sbz u_int16_t icmpid, *icmpsum; 4888223637Sbz#endif 4889223637Sbz u_int8_t icmptype; 4890130613Smlaier int state_icmp = 0; 4891223637Sbz struct pf_state_key_cmp key; 4892126258Smlaier 4893126258Smlaier switch (pd->proto) { 4894126258Smlaier#ifdef INET 4895126258Smlaier case IPPROTO_ICMP: 4896126258Smlaier icmptype = pd->hdr.icmp->icmp_type; 4897126258Smlaier icmpid = pd->hdr.icmp->icmp_id; 4898126258Smlaier icmpsum = &pd->hdr.icmp->icmp_cksum; 4899126258Smlaier 4900126258Smlaier if (icmptype == ICMP_UNREACH || 4901126258Smlaier icmptype == ICMP_SOURCEQUENCH || 4902126258Smlaier icmptype == ICMP_REDIRECT || 4903126258Smlaier icmptype == ICMP_TIMXCEED || 4904126258Smlaier icmptype == ICMP_PARAMPROB) 4905126258Smlaier state_icmp++; 4906126258Smlaier break; 4907126258Smlaier#endif /* INET */ 4908126258Smlaier#ifdef INET6 4909126258Smlaier case IPPROTO_ICMPV6: 4910126258Smlaier icmptype = pd->hdr.icmp6->icmp6_type; 4911126258Smlaier icmpid = pd->hdr.icmp6->icmp6_id; 4912126258Smlaier icmpsum = &pd->hdr.icmp6->icmp6_cksum; 4913126258Smlaier 4914126258Smlaier if (icmptype == ICMP6_DST_UNREACH || 4915126258Smlaier icmptype == ICMP6_PACKET_TOO_BIG || 4916126258Smlaier icmptype == ICMP6_TIME_EXCEEDED || 4917126258Smlaier icmptype == ICMP6_PARAM_PROB) 4918126258Smlaier state_icmp++; 4919126258Smlaier break; 4920126258Smlaier#endif /* INET6 */ 4921126258Smlaier } 4922126258Smlaier 4923126258Smlaier if (!state_icmp) { 4924126258Smlaier 4925126258Smlaier /* 4926126258Smlaier * ICMP query/reply message not related to a TCP/UDP packet. 4927126258Smlaier * Search for an ICMP state. 4928126258Smlaier */ 4929126258Smlaier key.af = pd->af; 4930126258Smlaier key.proto = pd->proto; 4931223637Sbz key.port[0] = key.port[1] = icmpid; 4932223637Sbz if (direction == PF_IN) { /* wire side, straight */ 4933223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 4934223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 4935223637Sbz } else { /* stack side, reverse */ 4936223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 4937223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 4938130613Smlaier } 4939126258Smlaier 4940223637Sbz#ifdef __FreeBSD__ 4941223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 4942223637Sbz#else 4943223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 4944223637Sbz#endif 4945126258Smlaier 4946126261Smlaier (*state)->expire = time_second; 4947126258Smlaier (*state)->timeout = PFTM_ICMP_ERROR_REPLY; 4948126258Smlaier 4949126258Smlaier /* translate source/destination address, if necessary */ 4950223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 4951223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 4952223637Sbz 4953223637Sbz switch (pd->af) { 4954126258Smlaier#ifdef INET 4955223637Sbz case AF_INET: 4956223637Sbz if (PF_ANEQ(pd->src, 4957223637Sbz &nk->addr[pd->sidx], AF_INET)) 4958126258Smlaier pf_change_a(&saddr->v4.s_addr, 4959126258Smlaier pd->ip_sum, 4960223637Sbz nk->addr[pd->sidx].v4.s_addr, 0); 4961223637Sbz 4962223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], 4963223637Sbz AF_INET)) 4964223637Sbz pf_change_a(&daddr->v4.s_addr, 4965223637Sbz pd->ip_sum, 4966223637Sbz nk->addr[pd->didx].v4.s_addr, 0); 4967223637Sbz 4968223637Sbz if (nk->port[0] != 4969223637Sbz pd->hdr.icmp->icmp_id) { 4970149884Smlaier pd->hdr.icmp->icmp_cksum = 4971149884Smlaier pf_cksum_fixup( 4972149884Smlaier pd->hdr.icmp->icmp_cksum, icmpid, 4973223637Sbz nk->port[pd->sidx], 0); 4974149884Smlaier pd->hdr.icmp->icmp_id = 4975223637Sbz nk->port[pd->sidx]; 4976223637Sbz } 4977223637Sbz 4978223637Sbz m_copyback(m, off, ICMP_MINLEN, 4979223637Sbz#ifdef __FreeBSD__ 4980223637Sbz (caddr_t) 4981223637Sbz#endif 4982223637Sbz pd->hdr.icmp); 4983223637Sbz break; 4984126258Smlaier#endif /* INET */ 4985126258Smlaier#ifdef INET6 4986223637Sbz case AF_INET6: 4987223637Sbz if (PF_ANEQ(pd->src, 4988223637Sbz &nk->addr[pd->sidx], AF_INET6)) 4989126258Smlaier pf_change_a6(saddr, 4990126258Smlaier &pd->hdr.icmp6->icmp6_cksum, 4991223637Sbz &nk->addr[pd->sidx], 0); 4992223637Sbz 4993223637Sbz if (PF_ANEQ(pd->dst, 4994223637Sbz &nk->addr[pd->didx], AF_INET6)) 4995126258Smlaier pf_change_a6(daddr, 4996126258Smlaier &pd->hdr.icmp6->icmp6_cksum, 4997223637Sbz &nk->addr[pd->didx], 0); 4998223637Sbz 4999223637Sbz m_copyback(m, off, 5000223637Sbz sizeof(struct icmp6_hdr), 5001223637Sbz#ifdef __FreeBSD__ 5002223637Sbz (caddr_t) 5003223637Sbz#endif 5004223637Sbz pd->hdr.icmp6); 5005223637Sbz break; 5006126258Smlaier#endif /* INET6 */ 5007126258Smlaier } 5008126258Smlaier } 5009126258Smlaier return (PF_PASS); 5010126258Smlaier 5011126258Smlaier } else { 5012126258Smlaier /* 5013126258Smlaier * ICMP error message in response to a TCP/UDP packet. 5014126258Smlaier * Extract the inner TCP/UDP header and search for that state. 5015126258Smlaier */ 5016126258Smlaier 5017126258Smlaier struct pf_pdesc pd2; 5018223637Sbz#ifdef __FreeBSD__ 5019223637Sbz bzero(&pd2, sizeof pd2); 5020223637Sbz#endif 5021126258Smlaier#ifdef INET 5022126258Smlaier struct ip h2; 5023126258Smlaier#endif /* INET */ 5024126258Smlaier#ifdef INET6 5025126258Smlaier struct ip6_hdr h2_6; 5026126258Smlaier int terminal = 0; 5027126258Smlaier#endif /* INET6 */ 5028223637Sbz#ifdef __FreeBSD__ 5029223637Sbz int ipoff2 = 0; 5030223637Sbz int off2 = 0; 5031223637Sbz#else 5032223637Sbz int ipoff2; 5033223637Sbz int off2; 5034223637Sbz#endif 5035126258Smlaier 5036126258Smlaier pd2.af = pd->af; 5037223637Sbz /* Payload packet is from the opposite direction. */ 5038223637Sbz pd2.sidx = (direction == PF_IN) ? 1 : 0; 5039223637Sbz pd2.didx = (direction == PF_IN) ? 0 : 1; 5040126258Smlaier switch (pd->af) { 5041126258Smlaier#ifdef INET 5042126258Smlaier case AF_INET: 5043126258Smlaier /* offset of h2 in mbuf chain */ 5044126258Smlaier ipoff2 = off + ICMP_MINLEN; 5045126258Smlaier 5046126258Smlaier if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), 5047145836Smlaier NULL, reason, pd2.af)) { 5048126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5049126258Smlaier ("pf: ICMP error message too short " 5050126258Smlaier "(ip)\n")); 5051126258Smlaier return (PF_DROP); 5052126258Smlaier } 5053126258Smlaier /* 5054126258Smlaier * ICMP error messages don't refer to non-first 5055126258Smlaier * fragments 5056126258Smlaier */ 5057145836Smlaier if (h2.ip_off & htons(IP_OFFMASK)) { 5058145836Smlaier REASON_SET(reason, PFRES_FRAG); 5059126258Smlaier return (PF_DROP); 5060145836Smlaier } 5061126258Smlaier 5062126258Smlaier /* offset of protocol header that follows h2 */ 5063126258Smlaier off2 = ipoff2 + (h2.ip_hl << 2); 5064126258Smlaier 5065126258Smlaier pd2.proto = h2.ip_p; 5066126258Smlaier pd2.src = (struct pf_addr *)&h2.ip_src; 5067126258Smlaier pd2.dst = (struct pf_addr *)&h2.ip_dst; 5068126258Smlaier pd2.ip_sum = &h2.ip_sum; 5069126258Smlaier break; 5070126258Smlaier#endif /* INET */ 5071126258Smlaier#ifdef INET6 5072126258Smlaier case AF_INET6: 5073126258Smlaier ipoff2 = off + sizeof(struct icmp6_hdr); 5074126258Smlaier 5075126258Smlaier if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6), 5076145836Smlaier NULL, reason, pd2.af)) { 5077126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5078126258Smlaier ("pf: ICMP error message too short " 5079126258Smlaier "(ip6)\n")); 5080126258Smlaier return (PF_DROP); 5081126258Smlaier } 5082126258Smlaier pd2.proto = h2_6.ip6_nxt; 5083126258Smlaier pd2.src = (struct pf_addr *)&h2_6.ip6_src; 5084126258Smlaier pd2.dst = (struct pf_addr *)&h2_6.ip6_dst; 5085126258Smlaier pd2.ip_sum = NULL; 5086126258Smlaier off2 = ipoff2 + sizeof(h2_6); 5087126258Smlaier do { 5088126258Smlaier switch (pd2.proto) { 5089126258Smlaier case IPPROTO_FRAGMENT: 5090126258Smlaier /* 5091126258Smlaier * ICMPv6 error messages for 5092126258Smlaier * non-first fragments 5093126258Smlaier */ 5094145836Smlaier REASON_SET(reason, PFRES_FRAG); 5095126258Smlaier return (PF_DROP); 5096126258Smlaier case IPPROTO_AH: 5097126258Smlaier case IPPROTO_HOPOPTS: 5098126258Smlaier case IPPROTO_ROUTING: 5099126258Smlaier case IPPROTO_DSTOPTS: { 5100126258Smlaier /* get next header and header length */ 5101126258Smlaier struct ip6_ext opt6; 5102126258Smlaier 5103126258Smlaier if (!pf_pull_hdr(m, off2, &opt6, 5104145836Smlaier sizeof(opt6), NULL, reason, 5105145836Smlaier pd2.af)) { 5106126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5107126258Smlaier ("pf: ICMPv6 short opt\n")); 5108126258Smlaier return (PF_DROP); 5109126258Smlaier } 5110126258Smlaier if (pd2.proto == IPPROTO_AH) 5111126258Smlaier off2 += (opt6.ip6e_len + 2) * 4; 5112126258Smlaier else 5113126258Smlaier off2 += (opt6.ip6e_len + 1) * 8; 5114126258Smlaier pd2.proto = opt6.ip6e_nxt; 5115126258Smlaier /* goto the next header */ 5116126258Smlaier break; 5117126258Smlaier } 5118126258Smlaier default: 5119126258Smlaier terminal++; 5120126258Smlaier break; 5121126258Smlaier } 5122126258Smlaier } while (!terminal); 5123126258Smlaier break; 5124126258Smlaier#endif /* INET6 */ 5125126258Smlaier } 5126126258Smlaier 5127126258Smlaier switch (pd2.proto) { 5128126258Smlaier case IPPROTO_TCP: { 5129126258Smlaier struct tcphdr th; 5130126258Smlaier u_int32_t seq; 5131126258Smlaier struct pf_state_peer *src, *dst; 5132126258Smlaier u_int8_t dws; 5133128129Smlaier int copyback = 0; 5134126258Smlaier 5135126258Smlaier /* 5136126258Smlaier * Only the first 8 bytes of the TCP header can be 5137126258Smlaier * expected. Don't access any TCP header fields after 5138126258Smlaier * th_seq, an ackskew test is not possible. 5139126258Smlaier */ 5140145836Smlaier if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason, 5141145836Smlaier pd2.af)) { 5142126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5143126258Smlaier ("pf: ICMP error message too short " 5144126258Smlaier "(tcp)\n")); 5145126258Smlaier return (PF_DROP); 5146126258Smlaier } 5147126258Smlaier 5148126258Smlaier key.af = pd2.af; 5149126258Smlaier key.proto = IPPROTO_TCP; 5150223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5151223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5152223637Sbz key.port[pd2.sidx] = th.th_sport; 5153223637Sbz key.port[pd2.didx] = th.th_dport; 5154126258Smlaier 5155223637Sbz#ifdef __FreeBSD__ 5156223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5157223637Sbz#else 5158223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5159223637Sbz#endif 5160126258Smlaier 5161126258Smlaier if (direction == (*state)->direction) { 5162126258Smlaier src = &(*state)->dst; 5163126258Smlaier dst = &(*state)->src; 5164126258Smlaier } else { 5165126258Smlaier src = &(*state)->src; 5166126258Smlaier dst = &(*state)->dst; 5167126258Smlaier } 5168126258Smlaier 5169171929Sdhartmei if (src->wscale && dst->wscale) 5170126258Smlaier dws = dst->wscale & PF_WSCALE_MASK; 5171126258Smlaier else 5172126258Smlaier dws = 0; 5173126258Smlaier 5174126258Smlaier /* Demodulate sequence number */ 5175126258Smlaier seq = ntohl(th.th_seq) - src->seqdiff; 5176128129Smlaier if (src->seqdiff) { 5177128129Smlaier pf_change_a(&th.th_seq, icmpsum, 5178126258Smlaier htonl(seq), 0); 5179128129Smlaier copyback = 1; 5180128129Smlaier } 5181126258Smlaier 5182200930Sdelphij if (!((*state)->state_flags & PFSTATE_SLOPPY) && 5183200930Sdelphij (!SEQ_GEQ(src->seqhi, seq) || 5184200930Sdelphij !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) { 5185223637Sbz#ifdef __FreeBSD__ 5186223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 5187223637Sbz#else 5188126258Smlaier if (pf_status.debug >= PF_DEBUG_MISC) { 5189223637Sbz#endif 5190126258Smlaier printf("pf: BAD ICMP %d:%d ", 5191126258Smlaier icmptype, pd->hdr.icmp->icmp_code); 5192126258Smlaier pf_print_host(pd->src, 0, pd->af); 5193126258Smlaier printf(" -> "); 5194126258Smlaier pf_print_host(pd->dst, 0, pd->af); 5195126258Smlaier printf(" state: "); 5196126258Smlaier pf_print_state(*state); 5197126258Smlaier printf(" seq=%u\n", seq); 5198126258Smlaier } 5199145836Smlaier REASON_SET(reason, PFRES_BADSTATE); 5200126258Smlaier return (PF_DROP); 5201223637Sbz } else { 5202223637Sbz#ifdef __FreeBSD__ 5203223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 5204223637Sbz#else 5205223637Sbz if (pf_status.debug >= PF_DEBUG_MISC) { 5206223637Sbz#endif 5207223637Sbz printf("pf: OK ICMP %d:%d ", 5208223637Sbz icmptype, pd->hdr.icmp->icmp_code); 5209223637Sbz pf_print_host(pd->src, 0, pd->af); 5210223637Sbz printf(" -> "); 5211223637Sbz pf_print_host(pd->dst, 0, pd->af); 5212223637Sbz printf(" state: "); 5213223637Sbz pf_print_state(*state); 5214223637Sbz printf(" seq=%u\n", seq); 5215223637Sbz } 5216126258Smlaier } 5217126258Smlaier 5218223637Sbz /* translate source/destination address, if necessary */ 5219223637Sbz if ((*state)->key[PF_SK_WIRE] != 5220223637Sbz (*state)->key[PF_SK_STACK]) { 5221223637Sbz struct pf_state_key *nk = 5222223637Sbz (*state)->key[pd->didx]; 5223223637Sbz 5224223637Sbz if (PF_ANEQ(pd2.src, 5225223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5226223637Sbz nk->port[pd2.sidx] != th.th_sport) 5227126258Smlaier pf_change_icmp(pd2.src, &th.th_sport, 5228223637Sbz daddr, &nk->addr[pd2.sidx], 5229223637Sbz nk->port[pd2.sidx], NULL, 5230126258Smlaier pd2.ip_sum, icmpsum, 5231126258Smlaier pd->ip_sum, 0, pd2.af); 5232223637Sbz 5233223637Sbz if (PF_ANEQ(pd2.dst, 5234223637Sbz &nk->addr[pd2.didx], pd2.af) || 5235223637Sbz nk->port[pd2.didx] != th.th_dport) 5236126258Smlaier pf_change_icmp(pd2.dst, &th.th_dport, 5237223637Sbz NULL, /* XXX Inbound NAT? */ 5238223637Sbz &nk->addr[pd2.didx], 5239223637Sbz nk->port[pd2.didx], NULL, 5240126258Smlaier pd2.ip_sum, icmpsum, 5241126258Smlaier pd->ip_sum, 0, pd2.af); 5242128129Smlaier copyback = 1; 5243128129Smlaier } 5244128129Smlaier 5245128129Smlaier if (copyback) { 5246126258Smlaier switch (pd2.af) { 5247126258Smlaier#ifdef INET 5248126258Smlaier case AF_INET: 5249126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5250223637Sbz#ifdef __FreeBSD__ 5251223637Sbz (caddr_t) 5252223637Sbz#endif 5253223637Sbz pd->hdr.icmp); 5254126258Smlaier m_copyback(m, ipoff2, sizeof(h2), 5255223637Sbz#ifdef __FreeBSD__ 5256223637Sbz (caddr_t) 5257223637Sbz#endif 5258223637Sbz &h2); 5259126258Smlaier break; 5260126258Smlaier#endif /* INET */ 5261126258Smlaier#ifdef INET6 5262126258Smlaier case AF_INET6: 5263126258Smlaier m_copyback(m, off, 5264126258Smlaier sizeof(struct icmp6_hdr), 5265223637Sbz#ifdef __FreeBSD__ 5266223637Sbz (caddr_t) 5267223637Sbz#endif 5268223637Sbz pd->hdr.icmp6); 5269126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5270223637Sbz#ifdef __FreeBSD__ 5271223637Sbz (caddr_t) 5272223637Sbz#endif 5273223637Sbz &h2_6); 5274126258Smlaier break; 5275126258Smlaier#endif /* INET6 */ 5276126258Smlaier } 5277223637Sbz#ifdef __FreeBSD__ 5278126261Smlaier m_copyback(m, off2, 8, (caddr_t)&th); 5279223637Sbz#else 5280223637Sbz m_copyback(m, off2, 8, &th); 5281223637Sbz#endif 5282126258Smlaier } 5283126258Smlaier 5284126258Smlaier return (PF_PASS); 5285126258Smlaier break; 5286126258Smlaier } 5287126258Smlaier case IPPROTO_UDP: { 5288126258Smlaier struct udphdr uh; 5289126258Smlaier 5290126258Smlaier if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), 5291145836Smlaier NULL, reason, pd2.af)) { 5292126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5293126258Smlaier ("pf: ICMP error message too short " 5294126258Smlaier "(udp)\n")); 5295126258Smlaier return (PF_DROP); 5296126258Smlaier } 5297126258Smlaier 5298126258Smlaier key.af = pd2.af; 5299126258Smlaier key.proto = IPPROTO_UDP; 5300223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5301223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5302223637Sbz key.port[pd2.sidx] = uh.uh_sport; 5303223637Sbz key.port[pd2.didx] = uh.uh_dport; 5304126258Smlaier 5305223637Sbz#ifdef __FreeBSD__ 5306223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5307223637Sbz#else 5308223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5309223637Sbz#endif 5310126258Smlaier 5311223637Sbz /* translate source/destination address, if necessary */ 5312223637Sbz if ((*state)->key[PF_SK_WIRE] != 5313223637Sbz (*state)->key[PF_SK_STACK]) { 5314223637Sbz struct pf_state_key *nk = 5315223637Sbz (*state)->key[pd->didx]; 5316223637Sbz 5317223637Sbz if (PF_ANEQ(pd2.src, 5318223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5319223637Sbz nk->port[pd2.sidx] != uh.uh_sport) 5320126258Smlaier pf_change_icmp(pd2.src, &uh.uh_sport, 5321223637Sbz daddr, &nk->addr[pd2.sidx], 5322223637Sbz nk->port[pd2.sidx], &uh.uh_sum, 5323126258Smlaier pd2.ip_sum, icmpsum, 5324126258Smlaier pd->ip_sum, 1, pd2.af); 5325223637Sbz 5326223637Sbz if (PF_ANEQ(pd2.dst, 5327223637Sbz &nk->addr[pd2.didx], pd2.af) || 5328223637Sbz nk->port[pd2.didx] != uh.uh_dport) 5329126258Smlaier pf_change_icmp(pd2.dst, &uh.uh_dport, 5330223637Sbz NULL, /* XXX Inbound NAT? */ 5331223637Sbz &nk->addr[pd2.didx], 5332223637Sbz nk->port[pd2.didx], &uh.uh_sum, 5333126258Smlaier pd2.ip_sum, icmpsum, 5334126258Smlaier pd->ip_sum, 1, pd2.af); 5335223637Sbz 5336126258Smlaier switch (pd2.af) { 5337126258Smlaier#ifdef INET 5338126258Smlaier case AF_INET: 5339126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5340223637Sbz#ifdef __FreeBSD__ 5341223637Sbz (caddr_t) 5342223637Sbz#endif 5343223637Sbz pd->hdr.icmp); 5344223637Sbz#ifdef __FreeBSD__ 5345223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5346223637Sbz#else 5347223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5348223637Sbz#endif 5349126258Smlaier break; 5350126258Smlaier#endif /* INET */ 5351126258Smlaier#ifdef INET6 5352126258Smlaier case AF_INET6: 5353126258Smlaier m_copyback(m, off, 5354126258Smlaier sizeof(struct icmp6_hdr), 5355223637Sbz#ifdef __FreeBSD__ 5356223637Sbz (caddr_t) 5357223637Sbz#endif 5358223637Sbz pd->hdr.icmp6); 5359126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5360223637Sbz#ifdef __FreeBSD__ 5361223637Sbz (caddr_t) 5362223637Sbz#endif 5363223637Sbz &h2_6); 5364126258Smlaier break; 5365126258Smlaier#endif /* INET6 */ 5366126258Smlaier } 5367223637Sbz#ifdef __FreeBSD__ 5368223637Sbz m_copyback(m, off2, sizeof(uh), (caddr_t)&uh); 5369223637Sbz#else 5370223637Sbz m_copyback(m, off2, sizeof(uh), &uh); 5371223637Sbz#endif 5372126258Smlaier } 5373126258Smlaier return (PF_PASS); 5374126258Smlaier break; 5375126258Smlaier } 5376126258Smlaier#ifdef INET 5377126258Smlaier case IPPROTO_ICMP: { 5378126258Smlaier struct icmp iih; 5379126258Smlaier 5380126258Smlaier if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, 5381145836Smlaier NULL, reason, pd2.af)) { 5382126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5383126258Smlaier ("pf: ICMP error message too short i" 5384126258Smlaier "(icmp)\n")); 5385126258Smlaier return (PF_DROP); 5386126258Smlaier } 5387126258Smlaier 5388126258Smlaier key.af = pd2.af; 5389126258Smlaier key.proto = IPPROTO_ICMP; 5390223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5391223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5392223637Sbz key.port[0] = key.port[1] = iih.icmp_id; 5393126258Smlaier 5394223637Sbz#ifdef __FreeBSD__ 5395223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5396223637Sbz#else 5397223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5398223637Sbz#endif 5399126258Smlaier 5400223637Sbz /* translate source/destination address, if necessary */ 5401223637Sbz if ((*state)->key[PF_SK_WIRE] != 5402223637Sbz (*state)->key[PF_SK_STACK]) { 5403223637Sbz struct pf_state_key *nk = 5404223637Sbz (*state)->key[pd->didx]; 5405223637Sbz 5406223637Sbz if (PF_ANEQ(pd2.src, 5407223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5408223637Sbz nk->port[pd2.sidx] != iih.icmp_id) 5409126258Smlaier pf_change_icmp(pd2.src, &iih.icmp_id, 5410223637Sbz daddr, &nk->addr[pd2.sidx], 5411223637Sbz nk->port[pd2.sidx], NULL, 5412126258Smlaier pd2.ip_sum, icmpsum, 5413126258Smlaier pd->ip_sum, 0, AF_INET); 5414223637Sbz 5415223637Sbz if (PF_ANEQ(pd2.dst, 5416223637Sbz &nk->addr[pd2.didx], pd2.af) || 5417223637Sbz nk->port[pd2.didx] != iih.icmp_id) 5418126258Smlaier pf_change_icmp(pd2.dst, &iih.icmp_id, 5419223637Sbz NULL, /* XXX Inbound NAT? */ 5420223637Sbz &nk->addr[pd2.didx], 5421223637Sbz nk->port[pd2.didx], NULL, 5422126258Smlaier pd2.ip_sum, icmpsum, 5423126258Smlaier pd->ip_sum, 0, AF_INET); 5424223637Sbz 5425223637Sbz#ifdef __FreeBSD__ 5426223637Sbz m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); 5427223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5428223637Sbz m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih); 5429223637Sbz#else 5430223637Sbz m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); 5431223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5432223637Sbz m_copyback(m, off2, ICMP_MINLEN, &iih); 5433223637Sbz#endif 5434126258Smlaier } 5435126258Smlaier return (PF_PASS); 5436126258Smlaier break; 5437126258Smlaier } 5438126258Smlaier#endif /* INET */ 5439126258Smlaier#ifdef INET6 5440126258Smlaier case IPPROTO_ICMPV6: { 5441126258Smlaier struct icmp6_hdr iih; 5442126258Smlaier 5443126258Smlaier if (!pf_pull_hdr(m, off2, &iih, 5444145836Smlaier sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) { 5445126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 5446126258Smlaier ("pf: ICMP error message too short " 5447126258Smlaier "(icmp6)\n")); 5448126258Smlaier return (PF_DROP); 5449126258Smlaier } 5450126258Smlaier 5451126258Smlaier key.af = pd2.af; 5452126258Smlaier key.proto = IPPROTO_ICMPV6; 5453223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5454223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5455223637Sbz key.port[0] = key.port[1] = iih.icmp6_id; 5456126258Smlaier 5457223637Sbz#ifdef __FreeBSD__ 5458223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5459223637Sbz#else 5460223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5461223637Sbz#endif 5462126258Smlaier 5463223637Sbz /* translate source/destination address, if necessary */ 5464223637Sbz if ((*state)->key[PF_SK_WIRE] != 5465223637Sbz (*state)->key[PF_SK_STACK]) { 5466223637Sbz struct pf_state_key *nk = 5467223637Sbz (*state)->key[pd->didx]; 5468223637Sbz 5469223637Sbz if (PF_ANEQ(pd2.src, 5470223637Sbz &nk->addr[pd2.sidx], pd2.af) || 5471223637Sbz nk->port[pd2.sidx] != iih.icmp6_id) 5472126258Smlaier pf_change_icmp(pd2.src, &iih.icmp6_id, 5473223637Sbz daddr, &nk->addr[pd2.sidx], 5474223637Sbz nk->port[pd2.sidx], NULL, 5475126258Smlaier pd2.ip_sum, icmpsum, 5476126258Smlaier pd->ip_sum, 0, AF_INET6); 5477223637Sbz 5478223637Sbz if (PF_ANEQ(pd2.dst, 5479223637Sbz &nk->addr[pd2.didx], pd2.af) || 5480223637Sbz nk->port[pd2.didx] != iih.icmp6_id) 5481126258Smlaier pf_change_icmp(pd2.dst, &iih.icmp6_id, 5482223637Sbz NULL, /* XXX Inbound NAT? */ 5483223637Sbz &nk->addr[pd2.didx], 5484223637Sbz nk->port[pd2.didx], NULL, 5485126258Smlaier pd2.ip_sum, icmpsum, 5486126258Smlaier pd->ip_sum, 0, AF_INET6); 5487223637Sbz 5488223637Sbz#ifdef __FreeBSD__ 5489126258Smlaier m_copyback(m, off, sizeof(struct icmp6_hdr), 5490126261Smlaier (caddr_t)pd->hdr.icmp6); 5491223637Sbz m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6); 5492126258Smlaier m_copyback(m, off2, sizeof(struct icmp6_hdr), 5493126261Smlaier (caddr_t)&iih); 5494223637Sbz#else 5495223637Sbz m_copyback(m, off, sizeof(struct icmp6_hdr), 5496223637Sbz pd->hdr.icmp6); 5497223637Sbz m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); 5498223637Sbz m_copyback(m, off2, sizeof(struct icmp6_hdr), 5499223637Sbz &iih); 5500223637Sbz#endif 5501126258Smlaier } 5502126258Smlaier return (PF_PASS); 5503126258Smlaier break; 5504126258Smlaier } 5505126258Smlaier#endif /* INET6 */ 5506126258Smlaier default: { 5507126258Smlaier key.af = pd2.af; 5508126258Smlaier key.proto = pd2.proto; 5509223637Sbz PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); 5510223637Sbz PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); 5511223637Sbz key.port[0] = key.port[1] = 0; 5512126258Smlaier 5513223637Sbz#ifdef __FreeBSD__ 5514223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5515223637Sbz#else 5516223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5517223637Sbz#endif 5518126258Smlaier 5519223637Sbz /* translate source/destination address, if necessary */ 5520223637Sbz if ((*state)->key[PF_SK_WIRE] != 5521223637Sbz (*state)->key[PF_SK_STACK]) { 5522223637Sbz struct pf_state_key *nk = 5523223637Sbz (*state)->key[pd->didx]; 5524223637Sbz 5525223637Sbz if (PF_ANEQ(pd2.src, 5526223637Sbz &nk->addr[pd2.sidx], pd2.af)) 5527223637Sbz pf_change_icmp(pd2.src, NULL, daddr, 5528223637Sbz &nk->addr[pd2.sidx], 0, NULL, 5529126258Smlaier pd2.ip_sum, icmpsum, 5530126258Smlaier pd->ip_sum, 0, pd2.af); 5531223637Sbz 5532223637Sbz if (PF_ANEQ(pd2.dst, 5533223637Sbz &nk->addr[pd2.didx], pd2.af)) 5534223637Sbz pf_change_icmp(pd2.src, NULL, 5535223637Sbz NULL, /* XXX Inbound NAT? */ 5536223637Sbz &nk->addr[pd2.didx], 0, NULL, 5537126258Smlaier pd2.ip_sum, icmpsum, 5538126258Smlaier pd->ip_sum, 0, pd2.af); 5539223637Sbz 5540126258Smlaier switch (pd2.af) { 5541126258Smlaier#ifdef INET 5542126258Smlaier case AF_INET: 5543223637Sbz#ifdef __FreeBSD__ 5544126258Smlaier m_copyback(m, off, ICMP_MINLEN, 5545126261Smlaier (caddr_t)pd->hdr.icmp); 5546223637Sbz m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); 5547223637Sbz#else 5548223637Sbz m_copyback(m, off, ICMP_MINLEN, 5549223637Sbz pd->hdr.icmp); 5550223637Sbz m_copyback(m, ipoff2, sizeof(h2), &h2); 5551223637Sbz#endif 5552126258Smlaier break; 5553126258Smlaier#endif /* INET */ 5554126258Smlaier#ifdef INET6 5555126258Smlaier case AF_INET6: 5556126258Smlaier m_copyback(m, off, 5557126258Smlaier sizeof(struct icmp6_hdr), 5558223637Sbz#ifdef __FreeBSD__ 5559223637Sbz (caddr_t) 5560223637Sbz#endif 5561223637Sbz pd->hdr.icmp6); 5562126258Smlaier m_copyback(m, ipoff2, sizeof(h2_6), 5563223637Sbz#ifdef __FreeBSD__ 5564223637Sbz (caddr_t) 5565223637Sbz#endif 5566223637Sbz &h2_6); 5567126258Smlaier break; 5568126258Smlaier#endif /* INET6 */ 5569126258Smlaier } 5570126258Smlaier } 5571126258Smlaier return (PF_PASS); 5572126258Smlaier break; 5573126258Smlaier } 5574126258Smlaier } 5575126258Smlaier } 5576126258Smlaier} 5577126258Smlaier 5578126258Smlaierint 5579130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, 5580223637Sbz struct mbuf *m, struct pf_pdesc *pd) 5581126258Smlaier{ 5582126258Smlaier struct pf_state_peer *src, *dst; 5583223637Sbz struct pf_state_key_cmp key; 5584126258Smlaier 5585126258Smlaier key.af = pd->af; 5586126258Smlaier key.proto = pd->proto; 5587130613Smlaier if (direction == PF_IN) { 5588223637Sbz PF_ACPY(&key.addr[0], pd->src, key.af); 5589223637Sbz PF_ACPY(&key.addr[1], pd->dst, key.af); 5590223637Sbz key.port[0] = key.port[1] = 0; 5591130613Smlaier } else { 5592223637Sbz PF_ACPY(&key.addr[1], pd->src, key.af); 5593223637Sbz PF_ACPY(&key.addr[0], pd->dst, key.af); 5594223637Sbz key.port[1] = key.port[0] = 0; 5595130613Smlaier } 5596126258Smlaier 5597223637Sbz#ifdef __FreeBSD__ 5598223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); 5599223637Sbz#else 5600223637Sbz STATE_LOOKUP(kif, &key, direction, *state, m); 5601223637Sbz#endif 5602126258Smlaier 5603126258Smlaier if (direction == (*state)->direction) { 5604126258Smlaier src = &(*state)->src; 5605126258Smlaier dst = &(*state)->dst; 5606126258Smlaier } else { 5607126258Smlaier src = &(*state)->dst; 5608126258Smlaier dst = &(*state)->src; 5609126258Smlaier } 5610126258Smlaier 5611126258Smlaier /* update states */ 5612126258Smlaier if (src->state < PFOTHERS_SINGLE) 5613126258Smlaier src->state = PFOTHERS_SINGLE; 5614126258Smlaier if (dst->state == PFOTHERS_SINGLE) 5615126258Smlaier dst->state = PFOTHERS_MULTIPLE; 5616126258Smlaier 5617126258Smlaier /* update expire time */ 5618126261Smlaier (*state)->expire = time_second; 5619126258Smlaier if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE) 5620126258Smlaier (*state)->timeout = PFTM_OTHER_MULTIPLE; 5621126258Smlaier else 5622126258Smlaier (*state)->timeout = PFTM_OTHER_SINGLE; 5623126258Smlaier 5624126258Smlaier /* translate source/destination address, if necessary */ 5625223637Sbz if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { 5626223637Sbz struct pf_state_key *nk = (*state)->key[pd->didx]; 5627223637Sbz 5628223637Sbz#ifdef __FreeBSD__ 5629223637Sbz KASSERT(nk, ("%s: nk is null", __FUNCTION__)); 5630223637Sbz KASSERT(pd, ("%s: pd is null", __FUNCTION__)); 5631223637Sbz KASSERT(pd->src, ("%s: pd->src is null", __FUNCTION__)); 5632223637Sbz KASSERT(pd->dst, ("%s: pd->dst is null", __FUNCTION__)); 5633223637Sbz#else 5634223637Sbz KASSERT(nk); 5635223637Sbz KASSERT(pd); 5636223637Sbz KASSERT(pd->src); 5637223637Sbz KASSERT(pd->dst); 5638223637Sbz#endif 5639223637Sbz switch (pd->af) { 5640126258Smlaier#ifdef INET 5641223637Sbz case AF_INET: 5642223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) 5643126258Smlaier pf_change_a(&pd->src->v4.s_addr, 5644223637Sbz pd->ip_sum, 5645223637Sbz nk->addr[pd->sidx].v4.s_addr, 5646126258Smlaier 0); 5647223637Sbz 5648223637Sbz 5649223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) 5650126258Smlaier pf_change_a(&pd->dst->v4.s_addr, 5651223637Sbz pd->ip_sum, 5652223637Sbz nk->addr[pd->didx].v4.s_addr, 5653126258Smlaier 0); 5654223637Sbz 5655126258Smlaier break; 5656126258Smlaier#endif /* INET */ 5657126258Smlaier#ifdef INET6 5658223637Sbz case AF_INET6: 5659223637Sbz if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) 5660223637Sbz PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); 5661223637Sbz 5662223637Sbz if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) 5663223637Sbz PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); 5664126258Smlaier#endif /* INET6 */ 5665223637Sbz } 5666126258Smlaier } 5667126258Smlaier return (PF_PASS); 5668126258Smlaier} 5669126258Smlaier 5670126258Smlaier/* 5671126258Smlaier * ipoff and off are measured from the start of the mbuf chain. 5672126258Smlaier * h must be at "ipoff" on the mbuf chain. 5673126258Smlaier */ 5674126258Smlaiervoid * 5675126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len, 5676126258Smlaier u_short *actionp, u_short *reasonp, sa_family_t af) 5677126258Smlaier{ 5678126258Smlaier switch (af) { 5679126258Smlaier#ifdef INET 5680126258Smlaier case AF_INET: { 5681126258Smlaier struct ip *h = mtod(m, struct ip *); 5682126258Smlaier u_int16_t fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3; 5683126258Smlaier 5684126258Smlaier if (fragoff) { 5685126258Smlaier if (fragoff >= len) 5686126258Smlaier ACTION_SET(actionp, PF_PASS); 5687126258Smlaier else { 5688126258Smlaier ACTION_SET(actionp, PF_DROP); 5689126258Smlaier REASON_SET(reasonp, PFRES_FRAG); 5690126258Smlaier } 5691126258Smlaier return (NULL); 5692126258Smlaier } 5693130613Smlaier if (m->m_pkthdr.len < off + len || 5694130613Smlaier ntohs(h->ip_len) < off + len) { 5695126258Smlaier ACTION_SET(actionp, PF_DROP); 5696126258Smlaier REASON_SET(reasonp, PFRES_SHORT); 5697126258Smlaier return (NULL); 5698126258Smlaier } 5699126258Smlaier break; 5700126258Smlaier } 5701126258Smlaier#endif /* INET */ 5702126258Smlaier#ifdef INET6 5703126258Smlaier case AF_INET6: { 5704126258Smlaier struct ip6_hdr *h = mtod(m, struct ip6_hdr *); 5705126258Smlaier 5706126258Smlaier if (m->m_pkthdr.len < off + len || 5707126258Smlaier (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) < 5708126258Smlaier (unsigned)(off + len)) { 5709126258Smlaier ACTION_SET(actionp, PF_DROP); 5710126258Smlaier REASON_SET(reasonp, PFRES_SHORT); 5711126258Smlaier return (NULL); 5712126258Smlaier } 5713126258Smlaier break; 5714126258Smlaier } 5715126258Smlaier#endif /* INET6 */ 5716126258Smlaier } 5717126258Smlaier m_copydata(m, off, len, p); 5718126258Smlaier return (p); 5719126258Smlaier} 5720126258Smlaier 5721126258Smlaierint 5722232292Sbzpf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif, 5723232292Sbz int rtableid) 5724126258Smlaier{ 5725223637Sbz#ifdef __FreeBSD__ 5726223637Sbz#ifdef RADIX_MPATH 5727223637Sbz struct radix_node_head *rnh; 5728223637Sbz#endif 5729223637Sbz#endif 5730126258Smlaier struct sockaddr_in *dst; 5731171168Smlaier int ret = 1; 5732171168Smlaier int check_mpath; 5733171168Smlaier#ifndef __FreeBSD__ 5734171168Smlaier extern int ipmultipath; 5735171168Smlaier#endif 5736145836Smlaier#ifdef INET6 5737171168Smlaier#ifndef __FreeBSD__ 5738171168Smlaier extern int ip6_multipath; 5739171168Smlaier#endif 5740145836Smlaier struct sockaddr_in6 *dst6; 5741145836Smlaier struct route_in6 ro; 5742145836Smlaier#else 5743126258Smlaier struct route ro; 5744145836Smlaier#endif 5745171168Smlaier struct radix_node *rn; 5746171168Smlaier struct rtentry *rt; 5747171168Smlaier struct ifnet *ifp; 5748126258Smlaier 5749171168Smlaier check_mpath = 0; 5750223637Sbz#ifdef __FreeBSD__ 5751223637Sbz#ifdef RADIX_MPATH 5752223637Sbz /* XXX: stick to table 0 for now */ 5753223637Sbz rnh = rt_tables_get_rnh(0, af); 5754223637Sbz if (rnh != NULL && rn_mpath_capable(rnh)) 5755223637Sbz check_mpath = 1; 5756223637Sbz#endif 5757223637Sbz#endif 5758126258Smlaier bzero(&ro, sizeof(ro)); 5759145836Smlaier switch (af) { 5760145836Smlaier case AF_INET: 5761145836Smlaier dst = satosin(&ro.ro_dst); 5762145836Smlaier dst->sin_family = AF_INET; 5763145836Smlaier dst->sin_len = sizeof(*dst); 5764145836Smlaier dst->sin_addr = addr->v4; 5765223637Sbz#ifndef __FreeBSD__ 5766171168Smlaier if (ipmultipath) 5767171168Smlaier check_mpath = 1; 5768171168Smlaier#endif 5769145836Smlaier break; 5770145836Smlaier#ifdef INET6 5771145836Smlaier case AF_INET6: 5772223637Sbz /* 5773223637Sbz * Skip check for addresses with embedded interface scope, 5774223637Sbz * as they would always match anyway. 5775223637Sbz */ 5776223637Sbz if (IN6_IS_SCOPE_EMBED(&addr->v6)) 5777223637Sbz goto out; 5778145836Smlaier dst6 = (struct sockaddr_in6 *)&ro.ro_dst; 5779145836Smlaier dst6->sin6_family = AF_INET6; 5780145836Smlaier dst6->sin6_len = sizeof(*dst6); 5781145836Smlaier dst6->sin6_addr = addr->v6; 5782223637Sbz#ifndef __FreeBSD__ 5783171168Smlaier if (ip6_multipath) 5784171168Smlaier check_mpath = 1; 5785171168Smlaier#endif 5786145836Smlaier break; 5787145836Smlaier#endif /* INET6 */ 5788145836Smlaier default: 5789145836Smlaier return (0); 5790145836Smlaier } 5791145836Smlaier 5792171168Smlaier /* Skip checks for ipsec interfaces */ 5793171168Smlaier if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC) 5794171168Smlaier goto out; 5795171168Smlaier 5796127145Smlaier#ifdef __FreeBSD__ 5797232292Sbz switch (af) { 5798232292Sbz#ifdef INET6 5799232292Sbz case AF_INET6: 5800232292Sbz in6_rtalloc_ign(&ro, 0, rtableid); 5801232292Sbz break; 5802232292Sbz#endif 5803222529Sbz#ifdef INET 5804232292Sbz case AF_INET: 5805232292Sbz in_rtalloc_ign((struct route *)&ro, 0, rtableid); 5806232292Sbz break; 5807222529Sbz#endif 5808232292Sbz default: 5809232292Sbz rtalloc_ign((struct route *)&ro, 0); /* No/default FIB. */ 5810232292Sbz break; 5811232292Sbz } 5812126261Smlaier#else /* ! __FreeBSD__ */ 5813145836Smlaier rtalloc_noclone((struct route *)&ro, NO_CLONING); 5814126261Smlaier#endif 5815126258Smlaier 5816126258Smlaier if (ro.ro_rt != NULL) { 5817171168Smlaier /* No interface given, this is a no-route check */ 5818171168Smlaier if (kif == NULL) 5819171168Smlaier goto out; 5820171168Smlaier 5821171168Smlaier if (kif->pfik_ifp == NULL) { 5822171168Smlaier ret = 0; 5823171168Smlaier goto out; 5824171168Smlaier } 5825171168Smlaier 5826171168Smlaier /* Perform uRPF check if passed input interface */ 5827171168Smlaier ret = 0; 5828171168Smlaier rn = (struct radix_node *)ro.ro_rt; 5829171168Smlaier do { 5830171168Smlaier rt = (struct rtentry *)rn; 5831171168Smlaier#ifndef __FreeBSD__ /* CARPDEV */ 5832171168Smlaier if (rt->rt_ifp->if_type == IFT_CARP) 5833171168Smlaier ifp = rt->rt_ifp->if_carpdev; 5834171168Smlaier else 5835171168Smlaier#endif 5836171168Smlaier ifp = rt->rt_ifp; 5837171168Smlaier 5838171168Smlaier if (kif->pfik_ifp == ifp) 5839171168Smlaier ret = 1; 5840223637Sbz#ifdef __FreeBSD__ 5841223637Sbz#ifdef RADIX_MPATH 5842171168Smlaier rn = rn_mpath_next(rn); 5843171168Smlaier#endif 5844223637Sbz#else 5845223637Sbz rn = rn_mpath_next(rn, 0); 5846223637Sbz#endif 5847171168Smlaier } while (check_mpath == 1 && rn != NULL && ret == 0); 5848171168Smlaier } else 5849171168Smlaier ret = 0; 5850171168Smlaierout: 5851171168Smlaier if (ro.ro_rt != NULL) 5852126258Smlaier RTFREE(ro.ro_rt); 5853171168Smlaier return (ret); 5854145836Smlaier} 5855145836Smlaier 5856145836Smlaierint 5857232292Sbzpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw, 5858232292Sbz int rtableid) 5859145836Smlaier{ 5860145836Smlaier struct sockaddr_in *dst; 5861145836Smlaier#ifdef INET6 5862145836Smlaier struct sockaddr_in6 *dst6; 5863145836Smlaier struct route_in6 ro; 5864145836Smlaier#else 5865145836Smlaier struct route ro; 5866145836Smlaier#endif 5867145836Smlaier int ret = 0; 5868145836Smlaier 5869145836Smlaier bzero(&ro, sizeof(ro)); 5870145836Smlaier switch (af) { 5871145836Smlaier case AF_INET: 5872145836Smlaier dst = satosin(&ro.ro_dst); 5873145836Smlaier dst->sin_family = AF_INET; 5874145836Smlaier dst->sin_len = sizeof(*dst); 5875145836Smlaier dst->sin_addr = addr->v4; 5876145836Smlaier break; 5877145836Smlaier#ifdef INET6 5878145836Smlaier case AF_INET6: 5879145836Smlaier dst6 = (struct sockaddr_in6 *)&ro.ro_dst; 5880145836Smlaier dst6->sin6_family = AF_INET6; 5881145836Smlaier dst6->sin6_len = sizeof(*dst6); 5882145836Smlaier dst6->sin6_addr = addr->v6; 5883145836Smlaier break; 5884145836Smlaier#endif /* INET6 */ 5885145836Smlaier default: 5886145836Smlaier return (0); 5887145836Smlaier } 5888145836Smlaier 5889145836Smlaier#ifdef __FreeBSD__ 5890232292Sbz switch (af) { 5891232292Sbz#ifdef INET6 5892232292Sbz case AF_INET6: 5893232292Sbz in6_rtalloc_ign(&ro, 0, rtableid); 5894232292Sbz break; 5895232292Sbz#endif 5896222529Sbz#ifdef INET 5897232292Sbz case AF_INET: 5898232292Sbz in_rtalloc_ign((struct route *)&ro, 0, rtableid); 5899232292Sbz break; 5900222529Sbz#endif 5901232292Sbz default: 5902186119Sqingli rtalloc_ign((struct route *)&ro, 0); 5903232292Sbz break; 5904232292Sbz } 5905145836Smlaier#else /* ! __FreeBSD__ */ 5906145836Smlaier rtalloc_noclone((struct route *)&ro, NO_CLONING); 5907145836Smlaier#endif 5908145836Smlaier 5909145836Smlaier if (ro.ro_rt != NULL) { 5910145836Smlaier#ifdef __FreeBSD__ 5911145836Smlaier /* XXX_IMPORT: later */ 5912145836Smlaier#else 5913145836Smlaier if (ro.ro_rt->rt_labelid == aw->v.rtlabel) 5914145836Smlaier ret = 1; 5915145836Smlaier#endif 5916145836Smlaier RTFREE(ro.ro_rt); 5917145836Smlaier } 5918145836Smlaier 5919126258Smlaier return (ret); 5920126258Smlaier} 5921126258Smlaier 5922126258Smlaier#ifdef INET 5923126258Smlaiervoid 5924126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 5925171168Smlaier struct pf_state *s, struct pf_pdesc *pd) 5926126258Smlaier{ 5927126258Smlaier struct mbuf *m0, *m1; 5928126258Smlaier struct route iproute; 5929171168Smlaier struct route *ro = NULL; 5930126258Smlaier struct sockaddr_in *dst; 5931126258Smlaier struct ip *ip; 5932126258Smlaier struct ifnet *ifp = NULL; 5933126258Smlaier struct pf_addr naddr; 5934130613Smlaier struct pf_src_node *sn = NULL; 5935126258Smlaier int error = 0; 5936127145Smlaier#ifdef __FreeBSD__ 5937126261Smlaier int sw_csum; 5938126261Smlaier#endif 5939171168Smlaier#ifdef IPSEC 5940171168Smlaier struct m_tag *mtag; 5941171168Smlaier#endif /* IPSEC */ 5942126258Smlaier 5943126258Smlaier if (m == NULL || *m == NULL || r == NULL || 5944126258Smlaier (dir != PF_IN && dir != PF_OUT) || oifp == NULL) 5945126258Smlaier panic("pf_route: invalid parameters"); 5946126258Smlaier 5947223637Sbz#ifdef __FreeBSD__ 5948171168Smlaier if (pd->pf_mtag->routed++ > 3) { 5949223637Sbz#else 5950223637Sbz if ((*m)->m_pkthdr.pf.routed++ > 3) { 5951223637Sbz#endif 5952171168Smlaier m0 = *m; 5953171168Smlaier *m = NULL; 5954171168Smlaier goto bad; 5955132303Smlaier } 5956132303Smlaier 5957126258Smlaier if (r->rt == PF_DUPTO) { 5958127145Smlaier#ifdef __FreeBSD__ 5959132303Smlaier if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) 5960126261Smlaier#else 5961132303Smlaier if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) 5962126261Smlaier#endif 5963126258Smlaier return; 5964126258Smlaier } else { 5965126258Smlaier if ((r->rt == PF_REPLYTO) == (r->direction == dir)) 5966126258Smlaier return; 5967126258Smlaier m0 = *m; 5968126258Smlaier } 5969126258Smlaier 5970145836Smlaier if (m0->m_len < sizeof(struct ip)) { 5971145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 5972145836Smlaier ("pf_route: m0->m_len < sizeof(struct ip)\n")); 5973145836Smlaier goto bad; 5974145836Smlaier } 5975145836Smlaier 5976126258Smlaier ip = mtod(m0, struct ip *); 5977126258Smlaier 5978126258Smlaier ro = &iproute; 5979126258Smlaier bzero((caddr_t)ro, sizeof(*ro)); 5980126258Smlaier dst = satosin(&ro->ro_dst); 5981126258Smlaier dst->sin_family = AF_INET; 5982126258Smlaier dst->sin_len = sizeof(*dst); 5983126258Smlaier dst->sin_addr = ip->ip_dst; 5984126258Smlaier 5985126258Smlaier if (r->rt == PF_FASTROUTE) { 5986223637Sbz#ifdef __FreeBSD__ 5987232292Sbz in_rtalloc_ign(ro, 0, M_GETFIB(m0)); 5988223637Sbz#else 5989223637Sbz rtalloc(ro); 5990223637Sbz#endif 5991126258Smlaier if (ro->ro_rt == 0) { 5992223637Sbz#ifdef __FreeBSD__ 5993196039Srwatson KMOD_IPSTAT_INC(ips_noroute); 5994223637Sbz#else 5995223637Sbz ipstat.ips_noroute++; 5996223637Sbz#endif 5997126258Smlaier goto bad; 5998126258Smlaier } 5999126258Smlaier 6000126258Smlaier ifp = ro->ro_rt->rt_ifp; 6001126258Smlaier ro->ro_rt->rt_use++; 6002126258Smlaier 6003126258Smlaier if (ro->ro_rt->rt_flags & RTF_GATEWAY) 6004126258Smlaier dst = satosin(ro->ro_rt->rt_gateway); 6005126258Smlaier } else { 6006145836Smlaier if (TAILQ_EMPTY(&r->rpool.list)) { 6007145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6008145836Smlaier ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n")); 6009145836Smlaier goto bad; 6010145836Smlaier } 6011126258Smlaier if (s == NULL) { 6012130613Smlaier pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src, 6013130613Smlaier &naddr, NULL, &sn); 6014126258Smlaier if (!PF_AZERO(&naddr, AF_INET)) 6015126258Smlaier dst->sin_addr.s_addr = naddr.v4.s_addr; 6016130613Smlaier ifp = r->rpool.cur->kif ? 6017130613Smlaier r->rpool.cur->kif->pfik_ifp : NULL; 6018126258Smlaier } else { 6019126258Smlaier if (!PF_AZERO(&s->rt_addr, AF_INET)) 6020126258Smlaier dst->sin_addr.s_addr = 6021126258Smlaier s->rt_addr.v4.s_addr; 6022130613Smlaier ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; 6023126258Smlaier } 6024126258Smlaier } 6025126258Smlaier if (ifp == NULL) 6026126258Smlaier goto bad; 6027126258Smlaier 6028130639Smlaier if (oifp != ifp) { 6029127145Smlaier#ifdef __FreeBSD__ 6030126261Smlaier PF_UNLOCK(); 6031145836Smlaier if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { 6032126261Smlaier PF_LOCK(); 6033126261Smlaier goto bad; 6034126261Smlaier } else if (m0 == NULL) { 6035126261Smlaier PF_LOCK(); 6036126261Smlaier goto done; 6037126261Smlaier } 6038126261Smlaier PF_LOCK(); 6039126261Smlaier#else 6040145836Smlaier if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) 6041126258Smlaier goto bad; 6042126258Smlaier else if (m0 == NULL) 6043126258Smlaier goto done; 6044126261Smlaier#endif 6045145836Smlaier if (m0->m_len < sizeof(struct ip)) { 6046145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6047145836Smlaier ("pf_route: m0->m_len < sizeof(struct ip)\n")); 6048145836Smlaier goto bad; 6049145836Smlaier } 6050126258Smlaier ip = mtod(m0, struct ip *); 6051126258Smlaier } 6052126258Smlaier 6053127145Smlaier#ifdef __FreeBSD__ 6054126261Smlaier /* Copied from FreeBSD 5.1-CURRENT ip_output. */ 6055126261Smlaier m0->m_pkthdr.csum_flags |= CSUM_IP; 6056126261Smlaier sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist; 6057126261Smlaier if (sw_csum & CSUM_DELAY_DATA) { 6058126261Smlaier /* 6059126261Smlaier * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least) 6060126261Smlaier */ 6061126261Smlaier NTOHS(ip->ip_len); 6062223637Sbz NTOHS(ip->ip_off); /* XXX: needed? */ 6063126261Smlaier in_delayed_cksum(m0); 6064126261Smlaier HTONS(ip->ip_len); 6065126261Smlaier HTONS(ip->ip_off); 6066126261Smlaier sw_csum &= ~CSUM_DELAY_DATA; 6067126261Smlaier } 6068126261Smlaier m0->m_pkthdr.csum_flags &= ifp->if_hwassist; 6069126261Smlaier 6070126261Smlaier if (ntohs(ip->ip_len) <= ifp->if_mtu || 6071126261Smlaier (ifp->if_hwassist & CSUM_FRAGMENT && 6072223637Sbz ((ip->ip_off & htons(IP_DF)) == 0))) { 6073126261Smlaier /* 6074126261Smlaier * ip->ip_len = htons(ip->ip_len); 6075126261Smlaier * ip->ip_off = htons(ip->ip_off); 6076126261Smlaier */ 6077126261Smlaier ip->ip_sum = 0; 6078126261Smlaier if (sw_csum & CSUM_DELAY_IP) { 6079126261Smlaier /* From KAME */ 6080126261Smlaier if (ip->ip_v == IPVERSION && 6081126261Smlaier (ip->ip_hl << 2) == sizeof(*ip)) { 6082126261Smlaier ip->ip_sum = in_cksum_hdr(ip); 6083126261Smlaier } else { 6084126261Smlaier ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); 6085126261Smlaier } 6086126261Smlaier } 6087126261Smlaier PF_UNLOCK(); 6088191148Skmacy error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro); 6089126261Smlaier PF_LOCK(); 6090126261Smlaier goto done; 6091126261Smlaier } 6092126261Smlaier#else 6093126258Smlaier /* Copied from ip_output. */ 6094130613Smlaier#ifdef IPSEC 6095130613Smlaier /* 6096130613Smlaier * If deferred crypto processing is needed, check that the 6097130613Smlaier * interface supports it. 6098130613Smlaier */ 6099130613Smlaier if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL)) 6100130613Smlaier != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) { 6101130613Smlaier /* Notify IPsec to do its own crypto. */ 6102130613Smlaier ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1)); 6103130613Smlaier goto bad; 6104130613Smlaier } 6105130613Smlaier#endif /* IPSEC */ 6106130613Smlaier 6107130613Smlaier /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */ 6108171168Smlaier if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) { 6109130613Smlaier if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || 6110130613Smlaier ifp->if_bridge != NULL) { 6111130613Smlaier in_delayed_cksum(m0); 6112223637Sbz m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clr */ 6113130613Smlaier } 6114171168Smlaier } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) { 6115130613Smlaier if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) || 6116130613Smlaier ifp->if_bridge != NULL) { 6117130613Smlaier in_delayed_cksum(m0); 6118223637Sbz m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clr */ 6119130613Smlaier } 6120130613Smlaier } 6121130613Smlaier 6122126258Smlaier if (ntohs(ip->ip_len) <= ifp->if_mtu) { 6123223637Sbz ip->ip_sum = 0; 6124126258Smlaier if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && 6125126258Smlaier ifp->if_bridge == NULL) { 6126171168Smlaier m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; 6127223637Sbz#ifdef __FreeBSD__ 6128196039Srwatson KMOD_IPSTAT_INC(ips_outhwcsum); 6129223637Sbz#else 6130223637Sbz ipstat.ips_outhwcsum++; 6131223637Sbz#endif 6132223637Sbz } else 6133126258Smlaier ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); 6134126258Smlaier /* Update relevant hardware checksum stats for TCP/UDP */ 6135171168Smlaier if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) 6136196039Srwatson KMOD_TCPSTAT_INC(tcps_outhwcsum); 6137171168Smlaier else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) 6138196039Srwatson KMOD_UDPSTAT_INC(udps_outhwcsum); 6139126258Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL); 6140126258Smlaier goto done; 6141126258Smlaier } 6142126261Smlaier#endif 6143223637Sbz 6144126258Smlaier /* 6145126258Smlaier * Too large for interface; fragment if possible. 6146126258Smlaier * Must be able to put at least 8 bytes per fragment. 6147126258Smlaier */ 6148223637Sbz if (ip->ip_off & htons(IP_DF)) { 6149223637Sbz#ifdef __FreeBSD__ 6150196039Srwatson KMOD_IPSTAT_INC(ips_cantfrag); 6151223637Sbz#else 6152223637Sbz ipstat.ips_cantfrag++; 6153223637Sbz#endif 6154126258Smlaier if (r->rt != PF_DUPTO) { 6155127145Smlaier#ifdef __FreeBSD__ 6156126261Smlaier /* icmp_error() expects host byte ordering */ 6157126261Smlaier NTOHS(ip->ip_len); 6158126261Smlaier NTOHS(ip->ip_off); 6159126261Smlaier PF_UNLOCK(); 6160126258Smlaier icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, 6161145886Smlaier ifp->if_mtu); 6162145874Smlaier PF_LOCK(); 6163145874Smlaier#else 6164145874Smlaier icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, 6165171168Smlaier ifp->if_mtu); 6166126261Smlaier#endif 6167126258Smlaier goto done; 6168126258Smlaier } else 6169126258Smlaier goto bad; 6170126258Smlaier } 6171126258Smlaier 6172126258Smlaier m1 = m0; 6173127145Smlaier#ifdef __FreeBSD__ 6174126261Smlaier /* 6175126261Smlaier * XXX: is cheaper + less error prone than own function 6176126261Smlaier */ 6177126261Smlaier NTOHS(ip->ip_len); 6178126261Smlaier NTOHS(ip->ip_off); 6179126261Smlaier error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum); 6180126261Smlaier#else 6181126258Smlaier error = ip_fragment(m0, ifp, ifp->if_mtu); 6182126261Smlaier#endif 6183127531Smlaier if (error) { 6184223637Sbz#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ 6185127531Smlaier m0 = NULL; 6186126261Smlaier#endif 6187126258Smlaier goto bad; 6188127531Smlaier } 6189126258Smlaier 6190126258Smlaier for (m0 = m1; m0; m0 = m1) { 6191126258Smlaier m1 = m0->m_nextpkt; 6192126258Smlaier m0->m_nextpkt = 0; 6193127145Smlaier#ifdef __FreeBSD__ 6194126261Smlaier if (error == 0) { 6195126261Smlaier PF_UNLOCK(); 6196126261Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), 6197126261Smlaier NULL); 6198126261Smlaier PF_LOCK(); 6199126261Smlaier } else 6200126261Smlaier#else 6201126258Smlaier if (error == 0) 6202126258Smlaier error = (*ifp->if_output)(ifp, m0, sintosa(dst), 6203126258Smlaier NULL); 6204126258Smlaier else 6205126261Smlaier#endif 6206126258Smlaier m_freem(m0); 6207126258Smlaier } 6208126258Smlaier 6209126258Smlaier if (error == 0) 6210223637Sbz#ifdef __FreeBSD__ 6211196039Srwatson KMOD_IPSTAT_INC(ips_fragmented); 6212223637Sbz#else 6213223637Sbz ipstat.ips_fragmented++; 6214223637Sbz#endif 6215126258Smlaier 6216126258Smlaierdone: 6217126258Smlaier if (r->rt != PF_DUPTO) 6218126258Smlaier *m = NULL; 6219126258Smlaier if (ro == &iproute && ro->ro_rt) 6220126258Smlaier RTFREE(ro->ro_rt); 6221126258Smlaier return; 6222126258Smlaier 6223126258Smlaierbad: 6224126258Smlaier m_freem(m0); 6225126258Smlaier goto done; 6226126258Smlaier} 6227126258Smlaier#endif /* INET */ 6228126258Smlaier 6229126258Smlaier#ifdef INET6 6230126258Smlaiervoid 6231126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, 6232171168Smlaier struct pf_state *s, struct pf_pdesc *pd) 6233126258Smlaier{ 6234126258Smlaier struct mbuf *m0; 6235126258Smlaier struct route_in6 ip6route; 6236126258Smlaier struct route_in6 *ro; 6237126258Smlaier struct sockaddr_in6 *dst; 6238126258Smlaier struct ip6_hdr *ip6; 6239126258Smlaier struct ifnet *ifp = NULL; 6240126258Smlaier struct pf_addr naddr; 6241130613Smlaier struct pf_src_node *sn = NULL; 6242126258Smlaier 6243126258Smlaier if (m == NULL || *m == NULL || r == NULL || 6244126258Smlaier (dir != PF_IN && dir != PF_OUT) || oifp == NULL) 6245126258Smlaier panic("pf_route6: invalid parameters"); 6246126258Smlaier 6247223637Sbz#ifdef __FreeBSD__ 6248171168Smlaier if (pd->pf_mtag->routed++ > 3) { 6249223637Sbz#else 6250223637Sbz if ((*m)->m_pkthdr.pf.routed++ > 3) { 6251223637Sbz#endif 6252171168Smlaier m0 = *m; 6253171168Smlaier *m = NULL; 6254171168Smlaier goto bad; 6255132303Smlaier } 6256132303Smlaier 6257126258Smlaier if (r->rt == PF_DUPTO) { 6258127145Smlaier#ifdef __FreeBSD__ 6259132303Smlaier if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL) 6260126261Smlaier#else 6261132303Smlaier if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL) 6262126261Smlaier#endif 6263126258Smlaier return; 6264126258Smlaier } else { 6265126258Smlaier if ((r->rt == PF_REPLYTO) == (r->direction == dir)) 6266126258Smlaier return; 6267126258Smlaier m0 = *m; 6268126258Smlaier } 6269126258Smlaier 6270145836Smlaier if (m0->m_len < sizeof(struct ip6_hdr)) { 6271145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6272145836Smlaier ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); 6273145836Smlaier goto bad; 6274145836Smlaier } 6275126258Smlaier ip6 = mtod(m0, struct ip6_hdr *); 6276126258Smlaier 6277126258Smlaier ro = &ip6route; 6278126258Smlaier bzero((caddr_t)ro, sizeof(*ro)); 6279126258Smlaier dst = (struct sockaddr_in6 *)&ro->ro_dst; 6280126258Smlaier dst->sin6_family = AF_INET6; 6281126258Smlaier dst->sin6_len = sizeof(*dst); 6282126258Smlaier dst->sin6_addr = ip6->ip6_dst; 6283126258Smlaier 6284171168Smlaier /* Cheat. XXX why only in the v6 case??? */ 6285126258Smlaier if (r->rt == PF_FASTROUTE) { 6286127145Smlaier#ifdef __FreeBSD__ 6287132280Smlaier m0->m_flags |= M_SKIP_FIREWALL; 6288126261Smlaier PF_UNLOCK(); 6289126261Smlaier ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 6290126261Smlaier#else 6291223637Sbz m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 6292223637Sbz ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); 6293126261Smlaier#endif 6294126258Smlaier return; 6295126258Smlaier } 6296126258Smlaier 6297145836Smlaier if (TAILQ_EMPTY(&r->rpool.list)) { 6298145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6299145836Smlaier ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n")); 6300145836Smlaier goto bad; 6301145836Smlaier } 6302126258Smlaier if (s == NULL) { 6303130613Smlaier pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src, 6304130613Smlaier &naddr, NULL, &sn); 6305126258Smlaier if (!PF_AZERO(&naddr, AF_INET6)) 6306126258Smlaier PF_ACPY((struct pf_addr *)&dst->sin6_addr, 6307126258Smlaier &naddr, AF_INET6); 6308130613Smlaier ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL; 6309126258Smlaier } else { 6310126258Smlaier if (!PF_AZERO(&s->rt_addr, AF_INET6)) 6311126258Smlaier PF_ACPY((struct pf_addr *)&dst->sin6_addr, 6312126258Smlaier &s->rt_addr, AF_INET6); 6313130613Smlaier ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL; 6314126258Smlaier } 6315126258Smlaier if (ifp == NULL) 6316126258Smlaier goto bad; 6317126258Smlaier 6318126258Smlaier if (oifp != ifp) { 6319127145Smlaier#ifdef __FreeBSD__ 6320132303Smlaier PF_UNLOCK(); 6321145836Smlaier if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) { 6322126261Smlaier PF_LOCK(); 6323132303Smlaier goto bad; 6324132303Smlaier } else if (m0 == NULL) { 6325132303Smlaier PF_LOCK(); 6326132303Smlaier goto done; 6327132303Smlaier } 6328132303Smlaier PF_LOCK(); 6329126261Smlaier#else 6330145836Smlaier if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) 6331132303Smlaier goto bad; 6332132303Smlaier else if (m0 == NULL) 6333132303Smlaier goto done; 6334126261Smlaier#endif 6335145836Smlaier if (m0->m_len < sizeof(struct ip6_hdr)) { 6336145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6337145836Smlaier ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n")); 6338145836Smlaier goto bad; 6339145836Smlaier } 6340132303Smlaier ip6 = mtod(m0, struct ip6_hdr *); 6341126258Smlaier } 6342126258Smlaier 6343293896Sglebius if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 & 6344293896Sglebius ~ifp->if_hwassist) { 6345293896Sglebius uint32_t plen = m0->m_pkthdr.len - sizeof(*ip6); 6346293896Sglebius in6_delayed_cksum(m0, plen, sizeof(struct ip6_hdr)); 6347293896Sglebius m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 6348293896Sglebius } 6349293896Sglebius 6350126258Smlaier /* 6351126258Smlaier * If the packet is too large for the outgoing interface, 6352126258Smlaier * send back an icmp6 error. 6353126258Smlaier */ 6354171168Smlaier if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr)) 6355126258Smlaier dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index); 6356126258Smlaier if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { 6357127145Smlaier#ifdef __FreeBSD__ 6358126261Smlaier PF_UNLOCK(); 6359126261Smlaier#endif 6360223637Sbz nd6_output(ifp, ifp, m0, dst, NULL); 6361127145Smlaier#ifdef __FreeBSD__ 6362126261Smlaier PF_LOCK(); 6363126261Smlaier#endif 6364126258Smlaier } else { 6365126258Smlaier in6_ifstat_inc(ifp, ifs6_in_toobig); 6366127145Smlaier#ifdef __FreeBSD__ 6367126261Smlaier if (r->rt != PF_DUPTO) { 6368126261Smlaier PF_UNLOCK(); 6369126261Smlaier icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); 6370126261Smlaier PF_LOCK(); 6371223637Sbz } else 6372126261Smlaier#else 6373126258Smlaier if (r->rt != PF_DUPTO) 6374126258Smlaier icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); 6375126258Smlaier else 6376126261Smlaier#endif 6377126258Smlaier goto bad; 6378126258Smlaier } 6379126258Smlaier 6380126258Smlaierdone: 6381126258Smlaier if (r->rt != PF_DUPTO) 6382126258Smlaier *m = NULL; 6383126258Smlaier return; 6384126258Smlaier 6385126258Smlaierbad: 6386126258Smlaier m_freem(m0); 6387126258Smlaier goto done; 6388126258Smlaier} 6389126258Smlaier#endif /* INET6 */ 6390126258Smlaier 6391127145Smlaier#ifdef __FreeBSD__ 6392126258Smlaier/* 6393132566Smlaier * FreeBSD supports cksum offloads for the following drivers. 6394137413Sru * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4), 6395132566Smlaier * ti(4), txp(4), xl(4) 6396132566Smlaier * 6397132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR : 6398132566Smlaier * network driver performed cksum including pseudo header, need to verify 6399132566Smlaier * csum_data 6400132566Smlaier * CSUM_DATA_VALID : 6401132566Smlaier * network driver performed cksum, needs to additional pseudo header 6402132566Smlaier * cksum computation with partial csum_data(i.e. lack of H/W support for 6403132566Smlaier * pseudo header, for instance hme(4), sk(4) and possibly gem(4)) 6404132566Smlaier * 6405132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and 6406132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper 6407132566Smlaier * TCP/UDP layer. 6408132566Smlaier * Also, set csum_data to 0xffff to force cksum validation. 6409126261Smlaier */ 6410126261Smlaierint 6411126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af) 6412126261Smlaier{ 6413126261Smlaier u_int16_t sum = 0; 6414126261Smlaier int hw_assist = 0; 6415126261Smlaier struct ip *ip; 6416126261Smlaier 6417126261Smlaier if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) 6418126261Smlaier return (1); 6419126261Smlaier if (m->m_pkthdr.len < off + len) 6420126261Smlaier return (1); 6421126261Smlaier 6422126261Smlaier switch (p) { 6423126261Smlaier case IPPROTO_TCP: 6424126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 6425126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { 6426126261Smlaier sum = m->m_pkthdr.csum_data; 6427126261Smlaier } else { 6428223637Sbz ip = mtod(m, struct ip *); 6429126261Smlaier sum = in_pseudo(ip->ip_src.s_addr, 6430223637Sbz ip->ip_dst.s_addr, htonl((u_short)len + 6431223637Sbz m->m_pkthdr.csum_data + IPPROTO_TCP)); 6432126261Smlaier } 6433126261Smlaier sum ^= 0xffff; 6434126261Smlaier ++hw_assist; 6435126261Smlaier } 6436126261Smlaier break; 6437126261Smlaier case IPPROTO_UDP: 6438126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { 6439126261Smlaier if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { 6440126261Smlaier sum = m->m_pkthdr.csum_data; 6441126261Smlaier } else { 6442223637Sbz ip = mtod(m, struct ip *); 6443126261Smlaier sum = in_pseudo(ip->ip_src.s_addr, 6444223637Sbz ip->ip_dst.s_addr, htonl((u_short)len + 6445223637Sbz m->m_pkthdr.csum_data + IPPROTO_UDP)); 6446126261Smlaier } 6447126261Smlaier sum ^= 0xffff; 6448126261Smlaier ++hw_assist; 6449223637Sbz } 6450126261Smlaier break; 6451126261Smlaier case IPPROTO_ICMP: 6452126261Smlaier#ifdef INET6 6453126261Smlaier case IPPROTO_ICMPV6: 6454126261Smlaier#endif /* INET6 */ 6455126261Smlaier break; 6456126261Smlaier default: 6457126261Smlaier return (1); 6458126261Smlaier } 6459126261Smlaier 6460126261Smlaier if (!hw_assist) { 6461126261Smlaier switch (af) { 6462126261Smlaier case AF_INET: 6463126261Smlaier if (p == IPPROTO_ICMP) { 6464126261Smlaier if (m->m_len < off) 6465126261Smlaier return (1); 6466126261Smlaier m->m_data += off; 6467126261Smlaier m->m_len -= off; 6468126261Smlaier sum = in_cksum(m, len); 6469126261Smlaier m->m_data -= off; 6470126261Smlaier m->m_len += off; 6471126261Smlaier } else { 6472126261Smlaier if (m->m_len < sizeof(struct ip)) 6473126261Smlaier return (1); 6474126261Smlaier sum = in4_cksum(m, p, off, len); 6475126261Smlaier } 6476126261Smlaier break; 6477126261Smlaier#ifdef INET6 6478126261Smlaier case AF_INET6: 6479126261Smlaier if (m->m_len < sizeof(struct ip6_hdr)) 6480126261Smlaier return (1); 6481126261Smlaier sum = in6_cksum(m, p, off, len); 6482126261Smlaier break; 6483126261Smlaier#endif /* INET6 */ 6484126261Smlaier default: 6485126261Smlaier return (1); 6486126261Smlaier } 6487126261Smlaier } 6488126261Smlaier if (sum) { 6489126261Smlaier switch (p) { 6490126261Smlaier case IPPROTO_TCP: 6491183550Szec { 6492196039Srwatson KMOD_TCPSTAT_INC(tcps_rcvbadsum); 6493126261Smlaier break; 6494183550Szec } 6495126261Smlaier case IPPROTO_UDP: 6496183550Szec { 6497196039Srwatson KMOD_UDPSTAT_INC(udps_badsum); 6498126261Smlaier break; 6499183550Szec } 6500222529Sbz#ifdef INET 6501126261Smlaier case IPPROTO_ICMP: 6502183550Szec { 6503196039Srwatson KMOD_ICMPSTAT_INC(icps_checksum); 6504126261Smlaier break; 6505183550Szec } 6506222529Sbz#endif 6507126261Smlaier#ifdef INET6 6508126261Smlaier case IPPROTO_ICMPV6: 6509183550Szec { 6510196039Srwatson KMOD_ICMP6STAT_INC(icp6s_checksum); 6511126261Smlaier break; 6512183550Szec } 6513126261Smlaier#endif /* INET6 */ 6514126261Smlaier } 6515126261Smlaier return (1); 6516132566Smlaier } else { 6517132566Smlaier if (p == IPPROTO_TCP || p == IPPROTO_UDP) { 6518132566Smlaier m->m_pkthdr.csum_flags |= 6519132566Smlaier (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 6520132566Smlaier m->m_pkthdr.csum_data = 0xffff; 6521132566Smlaier } 6522126261Smlaier } 6523126261Smlaier return (0); 6524126261Smlaier} 6525171168Smlaier#else /* !__FreeBSD__ */ 6526223637Sbz 6527126261Smlaier/* 6528126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag 6529126258Smlaier * off is the offset where the protocol header starts 6530126258Smlaier * len is the total length of protocol header plus payload 6531126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1. 6532126258Smlaier */ 6533126258Smlaierint 6534130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, 6535130613Smlaier sa_family_t af) 6536126258Smlaier{ 6537126258Smlaier u_int16_t flag_ok, flag_bad; 6538126258Smlaier u_int16_t sum; 6539126258Smlaier 6540126258Smlaier switch (p) { 6541126258Smlaier case IPPROTO_TCP: 6542126258Smlaier flag_ok = M_TCP_CSUM_IN_OK; 6543126258Smlaier flag_bad = M_TCP_CSUM_IN_BAD; 6544126258Smlaier break; 6545126258Smlaier case IPPROTO_UDP: 6546126258Smlaier flag_ok = M_UDP_CSUM_IN_OK; 6547126258Smlaier flag_bad = M_UDP_CSUM_IN_BAD; 6548126258Smlaier break; 6549126258Smlaier case IPPROTO_ICMP: 6550126258Smlaier#ifdef INET6 6551126258Smlaier case IPPROTO_ICMPV6: 6552126258Smlaier#endif /* INET6 */ 6553126258Smlaier flag_ok = flag_bad = 0; 6554126258Smlaier break; 6555126258Smlaier default: 6556126258Smlaier return (1); 6557126258Smlaier } 6558171168Smlaier if (m->m_pkthdr.csum_flags & flag_ok) 6559126258Smlaier return (0); 6560171168Smlaier if (m->m_pkthdr.csum_flags & flag_bad) 6561126258Smlaier return (1); 6562126258Smlaier if (off < sizeof(struct ip) || len < sizeof(struct udphdr)) 6563126258Smlaier return (1); 6564126258Smlaier if (m->m_pkthdr.len < off + len) 6565126258Smlaier return (1); 6566145836Smlaier switch (af) { 6567145836Smlaier#ifdef INET 6568126258Smlaier case AF_INET: 6569126258Smlaier if (p == IPPROTO_ICMP) { 6570126258Smlaier if (m->m_len < off) 6571126258Smlaier return (1); 6572126258Smlaier m->m_data += off; 6573126258Smlaier m->m_len -= off; 6574126258Smlaier sum = in_cksum(m, len); 6575126258Smlaier m->m_data -= off; 6576126258Smlaier m->m_len += off; 6577126258Smlaier } else { 6578126258Smlaier if (m->m_len < sizeof(struct ip)) 6579126258Smlaier return (1); 6580126258Smlaier sum = in4_cksum(m, p, off, len); 6581126258Smlaier } 6582126258Smlaier break; 6583145836Smlaier#endif /* INET */ 6584126258Smlaier#ifdef INET6 6585126258Smlaier case AF_INET6: 6586126258Smlaier if (m->m_len < sizeof(struct ip6_hdr)) 6587126258Smlaier return (1); 6588126258Smlaier sum = in6_cksum(m, p, off, len); 6589126258Smlaier break; 6590126258Smlaier#endif /* INET6 */ 6591126258Smlaier default: 6592126258Smlaier return (1); 6593126258Smlaier } 6594126258Smlaier if (sum) { 6595171168Smlaier m->m_pkthdr.csum_flags |= flag_bad; 6596126258Smlaier switch (p) { 6597126258Smlaier case IPPROTO_TCP: 6598196039Srwatson KMOD_TCPSTAT_INC(tcps_rcvbadsum); 6599126258Smlaier break; 6600126258Smlaier case IPPROTO_UDP: 6601196039Srwatson KMOD_UDPSTAT_INC(udps_badsum); 6602126258Smlaier break; 6603222529Sbz#ifdef INET 6604126258Smlaier case IPPROTO_ICMP: 6605196039Srwatson KMOD_ICMPSTAT_INC(icps_checksum); 6606126258Smlaier break; 6607222529Sbz#endif 6608126258Smlaier#ifdef INET6 6609126258Smlaier case IPPROTO_ICMPV6: 6610196039Srwatson KMOD_ICMP6STAT_INC(icp6s_checksum); 6611126258Smlaier break; 6612126258Smlaier#endif /* INET6 */ 6613126258Smlaier } 6614126258Smlaier return (1); 6615126258Smlaier } 6616171168Smlaier m->m_pkthdr.csum_flags |= flag_ok; 6617126258Smlaier return (0); 6618126258Smlaier} 6619223637Sbz#endif 6620126258Smlaier 6621223637Sbz#ifndef __FreeBSD__ 6622223637Sbzstruct pf_divert * 6623223637Sbzpf_find_divert(struct mbuf *m) 6624223637Sbz{ 6625223637Sbz struct m_tag *mtag; 6626223637Sbz 6627223637Sbz if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) 6628223637Sbz return (NULL); 6629223637Sbz 6630223637Sbz return ((struct pf_divert *)(mtag + 1)); 6631223637Sbz} 6632223637Sbz 6633223637Sbzstruct pf_divert * 6634223637Sbzpf_get_divert(struct mbuf *m) 6635223637Sbz{ 6636223637Sbz struct m_tag *mtag; 6637223637Sbz 6638223637Sbz if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) { 6639223637Sbz mtag = m_tag_get(PACKET_TAG_PF_DIVERT, sizeof(struct pf_divert), 6640223637Sbz M_NOWAIT); 6641223637Sbz if (mtag == NULL) 6642223637Sbz return (NULL); 6643223637Sbz bzero(mtag + 1, sizeof(struct pf_divert)); 6644223637Sbz m_tag_prepend(m, mtag); 6645223637Sbz } 6646223637Sbz 6647223637Sbz return ((struct pf_divert *)(mtag + 1)); 6648223637Sbz} 6649223637Sbz#endif 6650223637Sbz 6651126258Smlaier#ifdef INET 6652126258Smlaierint 6653135920Smlaier#ifdef __FreeBSD__ 6654145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0, 6655145836Smlaier struct ether_header *eh, struct inpcb *inp) 6656135920Smlaier#else 6657145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0, 6658145836Smlaier struct ether_header *eh) 6659135920Smlaier#endif 6660126258Smlaier{ 6661130613Smlaier struct pfi_kif *kif; 6662130613Smlaier u_short action, reason = 0, log = 0; 6663130613Smlaier struct mbuf *m = *m0; 6664223637Sbz#ifdef __FreeBSD__ 6665223637Sbz struct ip *h = NULL; 6666223637Sbz struct m_tag *ipfwtag; 6667223637Sbz struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; 6668223637Sbz#else 6669223637Sbz struct ip *h; 6670130613Smlaier struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; 6671223637Sbz#endif 6672130613Smlaier struct pf_state *s = NULL; 6673130613Smlaier struct pf_ruleset *ruleset = NULL; 6674130613Smlaier struct pf_pdesc pd; 6675130613Smlaier int off, dirndx, pqid = 0; 6676126258Smlaier 6677127145Smlaier#ifdef __FreeBSD__ 6678126261Smlaier PF_LOCK(); 6679223637Sbz if (!V_pf_status.running) 6680171168Smlaier { 6681126261Smlaier PF_UNLOCK(); 6682171168Smlaier return (PF_PASS); 6683126261Smlaier } 6684223637Sbz#else 6685223637Sbz if (!pf_status.running) 6686223637Sbz return (PF_PASS); 6687171168Smlaier#endif 6688126258Smlaier 6689171168Smlaier memset(&pd, 0, sizeof(pd)); 6690223637Sbz#ifdef __FreeBSD__ 6691171168Smlaier if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { 6692171168Smlaier PF_UNLOCK(); 6693171168Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6694171168Smlaier ("pf_test: pf_get_mtag returned NULL\n")); 6695171168Smlaier return (PF_DROP); 6696171168Smlaier } 6697171168Smlaier#endif 6698223637Sbz#ifndef __FreeBSD__ 6699145836Smlaier if (ifp->if_type == IFT_CARP && ifp->if_carpdev) 6700223637Sbz kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; 6701223637Sbz else 6702145836Smlaier#endif 6703223637Sbz kif = (struct pfi_kif *)ifp->if_pf_kif; 6704145836Smlaier 6705130613Smlaier if (kif == NULL) { 6706130613Smlaier#ifdef __FreeBSD__ 6707130613Smlaier PF_UNLOCK(); 6708130613Smlaier#endif 6709145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 6710145836Smlaier ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname)); 6711130613Smlaier return (PF_DROP); 6712130613Smlaier } 6713223637Sbz if (kif->pfik_flags & PFI_IFLAG_SKIP) 6714145836Smlaier#ifdef __FreeBSD__ 6715223637Sbz { 6716145836Smlaier PF_UNLOCK(); 6717145836Smlaier#endif 6718145836Smlaier return (PF_PASS); 6719223637Sbz#ifdef __FreeBSD__ 6720145836Smlaier } 6721223637Sbz#endif 6722130613Smlaier 6723130613Smlaier#ifdef __FreeBSD__ 6724126261Smlaier M_ASSERTPKTHDR(m); 6725126261Smlaier#else 6726126258Smlaier#ifdef DIAGNOSTIC 6727126258Smlaier if ((m->m_flags & M_PKTHDR) == 0) 6728126258Smlaier panic("non-M_PKTHDR is passed to pf_test"); 6729145836Smlaier#endif /* DIAGNOSTIC */ 6730223637Sbz#endif 6731126258Smlaier 6732126258Smlaier if (m->m_pkthdr.len < (int)sizeof(*h)) { 6733126258Smlaier action = PF_DROP; 6734126258Smlaier REASON_SET(&reason, PFRES_SHORT); 6735126258Smlaier log = 1; 6736126258Smlaier goto done; 6737126258Smlaier } 6738126258Smlaier 6739223637Sbz#ifdef __FreeBSD__ 6740223637Sbz if (m->m_flags & M_SKIP_FIREWALL) { 6741223637Sbz PF_UNLOCK(); 6742223637Sbz return (PF_PASS); 6743223637Sbz } 6744223637Sbz#else 6745223637Sbz if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) 6746223637Sbz return (PF_PASS); 6747223637Sbz#endif 6748223637Sbz 6749223637Sbz#ifdef __FreeBSD__ 6750223637Sbz if (ip_divert_ptr != NULL && 6751223637Sbz ((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) { 6752223637Sbz struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1); 6753223637Sbz if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) { 6754223637Sbz pd.pf_mtag->flags |= PF_PACKET_LOOPED; 6755223637Sbz m_tag_delete(m, ipfwtag); 6756223637Sbz } 6757223637Sbz if (pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) { 6758223637Sbz m->m_flags |= M_FASTFWD_OURS; 6759223637Sbz pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT; 6760223637Sbz } 6761223637Sbz } else 6762223637Sbz#endif 6763126258Smlaier /* We do IP header normalization and packet reassembly here */ 6764145836Smlaier if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) { 6765126258Smlaier action = PF_DROP; 6766126258Smlaier goto done; 6767126258Smlaier } 6768223637Sbz m = *m0; /* pf_normalize messes with m0 */ 6769126258Smlaier h = mtod(m, struct ip *); 6770126258Smlaier 6771126258Smlaier off = h->ip_hl << 2; 6772126258Smlaier if (off < (int)sizeof(*h)) { 6773126258Smlaier action = PF_DROP; 6774126258Smlaier REASON_SET(&reason, PFRES_SHORT); 6775126258Smlaier log = 1; 6776126258Smlaier goto done; 6777126258Smlaier } 6778126258Smlaier 6779126258Smlaier pd.src = (struct pf_addr *)&h->ip_src; 6780126258Smlaier pd.dst = (struct pf_addr *)&h->ip_dst; 6781223637Sbz pd.sport = pd.dport = NULL; 6782126258Smlaier pd.ip_sum = &h->ip_sum; 6783223637Sbz pd.proto_sum = NULL; 6784126258Smlaier pd.proto = h->ip_p; 6785223637Sbz pd.dir = dir; 6786223637Sbz pd.sidx = (dir == PF_IN) ? 0 : 1; 6787223637Sbz pd.didx = (dir == PF_IN) ? 1 : 0; 6788126258Smlaier pd.af = AF_INET; 6789126258Smlaier pd.tos = h->ip_tos; 6790126258Smlaier pd.tot_len = ntohs(h->ip_len); 6791145836Smlaier pd.eh = eh; 6792126258Smlaier 6793126258Smlaier /* handle fragments that didn't get reassembled by normalization */ 6794126258Smlaier if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { 6795130613Smlaier action = pf_test_fragment(&r, dir, kif, m, h, 6796126258Smlaier &pd, &a, &ruleset); 6797126258Smlaier goto done; 6798126258Smlaier } 6799126258Smlaier 6800126258Smlaier switch (h->ip_p) { 6801126258Smlaier 6802126258Smlaier case IPPROTO_TCP: { 6803126258Smlaier struct tcphdr th; 6804126258Smlaier 6805126258Smlaier pd.hdr.tcp = &th; 6806126258Smlaier if (!pf_pull_hdr(m, off, &th, sizeof(th), 6807126258Smlaier &action, &reason, AF_INET)) { 6808126258Smlaier log = action != PF_PASS; 6809126258Smlaier goto done; 6810126258Smlaier } 6811126258Smlaier pd.p_len = pd.tot_len - off - (th.th_off << 2); 6812126258Smlaier if ((th.th_flags & TH_ACK) && pd.p_len == 0) 6813126258Smlaier pqid = 1; 6814130613Smlaier action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); 6815126258Smlaier if (action == PF_DROP) 6816130613Smlaier goto done; 6817130613Smlaier action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, 6818126258Smlaier &reason); 6819126258Smlaier if (action == PF_PASS) { 6820223637Sbz#if NPFSYNC > 0 6821223637Sbz#ifdef __FreeBSD__ 6822223637Sbz if (pfsync_update_state_ptr != NULL) 6823223637Sbz pfsync_update_state_ptr(s); 6824223637Sbz#else 6825130613Smlaier pfsync_update_state(s); 6826223637Sbz#endif 6827145836Smlaier#endif /* NPFSYNC */ 6828126258Smlaier r = s->rule.ptr; 6829130613Smlaier a = s->anchor.ptr; 6830126258Smlaier log = s->log; 6831126258Smlaier } else if (s == NULL) 6832135920Smlaier#ifdef __FreeBSD__ 6833223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6834145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 6835135920Smlaier#else 6836223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6837145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6838135920Smlaier#endif 6839126258Smlaier break; 6840126258Smlaier } 6841126258Smlaier 6842126258Smlaier case IPPROTO_UDP: { 6843126258Smlaier struct udphdr uh; 6844126258Smlaier 6845126258Smlaier pd.hdr.udp = &uh; 6846126258Smlaier if (!pf_pull_hdr(m, off, &uh, sizeof(uh), 6847126258Smlaier &action, &reason, AF_INET)) { 6848126258Smlaier log = action != PF_PASS; 6849126258Smlaier goto done; 6850126258Smlaier } 6851130613Smlaier if (uh.uh_dport == 0 || 6852130613Smlaier ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || 6853130613Smlaier ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { 6854130613Smlaier action = PF_DROP; 6855171168Smlaier REASON_SET(&reason, PFRES_SHORT); 6856130613Smlaier goto done; 6857130613Smlaier } 6858130613Smlaier action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); 6859126258Smlaier if (action == PF_PASS) { 6860223637Sbz#if NPFSYNC > 0 6861223637Sbz#ifdef __FreeBSD__ 6862223637Sbz if (pfsync_update_state_ptr != NULL) 6863223637Sbz pfsync_update_state_ptr(s); 6864223637Sbz#else 6865130613Smlaier pfsync_update_state(s); 6866223637Sbz#endif 6867145836Smlaier#endif /* NPFSYNC */ 6868126258Smlaier r = s->rule.ptr; 6869126258Smlaier a = s->anchor.ptr; 6870126258Smlaier log = s->log; 6871126258Smlaier } else if (s == NULL) 6872135920Smlaier#ifdef __FreeBSD__ 6873223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6874145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 6875135920Smlaier#else 6876223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6877145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6878135920Smlaier#endif 6879126258Smlaier break; 6880126258Smlaier } 6881126258Smlaier 6882126258Smlaier case IPPROTO_ICMP: { 6883126258Smlaier struct icmp ih; 6884126258Smlaier 6885126258Smlaier pd.hdr.icmp = &ih; 6886126258Smlaier if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN, 6887126258Smlaier &action, &reason, AF_INET)) { 6888126258Smlaier log = action != PF_PASS; 6889126258Smlaier goto done; 6890126258Smlaier } 6891145836Smlaier action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, 6892145836Smlaier &reason); 6893126258Smlaier if (action == PF_PASS) { 6894223637Sbz#if NPFSYNC > 0 6895223637Sbz#ifdef __FreeBSD__ 6896223637Sbz if (pfsync_update_state_ptr != NULL) 6897223637Sbz pfsync_update_state_ptr(s); 6898223637Sbz#else 6899130613Smlaier pfsync_update_state(s); 6900223637Sbz#endif 6901145836Smlaier#endif /* NPFSYNC */ 6902126258Smlaier r = s->rule.ptr; 6903126258Smlaier a = s->anchor.ptr; 6904126258Smlaier log = s->log; 6905126258Smlaier } else if (s == NULL) 6906145836Smlaier#ifdef __FreeBSD__ 6907223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6908223637Sbz m, off, h, &pd, &a, &ruleset, NULL, inp); 6909145836Smlaier#else 6910223637Sbz action = pf_test_rule(&r, &s, dir, kif, 6911145836Smlaier m, off, h, &pd, &a, &ruleset, &ipintrq); 6912145836Smlaier#endif 6913126258Smlaier break; 6914126258Smlaier } 6915126258Smlaier 6916223637Sbz#ifdef INET6 6917223637Sbz case IPPROTO_ICMPV6: { 6918223637Sbz action = PF_DROP; 6919223637Sbz DPFPRINTF(PF_DEBUG_MISC, 6920223637Sbz ("pf: dropping IPv4 packet with ICMPv6 payload\n")); 6921223637Sbz goto done; 6922223637Sbz } 6923223637Sbz#endif 6924223637Sbz 6925126258Smlaier default: 6926223637Sbz action = pf_test_state_other(&s, dir, kif, m, &pd); 6927126258Smlaier if (action == PF_PASS) { 6928223637Sbz#if NPFSYNC > 0 6929223637Sbz#ifdef __FreeBSD__ 6930223637Sbz if (pfsync_update_state_ptr != NULL) 6931223637Sbz pfsync_update_state_ptr(s); 6932223637Sbz#else 6933130613Smlaier pfsync_update_state(s); 6934223637Sbz#endif 6935145836Smlaier#endif /* NPFSYNC */ 6936126258Smlaier r = s->rule.ptr; 6937126258Smlaier a = s->anchor.ptr; 6938126258Smlaier log = s->log; 6939126258Smlaier } else if (s == NULL) 6940145836Smlaier#ifdef __FreeBSD__ 6941223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 6942223637Sbz &pd, &a, &ruleset, NULL, inp); 6943145836Smlaier#else 6944223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 6945145836Smlaier &pd, &a, &ruleset, &ipintrq); 6946145836Smlaier#endif 6947126258Smlaier break; 6948126258Smlaier } 6949126258Smlaier 6950126258Smlaierdone: 6951126258Smlaier if (action == PF_PASS && h->ip_hl > 5 && 6952200930Sdelphij !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { 6953126258Smlaier action = PF_DROP; 6954145836Smlaier REASON_SET(&reason, PFRES_IPOPTIONS); 6955126258Smlaier log = 1; 6956126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 6957126258Smlaier ("pf: dropping packet with ip options\n")); 6958126258Smlaier } 6959126258Smlaier 6960232292Sbz if ((s && s->tag) || r->rtableid >= 0) 6961223637Sbz#ifdef __FreeBSD__ 6962223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); 6963223637Sbz#else 6964223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid); 6965223637Sbz#endif 6966145836Smlaier 6967223637Sbz if (dir == PF_IN && s && s->key[PF_SK_STACK]) 6968223637Sbz#ifdef __FreeBSD__ 6969223637Sbz pd.pf_mtag->statekey = s->key[PF_SK_STACK]; 6970223637Sbz#else 6971223637Sbz m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; 6972223637Sbz#endif 6973223637Sbz 6974126258Smlaier#ifdef ALTQ 6975126258Smlaier if (action == PF_PASS && r->qid) { 6976223637Sbz#ifdef __FreeBSD__ 6977171168Smlaier if (pqid || (pd.tos & IPTOS_LOWDELAY)) 6978171168Smlaier pd.pf_mtag->qid = r->pqid; 6979171168Smlaier else 6980171168Smlaier pd.pf_mtag->qid = r->qid; 6981171168Smlaier /* add hints for ecn */ 6982171168Smlaier pd.pf_mtag->hdr = h; 6983223637Sbz 6984223637Sbz#else 6985223637Sbz if (pqid || (pd.tos & IPTOS_LOWDELAY)) 6986223637Sbz m->m_pkthdr.pf.qid = r->pqid; 6987223637Sbz else 6988223637Sbz m->m_pkthdr.pf.qid = r->qid; 6989223637Sbz /* add hints for ecn */ 6990223637Sbz m->m_pkthdr.pf.hdr = h; 6991223637Sbz#endif 6992126258Smlaier } 6993145836Smlaier#endif /* ALTQ */ 6994126258Smlaier 6995130613Smlaier /* 6996130613Smlaier * connections redirected to loopback should not match sockets 6997130613Smlaier * bound specifically to loopback due to security implications, 6998130613Smlaier * see tcp_input() and in_pcblookup_listen(). 6999130613Smlaier */ 7000130613Smlaier if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 7001130613Smlaier pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 7002130613Smlaier (s->nat_rule.ptr->action == PF_RDR || 7003130613Smlaier s->nat_rule.ptr->action == PF_BINAT) && 7004171168Smlaier (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 7005223637Sbz#ifdef __FreeBSD__ 7006223637Sbz m->m_flags |= M_SKIP_FIREWALL; 7007223637Sbz#else 7008223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; 7009223637Sbz#endif 7010171168Smlaier 7011223637Sbz#ifdef __FreeBSD__ 7012223637Sbz if (action == PF_PASS && r->divert.port && 7013223637Sbz ip_divert_ptr != NULL && !PACKET_LOOPED()) { 7014223637Sbz 7015223637Sbz ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0, 7016223637Sbz sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO); 7017223637Sbz if (ipfwtag != NULL) { 7018225171Sbz ((struct ipfw_rule_ref *)(ipfwtag+1))->info = 7019225171Sbz ntohs(r->divert.port); 7020223637Sbz ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir; 7021223637Sbz 7022223637Sbz m_tag_prepend(m, ipfwtag); 7023223637Sbz 7024223637Sbz PF_UNLOCK(); 7025223637Sbz 7026223637Sbz if (m->m_flags & M_FASTFWD_OURS) { 7027223637Sbz pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT; 7028223637Sbz m->m_flags &= ~M_FASTFWD_OURS; 7029223637Sbz } 7030223637Sbz 7031223637Sbz ip_divert_ptr(*m0, 7032223637Sbz dir == PF_IN ? DIR_IN : DIR_OUT); 7033223637Sbz *m0 = NULL; 7034223637Sbz return (action); 7035223637Sbz } else { 7036223637Sbz /* XXX: ipfw has the same behaviour! */ 7037223637Sbz action = PF_DROP; 7038223637Sbz REASON_SET(&reason, PFRES_MEMORY); 7039223637Sbz log = 1; 7040223637Sbz DPFPRINTF(PF_DEBUG_MISC, 7041223637Sbz ("pf: failed to allocate divert tag\n")); 7042223637Sbz } 7043223637Sbz } 7044223637Sbz#else 7045223637Sbz if (dir == PF_IN && action == PF_PASS && r->divert.port) { 7046223637Sbz struct pf_divert *divert; 7047223637Sbz 7048223637Sbz if ((divert = pf_get_divert(m))) { 7049223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; 7050223637Sbz divert->port = r->divert.port; 7051223637Sbz divert->addr.ipv4 = r->divert.addr.v4; 7052223637Sbz } 7053223637Sbz } 7054223637Sbz#endif 7055223637Sbz 7056171168Smlaier if (log) { 7057171168Smlaier struct pf_rule *lr; 7058171168Smlaier 7059171168Smlaier if (s != NULL && s->nat_rule.ptr != NULL && 7060171168Smlaier s->nat_rule.ptr->log & PF_LOG_ALL) 7061171168Smlaier lr = s->nat_rule.ptr; 7062171168Smlaier else 7063171168Smlaier lr = r; 7064171168Smlaier PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset, 7065171168Smlaier &pd); 7066130613Smlaier } 7067130613Smlaier 7068130613Smlaier kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len; 7069130613Smlaier kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++; 7070130613Smlaier 7071130613Smlaier if (action == PF_PASS || r->action == PF_DROP) { 7072171168Smlaier dirndx = (dir == PF_OUT); 7073171168Smlaier r->packets[dirndx]++; 7074171168Smlaier r->bytes[dirndx] += pd.tot_len; 7075130613Smlaier if (a != NULL) { 7076171168Smlaier a->packets[dirndx]++; 7077171168Smlaier a->bytes[dirndx] += pd.tot_len; 7078130613Smlaier } 7079130613Smlaier if (s != NULL) { 7080130613Smlaier if (s->nat_rule.ptr != NULL) { 7081171168Smlaier s->nat_rule.ptr->packets[dirndx]++; 7082171168Smlaier s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; 7083130613Smlaier } 7084130613Smlaier if (s->src_node != NULL) { 7085171168Smlaier s->src_node->packets[dirndx]++; 7086171168Smlaier s->src_node->bytes[dirndx] += pd.tot_len; 7087130613Smlaier } 7088130613Smlaier if (s->nat_src_node != NULL) { 7089171168Smlaier s->nat_src_node->packets[dirndx]++; 7090171168Smlaier s->nat_src_node->bytes[dirndx] += pd.tot_len; 7091130613Smlaier } 7092171168Smlaier dirndx = (dir == s->direction) ? 0 : 1; 7093171168Smlaier s->packets[dirndx]++; 7094171168Smlaier s->bytes[dirndx] += pd.tot_len; 7095130613Smlaier } 7096130613Smlaier tr = r; 7097130613Smlaier nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; 7098223637Sbz#ifdef __FreeBSD__ 7099223637Sbz if (nr != NULL && r == &V_pf_default_rule) 7100223637Sbz#else 7101223637Sbz if (nr != NULL && r == &pf_default_rule) 7102223637Sbz#endif 7103223637Sbz tr = nr; 7104130613Smlaier if (tr->src.addr.type == PF_ADDR_TABLE) 7105223637Sbz pfr_update_stats(tr->src.addr.p.tbl, 7106223637Sbz (s == NULL) ? pd.src : 7107223637Sbz &s->key[(s->direction == PF_IN)]-> 7108223637Sbz addr[(s->direction == PF_OUT)], 7109223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7110223637Sbz r->action == PF_PASS, tr->src.neg); 7111130613Smlaier if (tr->dst.addr.type == PF_ADDR_TABLE) 7112223637Sbz pfr_update_stats(tr->dst.addr.p.tbl, 7113223637Sbz (s == NULL) ? pd.dst : 7114223637Sbz &s->key[(s->direction == PF_IN)]-> 7115223637Sbz addr[(s->direction == PF_IN)], 7116223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7117223637Sbz r->action == PF_PASS, tr->dst.neg); 7118130613Smlaier } 7119130613Smlaier 7120223637Sbz switch (action) { 7121223637Sbz case PF_SYNPROXY_DROP: 7122126258Smlaier m_freem(*m0); 7123223637Sbz case PF_DEFER: 7124126258Smlaier *m0 = NULL; 7125126258Smlaier action = PF_PASS; 7126223637Sbz break; 7127223637Sbz default: 7128126258Smlaier /* pf_route can free the mbuf causing *m0 to become NULL */ 7129223637Sbz if (r->rt) 7130223637Sbz pf_route(m0, r, dir, kif->pfik_ifp, s, &pd); 7131223637Sbz break; 7132223637Sbz } 7133127145Smlaier#ifdef __FreeBSD__ 7134126261Smlaier PF_UNLOCK(); 7135126261Smlaier#endif 7136126258Smlaier return (action); 7137126258Smlaier} 7138126258Smlaier#endif /* INET */ 7139126258Smlaier 7140126258Smlaier#ifdef INET6 7141126258Smlaierint 7142135920Smlaier#ifdef __FreeBSD__ 7143145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, 7144145836Smlaier struct ether_header *eh, struct inpcb *inp) 7145135920Smlaier#else 7146145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, 7147145836Smlaier struct ether_header *eh) 7148135920Smlaier#endif 7149126258Smlaier{ 7150130613Smlaier struct pfi_kif *kif; 7151130613Smlaier u_short action, reason = 0, log = 0; 7152171168Smlaier struct mbuf *m = *m0, *n = NULL; 7153223637Sbz#ifdef __FreeBSD__ 7154223637Sbz struct ip6_hdr *h = NULL; 7155223637Sbz struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; 7156223637Sbz#else 7157171168Smlaier struct ip6_hdr *h; 7158130613Smlaier struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; 7159223637Sbz#endif 7160130613Smlaier struct pf_state *s = NULL; 7161130613Smlaier struct pf_ruleset *ruleset = NULL; 7162130613Smlaier struct pf_pdesc pd; 7163169843Sdhartmei int off, terminal = 0, dirndx, rh_cnt = 0; 7164126258Smlaier 7165127145Smlaier#ifdef __FreeBSD__ 7166126261Smlaier PF_LOCK(); 7167223637Sbz if (!V_pf_status.running) { 7168126261Smlaier PF_UNLOCK(); 7169126258Smlaier return (PF_PASS); 7170126261Smlaier } 7171223637Sbz#else 7172223637Sbz if (!pf_status.running) 7173223637Sbz return (PF_PASS); 7174171168Smlaier#endif 7175126258Smlaier 7176171168Smlaier memset(&pd, 0, sizeof(pd)); 7177223637Sbz#ifdef __FreeBSD__ 7178171168Smlaier if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { 7179171168Smlaier PF_UNLOCK(); 7180171168Smlaier DPFPRINTF(PF_DEBUG_URGENT, 7181223637Sbz ("pf_test: pf_get_mtag returned NULL\n")); 7182171168Smlaier return (PF_DROP); 7183171168Smlaier } 7184223637Sbz#endif 7185223637Sbz#ifndef __FreeBSD__ 7186145836Smlaier if (ifp->if_type == IFT_CARP && ifp->if_carpdev) 7187223637Sbz kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; 7188223637Sbz else 7189145836Smlaier#endif 7190223637Sbz kif = (struct pfi_kif *)ifp->if_pf_kif; 7191145836Smlaier 7192130613Smlaier if (kif == NULL) { 7193130613Smlaier#ifdef __FreeBSD__ 7194130613Smlaier PF_UNLOCK(); 7195130613Smlaier#endif 7196145836Smlaier DPFPRINTF(PF_DEBUG_URGENT, 7197145836Smlaier ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname)); 7198130613Smlaier return (PF_DROP); 7199130613Smlaier } 7200223637Sbz if (kif->pfik_flags & PFI_IFLAG_SKIP) 7201145836Smlaier#ifdef __FreeBSD__ 7202223637Sbz { 7203145836Smlaier PF_UNLOCK(); 7204145836Smlaier#endif 7205145836Smlaier return (PF_PASS); 7206223637Sbz#ifdef __FreeBSD__ 7207145836Smlaier } 7208223637Sbz#endif 7209130613Smlaier 7210130613Smlaier#ifdef __FreeBSD__ 7211126261Smlaier M_ASSERTPKTHDR(m); 7212126261Smlaier#else 7213126258Smlaier#ifdef DIAGNOSTIC 7214126258Smlaier if ((m->m_flags & M_PKTHDR) == 0) 7215145836Smlaier panic("non-M_PKTHDR is passed to pf_test6"); 7216145836Smlaier#endif /* DIAGNOSTIC */ 7217126258Smlaier#endif 7218126258Smlaier 7219126258Smlaier if (m->m_pkthdr.len < (int)sizeof(*h)) { 7220126258Smlaier action = PF_DROP; 7221126258Smlaier REASON_SET(&reason, PFRES_SHORT); 7222126258Smlaier log = 1; 7223126258Smlaier goto done; 7224126258Smlaier } 7225126258Smlaier 7226223637Sbz#ifdef __FreeBSD__ 7227227898Sbz if (pd.pf_mtag->flags & PF_TAG_GENERATED) { 7228227898Sbz PF_UNLOCK(); 7229223637Sbz#else 7230223637Sbz if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) 7231223637Sbz#endif 7232223637Sbz return (PF_PASS); 7233227898Sbz#ifdef __FreeBSD__ 7234227898Sbz } 7235227898Sbz#endif 7236223637Sbz 7237126258Smlaier /* We do IP header normalization and packet reassembly here */ 7238145836Smlaier if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) { 7239126258Smlaier action = PF_DROP; 7240126258Smlaier goto done; 7241126258Smlaier } 7242223637Sbz m = *m0; /* pf_normalize messes with m0 */ 7243126258Smlaier h = mtod(m, struct ip6_hdr *); 7244126258Smlaier 7245169843Sdhartmei#if 1 7246169843Sdhartmei /* 7247169843Sdhartmei * we do not support jumbogram yet. if we keep going, zero ip6_plen 7248169843Sdhartmei * will do something bad, so drop the packet for now. 7249169843Sdhartmei */ 7250169843Sdhartmei if (htons(h->ip6_plen) == 0) { 7251169843Sdhartmei action = PF_DROP; 7252169843Sdhartmei REASON_SET(&reason, PFRES_NORM); /*XXX*/ 7253169843Sdhartmei goto done; 7254169843Sdhartmei } 7255169843Sdhartmei#endif 7256169843Sdhartmei 7257126258Smlaier pd.src = (struct pf_addr *)&h->ip6_src; 7258126258Smlaier pd.dst = (struct pf_addr *)&h->ip6_dst; 7259223637Sbz pd.sport = pd.dport = NULL; 7260126258Smlaier pd.ip_sum = NULL; 7261223637Sbz pd.proto_sum = NULL; 7262223637Sbz pd.dir = dir; 7263223637Sbz pd.sidx = (dir == PF_IN) ? 0 : 1; 7264223637Sbz pd.didx = (dir == PF_IN) ? 1 : 0; 7265126258Smlaier pd.af = AF_INET6; 7266126258Smlaier pd.tos = 0; 7267126258Smlaier pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); 7268145836Smlaier pd.eh = eh; 7269126258Smlaier 7270126258Smlaier off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); 7271126258Smlaier pd.proto = h->ip6_nxt; 7272126258Smlaier do { 7273126258Smlaier switch (pd.proto) { 7274126258Smlaier case IPPROTO_FRAGMENT: 7275130613Smlaier action = pf_test_fragment(&r, dir, kif, m, h, 7276126258Smlaier &pd, &a, &ruleset); 7277126258Smlaier if (action == PF_DROP) 7278126258Smlaier REASON_SET(&reason, PFRES_FRAG); 7279126258Smlaier goto done; 7280169843Sdhartmei case IPPROTO_ROUTING: { 7281169843Sdhartmei struct ip6_rthdr rthdr; 7282169843Sdhartmei 7283169843Sdhartmei if (rh_cnt++) { 7284169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7285169843Sdhartmei ("pf: IPv6 more than one rthdr\n")); 7286169843Sdhartmei action = PF_DROP; 7287169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7288169843Sdhartmei log = 1; 7289169843Sdhartmei goto done; 7290169843Sdhartmei } 7291169843Sdhartmei if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, 7292169843Sdhartmei &reason, pd.af)) { 7293169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7294169843Sdhartmei ("pf: IPv6 short rthdr\n")); 7295169843Sdhartmei action = PF_DROP; 7296169843Sdhartmei REASON_SET(&reason, PFRES_SHORT); 7297169843Sdhartmei log = 1; 7298169843Sdhartmei goto done; 7299169843Sdhartmei } 7300169843Sdhartmei if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { 7301169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7302169843Sdhartmei ("pf: IPv6 rthdr0\n")); 7303169843Sdhartmei action = PF_DROP; 7304169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7305169843Sdhartmei log = 1; 7306169843Sdhartmei goto done; 7307169843Sdhartmei } 7308223637Sbz /* FALLTHROUGH */ 7309169843Sdhartmei } 7310126258Smlaier case IPPROTO_AH: 7311126258Smlaier case IPPROTO_HOPOPTS: 7312126258Smlaier case IPPROTO_DSTOPTS: { 7313126258Smlaier /* get next header and header length */ 7314126258Smlaier struct ip6_ext opt6; 7315126258Smlaier 7316126258Smlaier if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6), 7317145836Smlaier NULL, &reason, pd.af)) { 7318126258Smlaier DPFPRINTF(PF_DEBUG_MISC, 7319126258Smlaier ("pf: IPv6 short opt\n")); 7320126258Smlaier action = PF_DROP; 7321126258Smlaier log = 1; 7322126258Smlaier goto done; 7323126258Smlaier } 7324126258Smlaier if (pd.proto == IPPROTO_AH) 7325126258Smlaier off += (opt6.ip6e_len + 2) * 4; 7326126258Smlaier else 7327126258Smlaier off += (opt6.ip6e_len + 1) * 8; 7328126258Smlaier pd.proto = opt6.ip6e_nxt; 7329126258Smlaier /* goto the next header */ 7330126258Smlaier break; 7331126258Smlaier } 7332126258Smlaier default: 7333126258Smlaier terminal++; 7334126258Smlaier break; 7335126258Smlaier } 7336126258Smlaier } while (!terminal); 7337126258Smlaier 7338171168Smlaier /* if there's no routing header, use unmodified mbuf for checksumming */ 7339171168Smlaier if (!n) 7340171168Smlaier n = m; 7341171168Smlaier 7342126258Smlaier switch (pd.proto) { 7343126258Smlaier 7344126258Smlaier case IPPROTO_TCP: { 7345126258Smlaier struct tcphdr th; 7346126258Smlaier 7347126258Smlaier pd.hdr.tcp = &th; 7348126258Smlaier if (!pf_pull_hdr(m, off, &th, sizeof(th), 7349126258Smlaier &action, &reason, AF_INET6)) { 7350126258Smlaier log = action != PF_PASS; 7351126258Smlaier goto done; 7352126258Smlaier } 7353126258Smlaier pd.p_len = pd.tot_len - off - (th.th_off << 2); 7354130613Smlaier action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); 7355126258Smlaier if (action == PF_DROP) 7356130613Smlaier goto done; 7357130613Smlaier action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, 7358126258Smlaier &reason); 7359126258Smlaier if (action == PF_PASS) { 7360223637Sbz#if NPFSYNC > 0 7361223637Sbz#ifdef __FreeBSD__ 7362223637Sbz if (pfsync_update_state_ptr != NULL) 7363223637Sbz pfsync_update_state_ptr(s); 7364223637Sbz#else 7365130613Smlaier pfsync_update_state(s); 7366223637Sbz#endif 7367145836Smlaier#endif /* NPFSYNC */ 7368126258Smlaier r = s->rule.ptr; 7369130613Smlaier a = s->anchor.ptr; 7370126258Smlaier log = s->log; 7371126258Smlaier } else if (s == NULL) 7372135920Smlaier#ifdef __FreeBSD__ 7373223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7374145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 7375135920Smlaier#else 7376223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7377145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7378135920Smlaier#endif 7379126258Smlaier break; 7380126258Smlaier } 7381126258Smlaier 7382126258Smlaier case IPPROTO_UDP: { 7383126258Smlaier struct udphdr uh; 7384126258Smlaier 7385126258Smlaier pd.hdr.udp = &uh; 7386126258Smlaier if (!pf_pull_hdr(m, off, &uh, sizeof(uh), 7387126258Smlaier &action, &reason, AF_INET6)) { 7388126258Smlaier log = action != PF_PASS; 7389126258Smlaier goto done; 7390126258Smlaier } 7391130613Smlaier if (uh.uh_dport == 0 || 7392130613Smlaier ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || 7393130613Smlaier ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { 7394130613Smlaier action = PF_DROP; 7395171168Smlaier REASON_SET(&reason, PFRES_SHORT); 7396130613Smlaier goto done; 7397130613Smlaier } 7398130613Smlaier action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); 7399126258Smlaier if (action == PF_PASS) { 7400223637Sbz#if NPFSYNC > 0 7401223637Sbz#ifdef __FreeBSD__ 7402223637Sbz if (pfsync_update_state_ptr != NULL) 7403223637Sbz pfsync_update_state_ptr(s); 7404223637Sbz#else 7405130613Smlaier pfsync_update_state(s); 7406223637Sbz#endif 7407145836Smlaier#endif /* NPFSYNC */ 7408126258Smlaier r = s->rule.ptr; 7409130613Smlaier a = s->anchor.ptr; 7410126258Smlaier log = s->log; 7411126258Smlaier } else if (s == NULL) 7412135920Smlaier#ifdef __FreeBSD__ 7413223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7414145836Smlaier m, off, h, &pd, &a, &ruleset, NULL, inp); 7415135920Smlaier#else 7416223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7417145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7418135920Smlaier#endif 7419126258Smlaier break; 7420126258Smlaier } 7421126258Smlaier 7422223637Sbz case IPPROTO_ICMP: { 7423223637Sbz action = PF_DROP; 7424223637Sbz DPFPRINTF(PF_DEBUG_MISC, 7425223637Sbz ("pf: dropping IPv6 packet with ICMPv4 payload\n")); 7426223637Sbz goto done; 7427223637Sbz } 7428223637Sbz 7429126258Smlaier case IPPROTO_ICMPV6: { 7430126258Smlaier struct icmp6_hdr ih; 7431126258Smlaier 7432126258Smlaier pd.hdr.icmp6 = &ih; 7433126258Smlaier if (!pf_pull_hdr(m, off, &ih, sizeof(ih), 7434126258Smlaier &action, &reason, AF_INET6)) { 7435126258Smlaier log = action != PF_PASS; 7436126258Smlaier goto done; 7437126258Smlaier } 7438130613Smlaier action = pf_test_state_icmp(&s, dir, kif, 7439145836Smlaier m, off, h, &pd, &reason); 7440126258Smlaier if (action == PF_PASS) { 7441223637Sbz#if NPFSYNC > 0 7442223637Sbz#ifdef __FreeBSD__ 7443223637Sbz if (pfsync_update_state_ptr != NULL) 7444223637Sbz pfsync_update_state_ptr(s); 7445223637Sbz#else 7446130613Smlaier pfsync_update_state(s); 7447223637Sbz#endif 7448145836Smlaier#endif /* NPFSYNC */ 7449126258Smlaier r = s->rule.ptr; 7450130613Smlaier a = s->anchor.ptr; 7451126258Smlaier log = s->log; 7452126258Smlaier } else if (s == NULL) 7453145836Smlaier#ifdef __FreeBSD__ 7454223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7455223637Sbz m, off, h, &pd, &a, &ruleset, NULL, inp); 7456145836Smlaier#else 7457223637Sbz action = pf_test_rule(&r, &s, dir, kif, 7458145836Smlaier m, off, h, &pd, &a, &ruleset, &ip6intrq); 7459145836Smlaier#endif 7460126258Smlaier break; 7461126258Smlaier } 7462126258Smlaier 7463126258Smlaier default: 7464223637Sbz action = pf_test_state_other(&s, dir, kif, m, &pd); 7465130613Smlaier if (action == PF_PASS) { 7466223637Sbz#if NPFSYNC > 0 7467223637Sbz#ifdef __FreeBSD__ 7468223637Sbz if (pfsync_update_state_ptr != NULL) 7469223637Sbz pfsync_update_state_ptr(s); 7470223637Sbz#else 7471145836Smlaier pfsync_update_state(s); 7472223637Sbz#endif 7473145836Smlaier#endif /* NPFSYNC */ 7474130613Smlaier r = s->rule.ptr; 7475130613Smlaier a = s->anchor.ptr; 7476130613Smlaier log = s->log; 7477130613Smlaier } else if (s == NULL) 7478145836Smlaier#ifdef __FreeBSD__ 7479223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 7480223637Sbz &pd, &a, &ruleset, NULL, inp); 7481145836Smlaier#else 7482223637Sbz action = pf_test_rule(&r, &s, dir, kif, m, off, h, 7483145836Smlaier &pd, &a, &ruleset, &ip6intrq); 7484145836Smlaier#endif 7485126258Smlaier break; 7486126258Smlaier } 7487126258Smlaier 7488126258Smlaierdone: 7489223637Sbz if (n != m) { 7490223637Sbz m_freem(n); 7491223637Sbz n = NULL; 7492223637Sbz } 7493223637Sbz 7494169843Sdhartmei /* handle dangerous IPv6 extension headers. */ 7495169843Sdhartmei if (action == PF_PASS && rh_cnt && 7496200930Sdelphij !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { 7497169843Sdhartmei action = PF_DROP; 7498169843Sdhartmei REASON_SET(&reason, PFRES_IPOPTIONS); 7499169843Sdhartmei log = 1; 7500169843Sdhartmei DPFPRINTF(PF_DEBUG_MISC, 7501169843Sdhartmei ("pf: dropping packet with dangerous v6 headers\n")); 7502169843Sdhartmei } 7503126258Smlaier 7504232292Sbz if ((s && s->tag) || r->rtableid >= 0) 7505223637Sbz#ifdef __FreeBSD__ 7506223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); 7507223637Sbz#else 7508223637Sbz pf_tag_packet(m, s ? s->tag : 0, r->rtableid); 7509223637Sbz#endif 7510145836Smlaier 7511223637Sbz if (dir == PF_IN && s && s->key[PF_SK_STACK]) 7512223637Sbz#ifdef __FreeBSD__ 7513223637Sbz pd.pf_mtag->statekey = s->key[PF_SK_STACK]; 7514223637Sbz#else 7515223637Sbz m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; 7516223637Sbz#endif 7517223637Sbz 7518126258Smlaier#ifdef ALTQ 7519126258Smlaier if (action == PF_PASS && r->qid) { 7520223637Sbz#ifdef __FreeBSD__ 7521171168Smlaier if (pd.tos & IPTOS_LOWDELAY) 7522171168Smlaier pd.pf_mtag->qid = r->pqid; 7523171168Smlaier else 7524171168Smlaier pd.pf_mtag->qid = r->qid; 7525171168Smlaier /* add hints for ecn */ 7526171168Smlaier pd.pf_mtag->hdr = h; 7527223637Sbz#else 7528223637Sbz if (pd.tos & IPTOS_LOWDELAY) 7529223637Sbz m->m_pkthdr.pf.qid = r->pqid; 7530223637Sbz else 7531223637Sbz m->m_pkthdr.pf.qid = r->qid; 7532223637Sbz /* add hints for ecn */ 7533223637Sbz m->m_pkthdr.pf.hdr = h; 7534223637Sbz#endif 7535126258Smlaier } 7536145836Smlaier#endif /* ALTQ */ 7537126258Smlaier 7538130613Smlaier if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 7539130613Smlaier pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 7540130613Smlaier (s->nat_rule.ptr->action == PF_RDR || 7541130613Smlaier s->nat_rule.ptr->action == PF_BINAT) && 7542171168Smlaier IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) 7543223637Sbz#ifdef __FreeBSD__ 7544223637Sbz m->m_flags |= M_SKIP_FIREWALL; 7545223637Sbz#else 7546223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; 7547223637Sbz#endif 7548171168Smlaier 7549223637Sbz#ifdef __FreeBSD__ 7550223637Sbz /* XXX: Anybody working on it?! */ 7551223637Sbz if (r->divert.port) 7552223637Sbz printf("pf: divert(9) is not supported for IPv6\n"); 7553223637Sbz#else 7554223637Sbz if (dir == PF_IN && action == PF_PASS && r->divert.port) { 7555223637Sbz struct pf_divert *divert; 7556223637Sbz 7557223637Sbz if ((divert = pf_get_divert(m))) { 7558223637Sbz m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; 7559223637Sbz divert->port = r->divert.port; 7560223637Sbz divert->addr.ipv6 = r->divert.addr.v6; 7561223637Sbz } 7562223637Sbz } 7563223637Sbz#endif 7564223637Sbz 7565171168Smlaier if (log) { 7566171168Smlaier struct pf_rule *lr; 7567171168Smlaier 7568171168Smlaier if (s != NULL && s->nat_rule.ptr != NULL && 7569171168Smlaier s->nat_rule.ptr->log & PF_LOG_ALL) 7570171168Smlaier lr = s->nat_rule.ptr; 7571171168Smlaier else 7572171168Smlaier lr = r; 7573171168Smlaier PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset, 7574171168Smlaier &pd); 7575130613Smlaier } 7576130613Smlaier 7577130613Smlaier kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len; 7578130613Smlaier kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++; 7579130613Smlaier 7580130613Smlaier if (action == PF_PASS || r->action == PF_DROP) { 7581171168Smlaier dirndx = (dir == PF_OUT); 7582171168Smlaier r->packets[dirndx]++; 7583171168Smlaier r->bytes[dirndx] += pd.tot_len; 7584130613Smlaier if (a != NULL) { 7585171168Smlaier a->packets[dirndx]++; 7586171168Smlaier a->bytes[dirndx] += pd.tot_len; 7587130613Smlaier } 7588130613Smlaier if (s != NULL) { 7589130613Smlaier if (s->nat_rule.ptr != NULL) { 7590171168Smlaier s->nat_rule.ptr->packets[dirndx]++; 7591171168Smlaier s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; 7592130613Smlaier } 7593130613Smlaier if (s->src_node != NULL) { 7594171168Smlaier s->src_node->packets[dirndx]++; 7595171168Smlaier s->src_node->bytes[dirndx] += pd.tot_len; 7596130613Smlaier } 7597130613Smlaier if (s->nat_src_node != NULL) { 7598171168Smlaier s->nat_src_node->packets[dirndx]++; 7599171168Smlaier s->nat_src_node->bytes[dirndx] += pd.tot_len; 7600130613Smlaier } 7601171168Smlaier dirndx = (dir == s->direction) ? 0 : 1; 7602171168Smlaier s->packets[dirndx]++; 7603171168Smlaier s->bytes[dirndx] += pd.tot_len; 7604130613Smlaier } 7605130613Smlaier tr = r; 7606130613Smlaier nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; 7607223637Sbz#ifdef __FreeBSD__ 7608223637Sbz if (nr != NULL && r == &V_pf_default_rule) 7609223637Sbz#else 7610223637Sbz if (nr != NULL && r == &pf_default_rule) 7611223637Sbz#endif 7612223637Sbz tr = nr; 7613130613Smlaier if (tr->src.addr.type == PF_ADDR_TABLE) 7614223637Sbz pfr_update_stats(tr->src.addr.p.tbl, 7615223637Sbz (s == NULL) ? pd.src : 7616223637Sbz &s->key[(s->direction == PF_IN)]->addr[0], 7617223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7618223637Sbz r->action == PF_PASS, tr->src.neg); 7619130613Smlaier if (tr->dst.addr.type == PF_ADDR_TABLE) 7620223637Sbz pfr_update_stats(tr->dst.addr.p.tbl, 7621223637Sbz (s == NULL) ? pd.dst : 7622223637Sbz &s->key[(s->direction == PF_IN)]->addr[1], 7623223637Sbz pd.af, pd.tot_len, dir == PF_OUT, 7624223637Sbz r->action == PF_PASS, tr->dst.neg); 7625130613Smlaier } 7626130613Smlaier 7627223637Sbz switch (action) { 7628223637Sbz case PF_SYNPROXY_DROP: 7629126258Smlaier m_freem(*m0); 7630223637Sbz case PF_DEFER: 7631126258Smlaier *m0 = NULL; 7632126258Smlaier action = PF_PASS; 7633223637Sbz break; 7634223637Sbz default: 7635126258Smlaier /* pf_route6 can free the mbuf causing *m0 to become NULL */ 7636223637Sbz if (r->rt) 7637223637Sbz pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd); 7638223637Sbz break; 7639223637Sbz } 7640126258Smlaier 7641127145Smlaier#ifdef __FreeBSD__ 7642126261Smlaier PF_UNLOCK(); 7643126261Smlaier#endif 7644126258Smlaier return (action); 7645126258Smlaier} 7646126258Smlaier#endif /* INET6 */ 7647145836Smlaier 7648145836Smlaierint 7649145836Smlaierpf_check_congestion(struct ifqueue *ifq) 7650145836Smlaier{ 7651145836Smlaier#ifdef __FreeBSD__ 7652145836Smlaier /* XXX_IMPORT: later */ 7653145836Smlaier return (0); 7654145836Smlaier#else 7655145836Smlaier if (ifq->ifq_congestion) 7656145836Smlaier return (1); 7657145836Smlaier else 7658145836Smlaier return (0); 7659145836Smlaier#endif 7660145836Smlaier} 7661223637Sbz 7662223637Sbz/* 7663223637Sbz * must be called whenever any addressing information such as 7664223637Sbz * address, port, protocol has changed 7665223637Sbz */ 7666223637Sbzvoid 7667223637Sbzpf_pkt_addr_changed(struct mbuf *m) 7668223637Sbz{ 7669223637Sbz#ifdef __FreeBSD__ 7670223637Sbz struct pf_mtag *pf_tag; 7671223637Sbz 7672223637Sbz if ((pf_tag = pf_find_mtag(m)) != NULL) 7673223637Sbz pf_tag->statekey = NULL; 7674223637Sbz#else 7675223637Sbz m->m_pkthdr.pf.statekey = NULL; 7676223637Sbz#endif 7677223637Sbz} 7678