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