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