Annotation of sys/net/pf.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pf.c,v 1.552 2007/08/21 15:57:27 dhartmei Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001 Daniel Hartmeier
! 5: * Copyright (c) 2002,2003 Henning Brauer
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: *
! 12: * - Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * - Redistributions in binary form must reproduce the above
! 15: * copyright notice, this list of conditions and the following
! 16: * disclaimer in the documentation and/or other materials provided
! 17: * with the distribution.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 20: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 21: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
! 22: * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
! 23: * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
! 25: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 26: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! 27: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 29: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 30: * POSSIBILITY OF SUCH DAMAGE.
! 31: *
! 32: * Effort sponsored in part by the Defense Advanced Research Projects
! 33: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 34: * Materiel Command, USAF, under agreement number F30602-01-2-0537.
! 35: *
! 36: */
! 37:
! 38: #include "bpfilter.h"
! 39: #include "pflog.h"
! 40: #include "pfsync.h"
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/mbuf.h>
! 45: #include <sys/filio.h>
! 46: #include <sys/socket.h>
! 47: #include <sys/socketvar.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/time.h>
! 50: #include <sys/pool.h>
! 51: #include <sys/proc.h>
! 52: #include <sys/rwlock.h>
! 53:
! 54: #include <net/if.h>
! 55: #include <net/if_types.h>
! 56: #include <net/bpf.h>
! 57: #include <net/route.h>
! 58: #include <net/radix_mpath.h>
! 59:
! 60: #include <netinet/in.h>
! 61: #include <netinet/in_var.h>
! 62: #include <netinet/in_systm.h>
! 63: #include <netinet/ip.h>
! 64: #include <netinet/ip_var.h>
! 65: #include <netinet/tcp.h>
! 66: #include <netinet/tcp_seq.h>
! 67: #include <netinet/udp.h>
! 68: #include <netinet/ip_icmp.h>
! 69: #include <netinet/in_pcb.h>
! 70: #include <netinet/tcp_timer.h>
! 71: #include <netinet/tcp_var.h>
! 72: #include <netinet/udp_var.h>
! 73: #include <netinet/icmp_var.h>
! 74: #include <netinet/if_ether.h>
! 75:
! 76: #include <dev/rndvar.h>
! 77: #include <net/pfvar.h>
! 78: #include <net/if_pflog.h>
! 79:
! 80: #if NPFSYNC > 0
! 81: #include <net/if_pfsync.h>
! 82: #endif /* NPFSYNC > 0 */
! 83:
! 84: #ifdef INET6
! 85: #include <netinet/ip6.h>
! 86: #include <netinet/in_pcb.h>
! 87: #include <netinet/icmp6.h>
! 88: #include <netinet6/nd6.h>
! 89: #endif /* INET6 */
! 90:
! 91:
! 92: #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
! 93:
! 94: /*
! 95: * Global variables
! 96: */
! 97:
! 98: /* state tables */
! 99: struct pf_state_tree_lan_ext pf_statetbl_lan_ext;
! 100: struct pf_state_tree_ext_gwy pf_statetbl_ext_gwy;
! 101:
! 102: struct pf_altqqueue pf_altqs[2];
! 103: struct pf_palist pf_pabuf;
! 104: struct pf_altqqueue *pf_altqs_active;
! 105: struct pf_altqqueue *pf_altqs_inactive;
! 106: struct pf_status pf_status;
! 107:
! 108: u_int32_t ticket_altqs_active;
! 109: u_int32_t ticket_altqs_inactive;
! 110: int altqs_inactive_open;
! 111: u_int32_t ticket_pabuf;
! 112:
! 113: struct pf_anchor_stackframe {
! 114: struct pf_ruleset *rs;
! 115: struct pf_rule *r;
! 116: struct pf_anchor_node *parent;
! 117: struct pf_anchor *child;
! 118: } pf_anchor_stack[64];
! 119:
! 120: struct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl;
! 121: struct pool pf_state_pl, pf_state_key_pl;
! 122: struct pool pf_altq_pl;
! 123:
! 124: void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
! 125:
! 126: void pf_init_threshold(struct pf_threshold *, u_int32_t,
! 127: u_int32_t);
! 128: void pf_add_threshold(struct pf_threshold *);
! 129: int pf_check_threshold(struct pf_threshold *);
! 130:
! 131: void pf_change_ap(struct pf_addr *, u_int16_t *,
! 132: u_int16_t *, u_int16_t *, struct pf_addr *,
! 133: u_int16_t, u_int8_t, sa_family_t);
! 134: int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
! 135: struct tcphdr *, struct pf_state_peer *);
! 136: #ifdef INET6
! 137: void pf_change_a6(struct pf_addr *, u_int16_t *,
! 138: struct pf_addr *, u_int8_t);
! 139: #endif /* INET6 */
! 140: void pf_change_icmp(struct pf_addr *, u_int16_t *,
! 141: struct pf_addr *, struct pf_addr *, u_int16_t,
! 142: u_int16_t *, u_int16_t *, u_int16_t *,
! 143: u_int16_t *, u_int8_t, sa_family_t);
! 144: void pf_send_tcp(const struct pf_rule *, sa_family_t,
! 145: const struct pf_addr *, const struct pf_addr *,
! 146: u_int16_t, u_int16_t, u_int32_t, u_int32_t,
! 147: u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
! 148: u_int16_t, struct ether_header *, struct ifnet *);
! 149: void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
! 150: sa_family_t, struct pf_rule *);
! 151: struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
! 152: int, int, struct pfi_kif *,
! 153: struct pf_addr *, u_int16_t, struct pf_addr *,
! 154: u_int16_t, int);
! 155: struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
! 156: int, int, struct pfi_kif *, struct pf_src_node **,
! 157: struct pf_addr *, u_int16_t,
! 158: struct pf_addr *, u_int16_t,
! 159: struct pf_addr *, u_int16_t *);
! 160: void pf_attach_state(struct pf_state_key *,
! 161: struct pf_state *, int);
! 162: void pf_detach_state(struct pf_state *, int);
! 163: int pf_test_rule(struct pf_rule **, struct pf_state **,
! 164: int, struct pfi_kif *, struct mbuf *, int,
! 165: void *, struct pf_pdesc *, struct pf_rule **,
! 166: struct pf_ruleset **, struct ifqueue *);
! 167: int pf_test_fragment(struct pf_rule **, int,
! 168: struct pfi_kif *, struct mbuf *, void *,
! 169: struct pf_pdesc *, struct pf_rule **,
! 170: struct pf_ruleset **);
! 171: int pf_test_state_tcp(struct pf_state **, int,
! 172: struct pfi_kif *, struct mbuf *, int,
! 173: void *, struct pf_pdesc *, u_short *);
! 174: int pf_test_state_udp(struct pf_state **, int,
! 175: struct pfi_kif *, struct mbuf *, int,
! 176: void *, struct pf_pdesc *);
! 177: int pf_test_state_icmp(struct pf_state **, int,
! 178: struct pfi_kif *, struct mbuf *, int,
! 179: void *, struct pf_pdesc *, u_short *);
! 180: int pf_test_state_other(struct pf_state **, int,
! 181: struct pfi_kif *, struct pf_pdesc *);
! 182: int pf_match_tag(struct mbuf *, struct pf_rule *, int *);
! 183: void pf_step_into_anchor(int *, struct pf_ruleset **, int,
! 184: struct pf_rule **, struct pf_rule **, int *);
! 185: int pf_step_out_of_anchor(int *, struct pf_ruleset **,
! 186: int, struct pf_rule **, struct pf_rule **,
! 187: int *);
! 188: void pf_hash(struct pf_addr *, struct pf_addr *,
! 189: struct pf_poolhashkey *, sa_family_t);
! 190: int pf_map_addr(u_int8_t, struct pf_rule *,
! 191: struct pf_addr *, struct pf_addr *,
! 192: struct pf_addr *, struct pf_src_node **);
! 193: int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
! 194: struct pf_addr *, struct pf_addr *, u_int16_t,
! 195: struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
! 196: struct pf_src_node **);
! 197: void pf_route(struct mbuf **, struct pf_rule *, int,
! 198: struct ifnet *, struct pf_state *,
! 199: struct pf_pdesc *);
! 200: void pf_route6(struct mbuf **, struct pf_rule *, int,
! 201: struct ifnet *, struct pf_state *,
! 202: struct pf_pdesc *);
! 203: int pf_socket_lookup(int, struct pf_pdesc *);
! 204: u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t,
! 205: sa_family_t);
! 206: u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t,
! 207: sa_family_t);
! 208: u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t,
! 209: u_int16_t);
! 210: void pf_set_rt_ifp(struct pf_state *,
! 211: struct pf_addr *);
! 212: int pf_check_proto_cksum(struct mbuf *, int, int,
! 213: u_int8_t, sa_family_t);
! 214: int pf_addr_wrap_neq(struct pf_addr_wrap *,
! 215: struct pf_addr_wrap *);
! 216: struct pf_state *pf_find_state(struct pfi_kif *,
! 217: struct pf_state_key_cmp *, u_int8_t);
! 218: int pf_src_connlimit(struct pf_state **);
! 219: void pf_stateins_err(const char *, struct pf_state *,
! 220: struct pfi_kif *);
! 221: int pf_check_congestion(struct ifqueue *);
! 222:
! 223: extern struct pool pfr_ktable_pl;
! 224: extern struct pool pfr_kentry_pl;
! 225:
! 226: struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
! 227: { &pf_state_pl, PFSTATE_HIWAT },
! 228: { &pf_src_tree_pl, PFSNODE_HIWAT },
! 229: { &pf_frent_pl, PFFRAG_FRENT_HIWAT },
! 230: { &pfr_ktable_pl, PFR_KTABLE_HIWAT },
! 231: { &pfr_kentry_pl, PFR_KENTRY_HIWAT }
! 232: };
! 233:
! 234: #define STATE_LOOKUP() \
! 235: do { \
! 236: if (direction == PF_IN) \
! 237: *state = pf_find_state(kif, &key, PF_EXT_GWY); \
! 238: else \
! 239: *state = pf_find_state(kif, &key, PF_LAN_EXT); \
! 240: if (*state == NULL || (*state)->timeout == PFTM_PURGE) \
! 241: return (PF_DROP); \
! 242: if (direction == PF_OUT && \
! 243: (((*state)->rule.ptr->rt == PF_ROUTETO && \
! 244: (*state)->rule.ptr->direction == PF_OUT) || \
! 245: ((*state)->rule.ptr->rt == PF_REPLYTO && \
! 246: (*state)->rule.ptr->direction == PF_IN)) && \
! 247: (*state)->rt_kif != NULL && \
! 248: (*state)->rt_kif != kif) \
! 249: return (PF_PASS); \
! 250: } while (0)
! 251:
! 252: #define STATE_TRANSLATE(sk) \
! 253: (sk)->lan.addr.addr32[0] != (sk)->gwy.addr.addr32[0] || \
! 254: ((sk)->af == AF_INET6 && \
! 255: ((sk)->lan.addr.addr32[1] != (sk)->gwy.addr.addr32[1] || \
! 256: (sk)->lan.addr.addr32[2] != (sk)->gwy.addr.addr32[2] || \
! 257: (sk)->lan.addr.addr32[3] != (sk)->gwy.addr.addr32[3])) || \
! 258: (sk)->lan.port != (sk)->gwy.port
! 259:
! 260: #define BOUND_IFACE(r, k) \
! 261: ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all
! 262:
! 263: #define STATE_INC_COUNTERS(s) \
! 264: do { \
! 265: s->rule.ptr->states++; \
! 266: if (s->anchor.ptr != NULL) \
! 267: s->anchor.ptr->states++; \
! 268: if (s->nat_rule.ptr != NULL) \
! 269: s->nat_rule.ptr->states++; \
! 270: } while (0)
! 271:
! 272: #define STATE_DEC_COUNTERS(s) \
! 273: do { \
! 274: if (s->nat_rule.ptr != NULL) \
! 275: s->nat_rule.ptr->states--; \
! 276: if (s->anchor.ptr != NULL) \
! 277: s->anchor.ptr->states--; \
! 278: s->rule.ptr->states--; \
! 279: } while (0)
! 280:
! 281: static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
! 282: static __inline int pf_state_compare_lan_ext(struct pf_state_key *,
! 283: struct pf_state_key *);
! 284: static __inline int pf_state_compare_ext_gwy(struct pf_state_key *,
! 285: struct pf_state_key *);
! 286: static __inline int pf_state_compare_id(struct pf_state *,
! 287: struct pf_state *);
! 288:
! 289: struct pf_src_tree tree_src_tracking;
! 290:
! 291: struct pf_state_tree_id tree_id;
! 292: struct pf_state_queue state_list;
! 293:
! 294: RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
! 295: RB_GENERATE(pf_state_tree_lan_ext, pf_state_key,
! 296: entry_lan_ext, pf_state_compare_lan_ext);
! 297: RB_GENERATE(pf_state_tree_ext_gwy, pf_state_key,
! 298: entry_ext_gwy, pf_state_compare_ext_gwy);
! 299: RB_GENERATE(pf_state_tree_id, pf_state,
! 300: entry_id, pf_state_compare_id);
! 301:
! 302: #define PF_DT_SKIP_LANEXT 0x01
! 303: #define PF_DT_SKIP_EXTGWY 0x02
! 304:
! 305: static __inline int
! 306: pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
! 307: {
! 308: int diff;
! 309:
! 310: if (a->rule.ptr > b->rule.ptr)
! 311: return (1);
! 312: if (a->rule.ptr < b->rule.ptr)
! 313: return (-1);
! 314: if ((diff = a->af - b->af) != 0)
! 315: return (diff);
! 316: switch (a->af) {
! 317: #ifdef INET
! 318: case AF_INET:
! 319: if (a->addr.addr32[0] > b->addr.addr32[0])
! 320: return (1);
! 321: if (a->addr.addr32[0] < b->addr.addr32[0])
! 322: return (-1);
! 323: break;
! 324: #endif /* INET */
! 325: #ifdef INET6
! 326: case AF_INET6:
! 327: if (a->addr.addr32[3] > b->addr.addr32[3])
! 328: return (1);
! 329: if (a->addr.addr32[3] < b->addr.addr32[3])
! 330: return (-1);
! 331: if (a->addr.addr32[2] > b->addr.addr32[2])
! 332: return (1);
! 333: if (a->addr.addr32[2] < b->addr.addr32[2])
! 334: return (-1);
! 335: if (a->addr.addr32[1] > b->addr.addr32[1])
! 336: return (1);
! 337: if (a->addr.addr32[1] < b->addr.addr32[1])
! 338: return (-1);
! 339: if (a->addr.addr32[0] > b->addr.addr32[0])
! 340: return (1);
! 341: if (a->addr.addr32[0] < b->addr.addr32[0])
! 342: return (-1);
! 343: break;
! 344: #endif /* INET6 */
! 345: }
! 346: return (0);
! 347: }
! 348:
! 349: static __inline int
! 350: pf_state_compare_lan_ext(struct pf_state_key *a, struct pf_state_key *b)
! 351: {
! 352: int diff;
! 353:
! 354: if ((diff = a->proto - b->proto) != 0)
! 355: return (diff);
! 356: if ((diff = a->af - b->af) != 0)
! 357: return (diff);
! 358: switch (a->af) {
! 359: #ifdef INET
! 360: case AF_INET:
! 361: if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
! 362: return (1);
! 363: if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
! 364: return (-1);
! 365: if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
! 366: return (1);
! 367: if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
! 368: return (-1);
! 369: break;
! 370: #endif /* INET */
! 371: #ifdef INET6
! 372: case AF_INET6:
! 373: if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
! 374: return (1);
! 375: if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
! 376: return (-1);
! 377: if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
! 378: return (1);
! 379: if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
! 380: return (-1);
! 381: if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
! 382: return (1);
! 383: if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
! 384: return (-1);
! 385: if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
! 386: return (1);
! 387: if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
! 388: return (-1);
! 389: if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
! 390: return (1);
! 391: if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
! 392: return (-1);
! 393: if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
! 394: return (1);
! 395: if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
! 396: return (-1);
! 397: if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
! 398: return (1);
! 399: if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
! 400: return (-1);
! 401: if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
! 402: return (1);
! 403: if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
! 404: return (-1);
! 405: break;
! 406: #endif /* INET6 */
! 407: }
! 408:
! 409: if ((diff = a->lan.port - b->lan.port) != 0)
! 410: return (diff);
! 411: if ((diff = a->ext.port - b->ext.port) != 0)
! 412: return (diff);
! 413:
! 414: return (0);
! 415: }
! 416:
! 417: static __inline int
! 418: pf_state_compare_ext_gwy(struct pf_state_key *a, struct pf_state_key *b)
! 419: {
! 420: int diff;
! 421:
! 422: if ((diff = a->proto - b->proto) != 0)
! 423: return (diff);
! 424: if ((diff = a->af - b->af) != 0)
! 425: return (diff);
! 426: switch (a->af) {
! 427: #ifdef INET
! 428: case AF_INET:
! 429: if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
! 430: return (1);
! 431: if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
! 432: return (-1);
! 433: if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
! 434: return (1);
! 435: if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
! 436: return (-1);
! 437: break;
! 438: #endif /* INET */
! 439: #ifdef INET6
! 440: case AF_INET6:
! 441: if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
! 442: return (1);
! 443: if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
! 444: return (-1);
! 445: if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
! 446: return (1);
! 447: if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
! 448: return (-1);
! 449: if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
! 450: return (1);
! 451: if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
! 452: return (-1);
! 453: if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
! 454: return (1);
! 455: if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
! 456: return (-1);
! 457: if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
! 458: return (1);
! 459: if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
! 460: return (-1);
! 461: if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
! 462: return (1);
! 463: if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
! 464: return (-1);
! 465: if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
! 466: return (1);
! 467: if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
! 468: return (-1);
! 469: if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
! 470: return (1);
! 471: if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
! 472: return (-1);
! 473: break;
! 474: #endif /* INET6 */
! 475: }
! 476:
! 477: if ((diff = a->ext.port - b->ext.port) != 0)
! 478: return (diff);
! 479: if ((diff = a->gwy.port - b->gwy.port) != 0)
! 480: return (diff);
! 481:
! 482: return (0);
! 483: }
! 484:
! 485: static __inline int
! 486: pf_state_compare_id(struct pf_state *a, struct pf_state *b)
! 487: {
! 488: if (a->id > b->id)
! 489: return (1);
! 490: if (a->id < b->id)
! 491: return (-1);
! 492: if (a->creatorid > b->creatorid)
! 493: return (1);
! 494: if (a->creatorid < b->creatorid)
! 495: return (-1);
! 496:
! 497: return (0);
! 498: }
! 499:
! 500: #ifdef INET6
! 501: void
! 502: pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
! 503: {
! 504: switch (af) {
! 505: #ifdef INET
! 506: case AF_INET:
! 507: dst->addr32[0] = src->addr32[0];
! 508: break;
! 509: #endif /* INET */
! 510: case AF_INET6:
! 511: dst->addr32[0] = src->addr32[0];
! 512: dst->addr32[1] = src->addr32[1];
! 513: dst->addr32[2] = src->addr32[2];
! 514: dst->addr32[3] = src->addr32[3];
! 515: break;
! 516: }
! 517: }
! 518: #endif /* INET6 */
! 519:
! 520: struct pf_state *
! 521: pf_find_state_byid(struct pf_state_cmp *key)
! 522: {
! 523: pf_status.fcounters[FCNT_STATE_SEARCH]++;
! 524:
! 525: return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key));
! 526: }
! 527:
! 528: struct pf_state *
! 529: pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int8_t tree)
! 530: {
! 531: struct pf_state_key *sk;
! 532: struct pf_state *s;
! 533:
! 534: pf_status.fcounters[FCNT_STATE_SEARCH]++;
! 535:
! 536: switch (tree) {
! 537: case PF_LAN_EXT:
! 538: sk = RB_FIND(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
! 539: (struct pf_state_key *)key);
! 540: break;
! 541: case PF_EXT_GWY:
! 542: sk = RB_FIND(pf_state_tree_ext_gwy, &pf_statetbl_ext_gwy,
! 543: (struct pf_state_key *)key);
! 544: break;
! 545: default:
! 546: panic("pf_find_state");
! 547: }
! 548:
! 549: /* list is sorted, if-bound states before floating ones */
! 550: if (sk != NULL)
! 551: TAILQ_FOREACH(s, &sk->states, next)
! 552: if (s->kif == pfi_all || s->kif == kif)
! 553: return (s);
! 554:
! 555: return (NULL);
! 556: }
! 557:
! 558: struct pf_state *
! 559: pf_find_state_all(struct pf_state_key_cmp *key, u_int8_t tree, int *more)
! 560: {
! 561: struct pf_state_key *sk;
! 562: struct pf_state *s, *ret = NULL;
! 563:
! 564: pf_status.fcounters[FCNT_STATE_SEARCH]++;
! 565:
! 566: switch (tree) {
! 567: case PF_LAN_EXT:
! 568: sk = RB_FIND(pf_state_tree_lan_ext,
! 569: &pf_statetbl_lan_ext, (struct pf_state_key *)key);
! 570: break;
! 571: case PF_EXT_GWY:
! 572: sk = RB_FIND(pf_state_tree_ext_gwy,
! 573: &pf_statetbl_ext_gwy, (struct pf_state_key *)key);
! 574: break;
! 575: default:
! 576: panic("pf_find_state_all");
! 577: }
! 578:
! 579: if (sk != NULL) {
! 580: ret = TAILQ_FIRST(&sk->states);
! 581: if (more == NULL)
! 582: return (ret);
! 583:
! 584: TAILQ_FOREACH(s, &sk->states, next)
! 585: (*more)++;
! 586: }
! 587:
! 588: return (ret);
! 589: }
! 590:
! 591: void
! 592: pf_init_threshold(struct pf_threshold *threshold,
! 593: u_int32_t limit, u_int32_t seconds)
! 594: {
! 595: threshold->limit = limit * PF_THRESHOLD_MULT;
! 596: threshold->seconds = seconds;
! 597: threshold->count = 0;
! 598: threshold->last = time_second;
! 599: }
! 600:
! 601: void
! 602: pf_add_threshold(struct pf_threshold *threshold)
! 603: {
! 604: u_int32_t t = time_second, diff = t - threshold->last;
! 605:
! 606: if (diff >= threshold->seconds)
! 607: threshold->count = 0;
! 608: else
! 609: threshold->count -= threshold->count * diff /
! 610: threshold->seconds;
! 611: threshold->count += PF_THRESHOLD_MULT;
! 612: threshold->last = t;
! 613: }
! 614:
! 615: int
! 616: pf_check_threshold(struct pf_threshold *threshold)
! 617: {
! 618: return (threshold->count > threshold->limit);
! 619: }
! 620:
! 621: int
! 622: pf_src_connlimit(struct pf_state **state)
! 623: {
! 624: int bad = 0;
! 625:
! 626: (*state)->src_node->conn++;
! 627: (*state)->src.tcp_est = 1;
! 628: pf_add_threshold(&(*state)->src_node->conn_rate);
! 629:
! 630: if ((*state)->rule.ptr->max_src_conn &&
! 631: (*state)->rule.ptr->max_src_conn <
! 632: (*state)->src_node->conn) {
! 633: pf_status.lcounters[LCNT_SRCCONN]++;
! 634: bad++;
! 635: }
! 636:
! 637: if ((*state)->rule.ptr->max_src_conn_rate.limit &&
! 638: pf_check_threshold(&(*state)->src_node->conn_rate)) {
! 639: pf_status.lcounters[LCNT_SRCCONNRATE]++;
! 640: bad++;
! 641: }
! 642:
! 643: if (!bad)
! 644: return (0);
! 645:
! 646: if ((*state)->rule.ptr->overload_tbl) {
! 647: struct pfr_addr p;
! 648: u_int32_t killed = 0;
! 649:
! 650: pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
! 651: if (pf_status.debug >= PF_DEBUG_MISC) {
! 652: printf("pf_src_connlimit: blocking address ");
! 653: pf_print_host(&(*state)->src_node->addr, 0,
! 654: (*state)->state_key->af);
! 655: }
! 656:
! 657: bzero(&p, sizeof(p));
! 658: p.pfra_af = (*state)->state_key->af;
! 659: switch ((*state)->state_key->af) {
! 660: #ifdef INET
! 661: case AF_INET:
! 662: p.pfra_net = 32;
! 663: p.pfra_ip4addr = (*state)->src_node->addr.v4;
! 664: break;
! 665: #endif /* INET */
! 666: #ifdef INET6
! 667: case AF_INET6:
! 668: p.pfra_net = 128;
! 669: p.pfra_ip6addr = (*state)->src_node->addr.v6;
! 670: break;
! 671: #endif /* INET6 */
! 672: }
! 673:
! 674: pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
! 675: &p, time_second);
! 676:
! 677: /* kill existing states if that's required. */
! 678: if ((*state)->rule.ptr->flush) {
! 679: struct pf_state_key *sk;
! 680: struct pf_state *st;
! 681:
! 682: pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
! 683: RB_FOREACH(st, pf_state_tree_id, &tree_id) {
! 684: sk = st->state_key;
! 685: /*
! 686: * Kill states from this source. (Only those
! 687: * from the same rule if PF_FLUSH_GLOBAL is not
! 688: * set)
! 689: */
! 690: if (sk->af ==
! 691: (*state)->state_key->af &&
! 692: (((*state)->state_key->direction ==
! 693: PF_OUT &&
! 694: PF_AEQ(&(*state)->src_node->addr,
! 695: &sk->lan.addr, sk->af)) ||
! 696: ((*state)->state_key->direction == PF_IN &&
! 697: PF_AEQ(&(*state)->src_node->addr,
! 698: &sk->ext.addr, sk->af))) &&
! 699: ((*state)->rule.ptr->flush &
! 700: PF_FLUSH_GLOBAL ||
! 701: (*state)->rule.ptr == st->rule.ptr)) {
! 702: st->timeout = PFTM_PURGE;
! 703: st->src.state = st->dst.state =
! 704: TCPS_CLOSED;
! 705: killed++;
! 706: }
! 707: }
! 708: if (pf_status.debug >= PF_DEBUG_MISC)
! 709: printf(", %u states killed", killed);
! 710: }
! 711: if (pf_status.debug >= PF_DEBUG_MISC)
! 712: printf("\n");
! 713: }
! 714:
! 715: /* kill this state */
! 716: (*state)->timeout = PFTM_PURGE;
! 717: (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
! 718: return (1);
! 719: }
! 720:
! 721: int
! 722: pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
! 723: struct pf_addr *src, sa_family_t af)
! 724: {
! 725: struct pf_src_node k;
! 726:
! 727: if (*sn == NULL) {
! 728: k.af = af;
! 729: PF_ACPY(&k.addr, src, af);
! 730: if (rule->rule_flag & PFRULE_RULESRCTRACK ||
! 731: rule->rpool.opts & PF_POOL_STICKYADDR)
! 732: k.rule.ptr = rule;
! 733: else
! 734: k.rule.ptr = NULL;
! 735: pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
! 736: *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
! 737: }
! 738: if (*sn == NULL) {
! 739: if (!rule->max_src_nodes ||
! 740: rule->src_nodes < rule->max_src_nodes)
! 741: (*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
! 742: else
! 743: pf_status.lcounters[LCNT_SRCNODES]++;
! 744: if ((*sn) == NULL)
! 745: return (-1);
! 746: bzero(*sn, sizeof(struct pf_src_node));
! 747:
! 748: pf_init_threshold(&(*sn)->conn_rate,
! 749: rule->max_src_conn_rate.limit,
! 750: rule->max_src_conn_rate.seconds);
! 751:
! 752: (*sn)->af = af;
! 753: if (rule->rule_flag & PFRULE_RULESRCTRACK ||
! 754: rule->rpool.opts & PF_POOL_STICKYADDR)
! 755: (*sn)->rule.ptr = rule;
! 756: else
! 757: (*sn)->rule.ptr = NULL;
! 758: PF_ACPY(&(*sn)->addr, src, af);
! 759: if (RB_INSERT(pf_src_tree,
! 760: &tree_src_tracking, *sn) != NULL) {
! 761: if (pf_status.debug >= PF_DEBUG_MISC) {
! 762: printf("pf: src_tree insert failed: ");
! 763: pf_print_host(&(*sn)->addr, 0, af);
! 764: printf("\n");
! 765: }
! 766: pool_put(&pf_src_tree_pl, *sn);
! 767: return (-1);
! 768: }
! 769: (*sn)->creation = time_second;
! 770: (*sn)->ruletype = rule->action;
! 771: if ((*sn)->rule.ptr != NULL)
! 772: (*sn)->rule.ptr->src_nodes++;
! 773: pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
! 774: pf_status.src_nodes++;
! 775: } else {
! 776: if (rule->max_src_states &&
! 777: (*sn)->states >= rule->max_src_states) {
! 778: pf_status.lcounters[LCNT_SRCSTATES]++;
! 779: return (-1);
! 780: }
! 781: }
! 782: return (0);
! 783: }
! 784:
! 785: void
! 786: pf_stateins_err(const char *tree, struct pf_state *s, struct pfi_kif *kif)
! 787: {
! 788: struct pf_state_key *sk = s->state_key;
! 789:
! 790: if (pf_status.debug >= PF_DEBUG_MISC) {
! 791: printf("pf: state insert failed: %s %s", tree, kif->pfik_name);
! 792: printf(" lan: ");
! 793: pf_print_host(&sk->lan.addr, sk->lan.port,
! 794: sk->af);
! 795: printf(" gwy: ");
! 796: pf_print_host(&sk->gwy.addr, sk->gwy.port,
! 797: sk->af);
! 798: printf(" ext: ");
! 799: pf_print_host(&sk->ext.addr, sk->ext.port,
! 800: sk->af);
! 801: if (s->sync_flags & PFSTATE_FROMSYNC)
! 802: printf(" (from sync)");
! 803: printf("\n");
! 804: }
! 805: }
! 806:
! 807: int
! 808: pf_insert_state(struct pfi_kif *kif, struct pf_state *s)
! 809: {
! 810: struct pf_state_key *cur;
! 811: struct pf_state *sp;
! 812:
! 813: KASSERT(s->state_key != NULL);
! 814: s->kif = kif;
! 815:
! 816: if ((cur = RB_INSERT(pf_state_tree_lan_ext, &pf_statetbl_lan_ext,
! 817: s->state_key)) != NULL) {
! 818: /* key exists. check for same kif, if none, add to key */
! 819: TAILQ_FOREACH(sp, &cur->states, next)
! 820: if (sp->kif == kif) { /* collision! */
! 821: pf_stateins_err("tree_lan_ext", s, kif);
! 822: return (-1);
! 823: }
! 824: pf_detach_state(s, PF_DT_SKIP_LANEXT|PF_DT_SKIP_EXTGWY);
! 825: pf_attach_state(cur, s, kif == pfi_all ? 1 : 0);
! 826: }
! 827:
! 828: /* if cur != NULL, we already found a state key and attached to it */
! 829: if (cur == NULL && (cur = RB_INSERT(pf_state_tree_ext_gwy,
! 830: &pf_statetbl_ext_gwy, s->state_key)) != NULL) {
! 831: /* must not happen. we must have found the sk above! */
! 832: pf_stateins_err("tree_ext_gwy", s, kif);
! 833: pf_detach_state(s, PF_DT_SKIP_EXTGWY);
! 834: return (-1);
! 835: }
! 836:
! 837: if (s->id == 0 && s->creatorid == 0) {
! 838: s->id = htobe64(pf_status.stateid++);
! 839: s->creatorid = pf_status.hostid;
! 840: }
! 841: if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) {
! 842: if (pf_status.debug >= PF_DEBUG_MISC) {
! 843: printf("pf: state insert failed: "
! 844: "id: %016llx creatorid: %08x",
! 845: betoh64(s->id), ntohl(s->creatorid));
! 846: if (s->sync_flags & PFSTATE_FROMSYNC)
! 847: printf(" (from sync)");
! 848: printf("\n");
! 849: }
! 850: pf_detach_state(s, 0);
! 851: return (-1);
! 852: }
! 853: TAILQ_INSERT_TAIL(&state_list, s, entry_list);
! 854: pf_status.fcounters[FCNT_STATE_INSERT]++;
! 855: pf_status.states++;
! 856: pfi_kif_ref(kif, PFI_KIF_REF_STATE);
! 857: #if NPFSYNC
! 858: pfsync_insert_state(s);
! 859: #endif
! 860: return (0);
! 861: }
! 862:
! 863: void
! 864: pf_purge_thread(void *v)
! 865: {
! 866: int nloops = 0, s;
! 867:
! 868: for (;;) {
! 869: tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
! 870:
! 871: s = splsoftnet();
! 872:
! 873: /* process a fraction of the state table every second */
! 874: pf_purge_expired_states(1 + (pf_status.states
! 875: / pf_default_rule.timeout[PFTM_INTERVAL]));
! 876:
! 877: /* purge other expired types every PFTM_INTERVAL seconds */
! 878: if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
! 879: pf_purge_expired_fragments();
! 880: pf_purge_expired_src_nodes(0);
! 881: nloops = 0;
! 882: }
! 883:
! 884: splx(s);
! 885: }
! 886: }
! 887:
! 888: u_int32_t
! 889: pf_state_expires(const struct pf_state *state)
! 890: {
! 891: u_int32_t timeout;
! 892: u_int32_t start;
! 893: u_int32_t end;
! 894: u_int32_t states;
! 895:
! 896: /* handle all PFTM_* > PFTM_MAX here */
! 897: if (state->timeout == PFTM_PURGE)
! 898: return (time_second);
! 899: if (state->timeout == PFTM_UNTIL_PACKET)
! 900: return (0);
! 901: KASSERT(state->timeout != PFTM_UNLINKED);
! 902: KASSERT(state->timeout < PFTM_MAX);
! 903: timeout = state->rule.ptr->timeout[state->timeout];
! 904: if (!timeout)
! 905: timeout = pf_default_rule.timeout[state->timeout];
! 906: start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
! 907: if (start) {
! 908: end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
! 909: states = state->rule.ptr->states;
! 910: } else {
! 911: start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
! 912: end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
! 913: states = pf_status.states;
! 914: }
! 915: if (end && states > start && start < end) {
! 916: if (states < end)
! 917: return (state->expire + timeout * (end - states) /
! 918: (end - start));
! 919: else
! 920: return (time_second);
! 921: }
! 922: return (state->expire + timeout);
! 923: }
! 924:
! 925: void
! 926: pf_purge_expired_src_nodes(int waslocked)
! 927: {
! 928: struct pf_src_node *cur, *next;
! 929: int locked = waslocked;
! 930:
! 931: for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
! 932: next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
! 933:
! 934: if (cur->states <= 0 && cur->expire <= time_second) {
! 935: if (! locked) {
! 936: rw_enter_write(&pf_consistency_lock);
! 937: next = RB_NEXT(pf_src_tree,
! 938: &tree_src_tracking, cur);
! 939: locked = 1;
! 940: }
! 941: if (cur->rule.ptr != NULL) {
! 942: cur->rule.ptr->src_nodes--;
! 943: if (cur->rule.ptr->states <= 0 &&
! 944: cur->rule.ptr->max_src_nodes <= 0)
! 945: pf_rm_rule(NULL, cur->rule.ptr);
! 946: }
! 947: RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
! 948: pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
! 949: pf_status.src_nodes--;
! 950: pool_put(&pf_src_tree_pl, cur);
! 951: }
! 952: }
! 953:
! 954: if (locked && !waslocked)
! 955: rw_exit_write(&pf_consistency_lock);
! 956: }
! 957:
! 958: void
! 959: pf_src_tree_remove_state(struct pf_state *s)
! 960: {
! 961: u_int32_t timeout;
! 962:
! 963: if (s->src_node != NULL) {
! 964: if (s->state_key->proto == IPPROTO_TCP) {
! 965: if (s->src.tcp_est)
! 966: --s->src_node->conn;
! 967: }
! 968: if (--s->src_node->states <= 0) {
! 969: timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
! 970: if (!timeout)
! 971: timeout =
! 972: pf_default_rule.timeout[PFTM_SRC_NODE];
! 973: s->src_node->expire = time_second + timeout;
! 974: }
! 975: }
! 976: if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
! 977: if (--s->nat_src_node->states <= 0) {
! 978: timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
! 979: if (!timeout)
! 980: timeout =
! 981: pf_default_rule.timeout[PFTM_SRC_NODE];
! 982: s->nat_src_node->expire = time_second + timeout;
! 983: }
! 984: }
! 985: s->src_node = s->nat_src_node = NULL;
! 986: }
! 987:
! 988: /* callers should be at splsoftnet */
! 989: void
! 990: pf_unlink_state(struct pf_state *cur)
! 991: {
! 992: if (cur->src.state == PF_TCPS_PROXY_DST) {
! 993: pf_send_tcp(cur->rule.ptr, cur->state_key->af,
! 994: &cur->state_key->ext.addr, &cur->state_key->lan.addr,
! 995: cur->state_key->ext.port, cur->state_key->lan.port,
! 996: cur->src.seqhi, cur->src.seqlo + 1,
! 997: TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL);
! 998: }
! 999: RB_REMOVE(pf_state_tree_id, &tree_id, cur);
! 1000: #if NPFSYNC
! 1001: if (cur->creatorid == pf_status.hostid)
! 1002: pfsync_delete_state(cur);
! 1003: #endif
! 1004: cur->timeout = PFTM_UNLINKED;
! 1005: pf_src_tree_remove_state(cur);
! 1006: pf_detach_state(cur, 0);
! 1007: }
! 1008:
! 1009: /* callers should be at splsoftnet and hold the
! 1010: * write_lock on pf_consistency_lock */
! 1011: void
! 1012: pf_free_state(struct pf_state *cur)
! 1013: {
! 1014: #if NPFSYNC
! 1015: if (pfsyncif != NULL &&
! 1016: (pfsyncif->sc_bulk_send_next == cur ||
! 1017: pfsyncif->sc_bulk_terminator == cur))
! 1018: return;
! 1019: #endif
! 1020: KASSERT(cur->timeout == PFTM_UNLINKED);
! 1021: if (--cur->rule.ptr->states <= 0 &&
! 1022: cur->rule.ptr->src_nodes <= 0)
! 1023: pf_rm_rule(NULL, cur->rule.ptr);
! 1024: if (cur->nat_rule.ptr != NULL)
! 1025: if (--cur->nat_rule.ptr->states <= 0 &&
! 1026: cur->nat_rule.ptr->src_nodes <= 0)
! 1027: pf_rm_rule(NULL, cur->nat_rule.ptr);
! 1028: if (cur->anchor.ptr != NULL)
! 1029: if (--cur->anchor.ptr->states <= 0)
! 1030: pf_rm_rule(NULL, cur->anchor.ptr);
! 1031: pf_normalize_tcp_cleanup(cur);
! 1032: pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
! 1033: TAILQ_REMOVE(&state_list, cur, entry_list);
! 1034: if (cur->tag)
! 1035: pf_tag_unref(cur->tag);
! 1036: pool_put(&pf_state_pl, cur);
! 1037: pf_status.fcounters[FCNT_STATE_REMOVALS]++;
! 1038: pf_status.states--;
! 1039: }
! 1040:
! 1041: void
! 1042: pf_purge_expired_states(u_int32_t maxcheck)
! 1043: {
! 1044: static struct pf_state *cur = NULL;
! 1045: struct pf_state *next;
! 1046: int locked = 0;
! 1047:
! 1048: while (maxcheck--) {
! 1049: /* wrap to start of list when we hit the end */
! 1050: if (cur == NULL) {
! 1051: cur = TAILQ_FIRST(&state_list);
! 1052: if (cur == NULL)
! 1053: break; /* list empty */
! 1054: }
! 1055:
! 1056: /* get next state, as cur may get deleted */
! 1057: next = TAILQ_NEXT(cur, entry_list);
! 1058:
! 1059: if (cur->timeout == PFTM_UNLINKED) {
! 1060: /* free unlinked state */
! 1061: if (! locked) {
! 1062: rw_enter_write(&pf_consistency_lock);
! 1063: locked = 1;
! 1064: }
! 1065: pf_free_state(cur);
! 1066: } else if (pf_state_expires(cur) <= time_second) {
! 1067: /* unlink and free expired state */
! 1068: pf_unlink_state(cur);
! 1069: if (! locked) {
! 1070: rw_enter_write(&pf_consistency_lock);
! 1071: locked = 1;
! 1072: }
! 1073: pf_free_state(cur);
! 1074: }
! 1075: cur = next;
! 1076: }
! 1077:
! 1078: if (locked)
! 1079: rw_exit_write(&pf_consistency_lock);
! 1080: }
! 1081:
! 1082: int
! 1083: pf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
! 1084: {
! 1085: if (aw->type != PF_ADDR_TABLE)
! 1086: return (0);
! 1087: if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
! 1088: return (1);
! 1089: return (0);
! 1090: }
! 1091:
! 1092: void
! 1093: pf_tbladdr_remove(struct pf_addr_wrap *aw)
! 1094: {
! 1095: if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
! 1096: return;
! 1097: pfr_detach_table(aw->p.tbl);
! 1098: aw->p.tbl = NULL;
! 1099: }
! 1100:
! 1101: void
! 1102: pf_tbladdr_copyout(struct pf_addr_wrap *aw)
! 1103: {
! 1104: struct pfr_ktable *kt = aw->p.tbl;
! 1105:
! 1106: if (aw->type != PF_ADDR_TABLE || kt == NULL)
! 1107: return;
! 1108: if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
! 1109: kt = kt->pfrkt_root;
! 1110: aw->p.tbl = NULL;
! 1111: aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
! 1112: kt->pfrkt_cnt : -1;
! 1113: }
! 1114:
! 1115: void
! 1116: pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
! 1117: {
! 1118: switch (af) {
! 1119: #ifdef INET
! 1120: case AF_INET: {
! 1121: u_int32_t a = ntohl(addr->addr32[0]);
! 1122: printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
! 1123: (a>>8)&255, a&255);
! 1124: if (p) {
! 1125: p = ntohs(p);
! 1126: printf(":%u", p);
! 1127: }
! 1128: break;
! 1129: }
! 1130: #endif /* INET */
! 1131: #ifdef INET6
! 1132: case AF_INET6: {
! 1133: u_int16_t b;
! 1134: u_int8_t i, curstart = 255, curend = 0,
! 1135: maxstart = 0, maxend = 0;
! 1136: for (i = 0; i < 8; i++) {
! 1137: if (!addr->addr16[i]) {
! 1138: if (curstart == 255)
! 1139: curstart = i;
! 1140: else
! 1141: curend = i;
! 1142: } else {
! 1143: if (curstart) {
! 1144: if ((curend - curstart) >
! 1145: (maxend - maxstart)) {
! 1146: maxstart = curstart;
! 1147: maxend = curend;
! 1148: curstart = 255;
! 1149: }
! 1150: }
! 1151: }
! 1152: }
! 1153: for (i = 0; i < 8; i++) {
! 1154: if (i >= maxstart && i <= maxend) {
! 1155: if (maxend != 7) {
! 1156: if (i == maxstart)
! 1157: printf(":");
! 1158: } else {
! 1159: if (i == maxend)
! 1160: printf(":");
! 1161: }
! 1162: } else {
! 1163: b = ntohs(addr->addr16[i]);
! 1164: printf("%x", b);
! 1165: if (i < 7)
! 1166: printf(":");
! 1167: }
! 1168: }
! 1169: if (p) {
! 1170: p = ntohs(p);
! 1171: printf("[%u]", p);
! 1172: }
! 1173: break;
! 1174: }
! 1175: #endif /* INET6 */
! 1176: }
! 1177: }
! 1178:
! 1179: void
! 1180: pf_print_state(struct pf_state *s)
! 1181: {
! 1182: struct pf_state_key *sk = s->state_key;
! 1183: switch (sk->proto) {
! 1184: case IPPROTO_TCP:
! 1185: printf("TCP ");
! 1186: break;
! 1187: case IPPROTO_UDP:
! 1188: printf("UDP ");
! 1189: break;
! 1190: case IPPROTO_ICMP:
! 1191: printf("ICMP ");
! 1192: break;
! 1193: case IPPROTO_ICMPV6:
! 1194: printf("ICMPV6 ");
! 1195: break;
! 1196: default:
! 1197: printf("%u ", sk->proto);
! 1198: break;
! 1199: }
! 1200: pf_print_host(&sk->lan.addr, sk->lan.port, sk->af);
! 1201: printf(" ");
! 1202: pf_print_host(&sk->gwy.addr, sk->gwy.port, sk->af);
! 1203: printf(" ");
! 1204: pf_print_host(&sk->ext.addr, sk->ext.port, sk->af);
! 1205: printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
! 1206: s->src.seqhi, s->src.max_win, s->src.seqdiff);
! 1207: if (s->src.wscale && s->dst.wscale)
! 1208: printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
! 1209: printf("]");
! 1210: printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
! 1211: s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
! 1212: if (s->src.wscale && s->dst.wscale)
! 1213: printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
! 1214: printf("]");
! 1215: printf(" %u:%u", s->src.state, s->dst.state);
! 1216: }
! 1217:
! 1218: void
! 1219: pf_print_flags(u_int8_t f)
! 1220: {
! 1221: if (f)
! 1222: printf(" ");
! 1223: if (f & TH_FIN)
! 1224: printf("F");
! 1225: if (f & TH_SYN)
! 1226: printf("S");
! 1227: if (f & TH_RST)
! 1228: printf("R");
! 1229: if (f & TH_PUSH)
! 1230: printf("P");
! 1231: if (f & TH_ACK)
! 1232: printf("A");
! 1233: if (f & TH_URG)
! 1234: printf("U");
! 1235: if (f & TH_ECE)
! 1236: printf("E");
! 1237: if (f & TH_CWR)
! 1238: printf("W");
! 1239: }
! 1240:
! 1241: #define PF_SET_SKIP_STEPS(i) \
! 1242: do { \
! 1243: while (head[i] != cur) { \
! 1244: head[i]->skip[i].ptr = cur; \
! 1245: head[i] = TAILQ_NEXT(head[i], entries); \
! 1246: } \
! 1247: } while (0)
! 1248:
! 1249: void
! 1250: pf_calc_skip_steps(struct pf_rulequeue *rules)
! 1251: {
! 1252: struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
! 1253: int i;
! 1254:
! 1255: cur = TAILQ_FIRST(rules);
! 1256: prev = cur;
! 1257: for (i = 0; i < PF_SKIP_COUNT; ++i)
! 1258: head[i] = cur;
! 1259: while (cur != NULL) {
! 1260:
! 1261: if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
! 1262: PF_SET_SKIP_STEPS(PF_SKIP_IFP);
! 1263: if (cur->direction != prev->direction)
! 1264: PF_SET_SKIP_STEPS(PF_SKIP_DIR);
! 1265: if (cur->af != prev->af)
! 1266: PF_SET_SKIP_STEPS(PF_SKIP_AF);
! 1267: if (cur->proto != prev->proto)
! 1268: PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
! 1269: if (cur->src.neg != prev->src.neg ||
! 1270: pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
! 1271: PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
! 1272: if (cur->src.port[0] != prev->src.port[0] ||
! 1273: cur->src.port[1] != prev->src.port[1] ||
! 1274: cur->src.port_op != prev->src.port_op)
! 1275: PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
! 1276: if (cur->dst.neg != prev->dst.neg ||
! 1277: pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
! 1278: PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
! 1279: if (cur->dst.port[0] != prev->dst.port[0] ||
! 1280: cur->dst.port[1] != prev->dst.port[1] ||
! 1281: cur->dst.port_op != prev->dst.port_op)
! 1282: PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
! 1283:
! 1284: prev = cur;
! 1285: cur = TAILQ_NEXT(cur, entries);
! 1286: }
! 1287: for (i = 0; i < PF_SKIP_COUNT; ++i)
! 1288: PF_SET_SKIP_STEPS(i);
! 1289: }
! 1290:
! 1291: int
! 1292: pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
! 1293: {
! 1294: if (aw1->type != aw2->type)
! 1295: return (1);
! 1296: switch (aw1->type) {
! 1297: case PF_ADDR_ADDRMASK:
! 1298: if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
! 1299: return (1);
! 1300: if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
! 1301: return (1);
! 1302: return (0);
! 1303: case PF_ADDR_DYNIFTL:
! 1304: return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
! 1305: case PF_ADDR_NOROUTE:
! 1306: case PF_ADDR_URPFFAILED:
! 1307: return (0);
! 1308: case PF_ADDR_TABLE:
! 1309: return (aw1->p.tbl != aw2->p.tbl);
! 1310: case PF_ADDR_RTLABEL:
! 1311: return (aw1->v.rtlabel != aw2->v.rtlabel);
! 1312: default:
! 1313: printf("invalid address type: %d\n", aw1->type);
! 1314: return (1);
! 1315: }
! 1316: }
! 1317:
! 1318: u_int16_t
! 1319: pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
! 1320: {
! 1321: u_int32_t l;
! 1322:
! 1323: if (udp && !cksum)
! 1324: return (0x0000);
! 1325: l = cksum + old - new;
! 1326: l = (l >> 16) + (l & 65535);
! 1327: l = l & 65535;
! 1328: if (udp && !l)
! 1329: return (0xFFFF);
! 1330: return (l);
! 1331: }
! 1332:
! 1333: void
! 1334: pf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
! 1335: struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
! 1336: {
! 1337: struct pf_addr ao;
! 1338: u_int16_t po = *p;
! 1339:
! 1340: PF_ACPY(&ao, a, af);
! 1341: PF_ACPY(a, an, af);
! 1342:
! 1343: *p = pn;
! 1344:
! 1345: switch (af) {
! 1346: #ifdef INET
! 1347: case AF_INET:
! 1348: *ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
! 1349: ao.addr16[0], an->addr16[0], 0),
! 1350: ao.addr16[1], an->addr16[1], 0);
! 1351: *p = pn;
! 1352: *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
! 1353: ao.addr16[0], an->addr16[0], u),
! 1354: ao.addr16[1], an->addr16[1], u),
! 1355: po, pn, u);
! 1356: break;
! 1357: #endif /* INET */
! 1358: #ifdef INET6
! 1359: case AF_INET6:
! 1360: *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1361: pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1362: pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
! 1363: ao.addr16[0], an->addr16[0], u),
! 1364: ao.addr16[1], an->addr16[1], u),
! 1365: ao.addr16[2], an->addr16[2], u),
! 1366: ao.addr16[3], an->addr16[3], u),
! 1367: ao.addr16[4], an->addr16[4], u),
! 1368: ao.addr16[5], an->addr16[5], u),
! 1369: ao.addr16[6], an->addr16[6], u),
! 1370: ao.addr16[7], an->addr16[7], u),
! 1371: po, pn, u);
! 1372: break;
! 1373: #endif /* INET6 */
! 1374: }
! 1375: }
! 1376:
! 1377:
! 1378: /* Changes a u_int32_t. Uses a void * so there are no align restrictions */
! 1379: void
! 1380: pf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
! 1381: {
! 1382: u_int32_t ao;
! 1383:
! 1384: memcpy(&ao, a, sizeof(ao));
! 1385: memcpy(a, &an, sizeof(u_int32_t));
! 1386: *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
! 1387: ao % 65536, an % 65536, u);
! 1388: }
! 1389:
! 1390: #ifdef INET6
! 1391: void
! 1392: pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
! 1393: {
! 1394: struct pf_addr ao;
! 1395:
! 1396: PF_ACPY(&ao, a, AF_INET6);
! 1397: PF_ACPY(a, an, AF_INET6);
! 1398:
! 1399: *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1400: pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1401: pf_cksum_fixup(pf_cksum_fixup(*c,
! 1402: ao.addr16[0], an->addr16[0], u),
! 1403: ao.addr16[1], an->addr16[1], u),
! 1404: ao.addr16[2], an->addr16[2], u),
! 1405: ao.addr16[3], an->addr16[3], u),
! 1406: ao.addr16[4], an->addr16[4], u),
! 1407: ao.addr16[5], an->addr16[5], u),
! 1408: ao.addr16[6], an->addr16[6], u),
! 1409: ao.addr16[7], an->addr16[7], u);
! 1410: }
! 1411: #endif /* INET6 */
! 1412:
! 1413: void
! 1414: pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
! 1415: struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
! 1416: u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
! 1417: {
! 1418: struct pf_addr oia, ooa;
! 1419:
! 1420: PF_ACPY(&oia, ia, af);
! 1421: PF_ACPY(&ooa, oa, af);
! 1422:
! 1423: /* Change inner protocol port, fix inner protocol checksum. */
! 1424: if (ip != NULL) {
! 1425: u_int16_t oip = *ip;
! 1426: u_int32_t opc;
! 1427:
! 1428: if (pc != NULL)
! 1429: opc = *pc;
! 1430: *ip = np;
! 1431: if (pc != NULL)
! 1432: *pc = pf_cksum_fixup(*pc, oip, *ip, u);
! 1433: *ic = pf_cksum_fixup(*ic, oip, *ip, 0);
! 1434: if (pc != NULL)
! 1435: *ic = pf_cksum_fixup(*ic, opc, *pc, 0);
! 1436: }
! 1437: /* Change inner ip address, fix inner ip and icmp checksums. */
! 1438: PF_ACPY(ia, na, af);
! 1439: switch (af) {
! 1440: #ifdef INET
! 1441: case AF_INET: {
! 1442: u_int32_t oh2c = *h2c;
! 1443:
! 1444: *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
! 1445: oia.addr16[0], ia->addr16[0], 0),
! 1446: oia.addr16[1], ia->addr16[1], 0);
! 1447: *ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
! 1448: oia.addr16[0], ia->addr16[0], 0),
! 1449: oia.addr16[1], ia->addr16[1], 0);
! 1450: *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
! 1451: break;
! 1452: }
! 1453: #endif /* INET */
! 1454: #ifdef INET6
! 1455: case AF_INET6:
! 1456: *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1457: pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1458: pf_cksum_fixup(pf_cksum_fixup(*ic,
! 1459: oia.addr16[0], ia->addr16[0], u),
! 1460: oia.addr16[1], ia->addr16[1], u),
! 1461: oia.addr16[2], ia->addr16[2], u),
! 1462: oia.addr16[3], ia->addr16[3], u),
! 1463: oia.addr16[4], ia->addr16[4], u),
! 1464: oia.addr16[5], ia->addr16[5], u),
! 1465: oia.addr16[6], ia->addr16[6], u),
! 1466: oia.addr16[7], ia->addr16[7], u);
! 1467: break;
! 1468: #endif /* INET6 */
! 1469: }
! 1470: /* Change outer ip address, fix outer ip or icmpv6 checksum. */
! 1471: PF_ACPY(oa, na, af);
! 1472: switch (af) {
! 1473: #ifdef INET
! 1474: case AF_INET:
! 1475: *hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
! 1476: ooa.addr16[0], oa->addr16[0], 0),
! 1477: ooa.addr16[1], oa->addr16[1], 0);
! 1478: break;
! 1479: #endif /* INET */
! 1480: #ifdef INET6
! 1481: case AF_INET6:
! 1482: *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1483: pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
! 1484: pf_cksum_fixup(pf_cksum_fixup(*ic,
! 1485: ooa.addr16[0], oa->addr16[0], u),
! 1486: ooa.addr16[1], oa->addr16[1], u),
! 1487: ooa.addr16[2], oa->addr16[2], u),
! 1488: ooa.addr16[3], oa->addr16[3], u),
! 1489: ooa.addr16[4], oa->addr16[4], u),
! 1490: ooa.addr16[5], oa->addr16[5], u),
! 1491: ooa.addr16[6], oa->addr16[6], u),
! 1492: ooa.addr16[7], oa->addr16[7], u);
! 1493: break;
! 1494: #endif /* INET6 */
! 1495: }
! 1496: }
! 1497:
! 1498:
! 1499: /*
! 1500: * Need to modulate the sequence numbers in the TCP SACK option
! 1501: * (credits to Krzysztof Pfaff for report and patch)
! 1502: */
! 1503: int
! 1504: pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd,
! 1505: struct tcphdr *th, struct pf_state_peer *dst)
! 1506: {
! 1507: int hlen = (th->th_off << 2) - sizeof(*th), thoptlen = hlen;
! 1508: u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
! 1509: int copyback = 0, i, olen;
! 1510: struct sackblk sack;
! 1511:
! 1512: #define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2)
! 1513: if (hlen < TCPOLEN_SACKLEN ||
! 1514: !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af))
! 1515: return 0;
! 1516:
! 1517: while (hlen >= TCPOLEN_SACKLEN) {
! 1518: olen = opt[1];
! 1519: switch (*opt) {
! 1520: case TCPOPT_EOL: /* FALLTHROUGH */
! 1521: case TCPOPT_NOP:
! 1522: opt++;
! 1523: hlen--;
! 1524: break;
! 1525: case TCPOPT_SACK:
! 1526: if (olen > hlen)
! 1527: olen = hlen;
! 1528: if (olen >= TCPOLEN_SACKLEN) {
! 1529: for (i = 2; i + TCPOLEN_SACK <= olen;
! 1530: i += TCPOLEN_SACK) {
! 1531: memcpy(&sack, &opt[i], sizeof(sack));
! 1532: pf_change_a(&sack.start, &th->th_sum,
! 1533: htonl(ntohl(sack.start) -
! 1534: dst->seqdiff), 0);
! 1535: pf_change_a(&sack.end, &th->th_sum,
! 1536: htonl(ntohl(sack.end) -
! 1537: dst->seqdiff), 0);
! 1538: memcpy(&opt[i], &sack, sizeof(sack));
! 1539: }
! 1540: copyback = 1;
! 1541: }
! 1542: /* FALLTHROUGH */
! 1543: default:
! 1544: if (olen < 2)
! 1545: olen = 2;
! 1546: hlen -= olen;
! 1547: opt += olen;
! 1548: }
! 1549: }
! 1550:
! 1551: if (copyback)
! 1552: m_copyback(m, off + sizeof(*th), thoptlen, opts);
! 1553: return (copyback);
! 1554: }
! 1555:
! 1556: void
! 1557: pf_send_tcp(const struct pf_rule *r, sa_family_t af,
! 1558: const struct pf_addr *saddr, const struct pf_addr *daddr,
! 1559: u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
! 1560: u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
! 1561: u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp)
! 1562: {
! 1563: struct mbuf *m;
! 1564: int len, tlen;
! 1565: #ifdef INET
! 1566: struct ip *h;
! 1567: #endif /* INET */
! 1568: #ifdef INET6
! 1569: struct ip6_hdr *h6;
! 1570: #endif /* INET6 */
! 1571: struct tcphdr *th;
! 1572: char *opt;
! 1573:
! 1574: /* maximum segment size tcp option */
! 1575: tlen = sizeof(struct tcphdr);
! 1576: if (mss)
! 1577: tlen += 4;
! 1578:
! 1579: switch (af) {
! 1580: #ifdef INET
! 1581: case AF_INET:
! 1582: len = sizeof(struct ip) + tlen;
! 1583: break;
! 1584: #endif /* INET */
! 1585: #ifdef INET6
! 1586: case AF_INET6:
! 1587: len = sizeof(struct ip6_hdr) + tlen;
! 1588: break;
! 1589: #endif /* INET6 */
! 1590: }
! 1591:
! 1592: /* create outgoing mbuf */
! 1593: m = m_gethdr(M_DONTWAIT, MT_HEADER);
! 1594: if (m == NULL)
! 1595: return;
! 1596: if (tag)
! 1597: m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
! 1598: m->m_pkthdr.pf.tag = rtag;
! 1599:
! 1600: if (r != NULL && r->rtableid >= 0)
! 1601: m->m_pkthdr.pf.rtableid = m->m_pkthdr.pf.rtableid;
! 1602:
! 1603: #ifdef ALTQ
! 1604: if (r != NULL && r->qid) {
! 1605: m->m_pkthdr.pf.qid = r->qid;
! 1606: /* add hints for ecn */
! 1607: m->m_pkthdr.pf.hdr = mtod(m, struct ip *);
! 1608: }
! 1609: #endif /* ALTQ */
! 1610: m->m_data += max_linkhdr;
! 1611: m->m_pkthdr.len = m->m_len = len;
! 1612: m->m_pkthdr.rcvif = NULL;
! 1613: bzero(m->m_data, len);
! 1614: switch (af) {
! 1615: #ifdef INET
! 1616: case AF_INET:
! 1617: h = mtod(m, struct ip *);
! 1618:
! 1619: /* IP header fields included in the TCP checksum */
! 1620: h->ip_p = IPPROTO_TCP;
! 1621: h->ip_len = htons(tlen);
! 1622: h->ip_src.s_addr = saddr->v4.s_addr;
! 1623: h->ip_dst.s_addr = daddr->v4.s_addr;
! 1624:
! 1625: th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
! 1626: break;
! 1627: #endif /* INET */
! 1628: #ifdef INET6
! 1629: case AF_INET6:
! 1630: h6 = mtod(m, struct ip6_hdr *);
! 1631:
! 1632: /* IP header fields included in the TCP checksum */
! 1633: h6->ip6_nxt = IPPROTO_TCP;
! 1634: h6->ip6_plen = htons(tlen);
! 1635: memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
! 1636: memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
! 1637:
! 1638: th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
! 1639: break;
! 1640: #endif /* INET6 */
! 1641: }
! 1642:
! 1643: /* TCP header */
! 1644: th->th_sport = sport;
! 1645: th->th_dport = dport;
! 1646: th->th_seq = htonl(seq);
! 1647: th->th_ack = htonl(ack);
! 1648: th->th_off = tlen >> 2;
! 1649: th->th_flags = flags;
! 1650: th->th_win = htons(win);
! 1651:
! 1652: if (mss) {
! 1653: opt = (char *)(th + 1);
! 1654: opt[0] = TCPOPT_MAXSEG;
! 1655: opt[1] = 4;
! 1656: HTONS(mss);
! 1657: bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
! 1658: }
! 1659:
! 1660: switch (af) {
! 1661: #ifdef INET
! 1662: case AF_INET:
! 1663: /* TCP checksum */
! 1664: th->th_sum = in_cksum(m, len);
! 1665:
! 1666: /* Finish the IP header */
! 1667: h->ip_v = 4;
! 1668: h->ip_hl = sizeof(*h) >> 2;
! 1669: h->ip_tos = IPTOS_LOWDELAY;
! 1670: h->ip_len = htons(len);
! 1671: h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
! 1672: h->ip_ttl = ttl ? ttl : ip_defttl;
! 1673: h->ip_sum = 0;
! 1674: if (eh == NULL) {
! 1675: ip_output(m, (void *)NULL, (void *)NULL, 0,
! 1676: (void *)NULL, (void *)NULL);
! 1677: } else {
! 1678: struct route ro;
! 1679: struct rtentry rt;
! 1680: struct ether_header *e = (void *)ro.ro_dst.sa_data;
! 1681:
! 1682: if (ifp == NULL) {
! 1683: m_freem(m);
! 1684: return;
! 1685: }
! 1686: rt.rt_ifp = ifp;
! 1687: ro.ro_rt = &rt;
! 1688: ro.ro_dst.sa_len = sizeof(ro.ro_dst);
! 1689: ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
! 1690: bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
! 1691: bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
! 1692: e->ether_type = eh->ether_type;
! 1693: ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
! 1694: (void *)NULL, (void *)NULL);
! 1695: }
! 1696: break;
! 1697: #endif /* INET */
! 1698: #ifdef INET6
! 1699: case AF_INET6:
! 1700: /* TCP checksum */
! 1701: th->th_sum = in6_cksum(m, IPPROTO_TCP,
! 1702: sizeof(struct ip6_hdr), tlen);
! 1703:
! 1704: h6->ip6_vfc |= IPV6_VERSION;
! 1705: h6->ip6_hlim = IPV6_DEFHLIM;
! 1706:
! 1707: ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
! 1708: break;
! 1709: #endif /* INET6 */
! 1710: }
! 1711: }
! 1712:
! 1713: void
! 1714: pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
! 1715: struct pf_rule *r)
! 1716: {
! 1717: struct mbuf *m0;
! 1718:
! 1719: m0 = m_copy(m, 0, M_COPYALL);
! 1720: m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
! 1721:
! 1722: if (r->rtableid >= 0)
! 1723: m0->m_pkthdr.pf.rtableid = r->rtableid;
! 1724:
! 1725: #ifdef ALTQ
! 1726: if (r->qid) {
! 1727: m0->m_pkthdr.pf.qid = r->qid;
! 1728: /* add hints for ecn */
! 1729: m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *);
! 1730: }
! 1731: #endif /* ALTQ */
! 1732:
! 1733: switch (af) {
! 1734: #ifdef INET
! 1735: case AF_INET:
! 1736: icmp_error(m0, type, code, 0, 0);
! 1737: break;
! 1738: #endif /* INET */
! 1739: #ifdef INET6
! 1740: case AF_INET6:
! 1741: icmp6_error(m0, type, code, 0);
! 1742: break;
! 1743: #endif /* INET6 */
! 1744: }
! 1745: }
! 1746:
! 1747: /*
! 1748: * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
! 1749: * If n is 0, they match if they are equal. If n is != 0, they match if they
! 1750: * are different.
! 1751: */
! 1752: int
! 1753: pf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
! 1754: struct pf_addr *b, sa_family_t af)
! 1755: {
! 1756: int match = 0;
! 1757:
! 1758: switch (af) {
! 1759: #ifdef INET
! 1760: case AF_INET:
! 1761: if ((a->addr32[0] & m->addr32[0]) ==
! 1762: (b->addr32[0] & m->addr32[0]))
! 1763: match++;
! 1764: break;
! 1765: #endif /* INET */
! 1766: #ifdef INET6
! 1767: case AF_INET6:
! 1768: if (((a->addr32[0] & m->addr32[0]) ==
! 1769: (b->addr32[0] & m->addr32[0])) &&
! 1770: ((a->addr32[1] & m->addr32[1]) ==
! 1771: (b->addr32[1] & m->addr32[1])) &&
! 1772: ((a->addr32[2] & m->addr32[2]) ==
! 1773: (b->addr32[2] & m->addr32[2])) &&
! 1774: ((a->addr32[3] & m->addr32[3]) ==
! 1775: (b->addr32[3] & m->addr32[3])))
! 1776: match++;
! 1777: break;
! 1778: #endif /* INET6 */
! 1779: }
! 1780: if (match) {
! 1781: if (n)
! 1782: return (0);
! 1783: else
! 1784: return (1);
! 1785: } else {
! 1786: if (n)
! 1787: return (1);
! 1788: else
! 1789: return (0);
! 1790: }
! 1791: }
! 1792:
! 1793: int
! 1794: pf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
! 1795: {
! 1796: switch (op) {
! 1797: case PF_OP_IRG:
! 1798: return ((p > a1) && (p < a2));
! 1799: case PF_OP_XRG:
! 1800: return ((p < a1) || (p > a2));
! 1801: case PF_OP_RRG:
! 1802: return ((p >= a1) && (p <= a2));
! 1803: case PF_OP_EQ:
! 1804: return (p == a1);
! 1805: case PF_OP_NE:
! 1806: return (p != a1);
! 1807: case PF_OP_LT:
! 1808: return (p < a1);
! 1809: case PF_OP_LE:
! 1810: return (p <= a1);
! 1811: case PF_OP_GT:
! 1812: return (p > a1);
! 1813: case PF_OP_GE:
! 1814: return (p >= a1);
! 1815: }
! 1816: return (0); /* never reached */
! 1817: }
! 1818:
! 1819: int
! 1820: pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
! 1821: {
! 1822: NTOHS(a1);
! 1823: NTOHS(a2);
! 1824: NTOHS(p);
! 1825: return (pf_match(op, a1, a2, p));
! 1826: }
! 1827:
! 1828: int
! 1829: pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
! 1830: {
! 1831: if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
! 1832: return (0);
! 1833: return (pf_match(op, a1, a2, u));
! 1834: }
! 1835:
! 1836: int
! 1837: pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
! 1838: {
! 1839: if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
! 1840: return (0);
! 1841: return (pf_match(op, a1, a2, g));
! 1842: }
! 1843:
! 1844: int
! 1845: pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag)
! 1846: {
! 1847: if (*tag == -1)
! 1848: *tag = m->m_pkthdr.pf.tag;
! 1849:
! 1850: return ((!r->match_tag_not && r->match_tag == *tag) ||
! 1851: (r->match_tag_not && r->match_tag != *tag));
! 1852: }
! 1853:
! 1854: int
! 1855: pf_tag_packet(struct mbuf *m, int tag, int rtableid)
! 1856: {
! 1857: if (tag <= 0 && rtableid < 0)
! 1858: return (0);
! 1859:
! 1860: if (tag > 0)
! 1861: m->m_pkthdr.pf.tag = tag;
! 1862: if (rtableid >= 0)
! 1863: m->m_pkthdr.pf.rtableid = rtableid;
! 1864:
! 1865: return (0);
! 1866: }
! 1867:
! 1868: void
! 1869: pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
! 1870: struct pf_rule **r, struct pf_rule **a, int *match)
! 1871: {
! 1872: struct pf_anchor_stackframe *f;
! 1873:
! 1874: (*r)->anchor->match = 0;
! 1875: if (match)
! 1876: *match = 0;
! 1877: if (*depth >= sizeof(pf_anchor_stack) /
! 1878: sizeof(pf_anchor_stack[0])) {
! 1879: printf("pf_step_into_anchor: stack overflow\n");
! 1880: *r = TAILQ_NEXT(*r, entries);
! 1881: return;
! 1882: } else if (*depth == 0 && a != NULL)
! 1883: *a = *r;
! 1884: f = pf_anchor_stack + (*depth)++;
! 1885: f->rs = *rs;
! 1886: f->r = *r;
! 1887: if ((*r)->anchor_wildcard) {
! 1888: f->parent = &(*r)->anchor->children;
! 1889: if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
! 1890: NULL) {
! 1891: *r = NULL;
! 1892: return;
! 1893: }
! 1894: *rs = &f->child->ruleset;
! 1895: } else {
! 1896: f->parent = NULL;
! 1897: f->child = NULL;
! 1898: *rs = &(*r)->anchor->ruleset;
! 1899: }
! 1900: *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
! 1901: }
! 1902:
! 1903: int
! 1904: pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
! 1905: struct pf_rule **r, struct pf_rule **a, int *match)
! 1906: {
! 1907: struct pf_anchor_stackframe *f;
! 1908: int quick = 0;
! 1909:
! 1910: do {
! 1911: if (*depth <= 0)
! 1912: break;
! 1913: f = pf_anchor_stack + *depth - 1;
! 1914: if (f->parent != NULL && f->child != NULL) {
! 1915: if (f->child->match ||
! 1916: (match != NULL && *match)) {
! 1917: f->r->anchor->match = 1;
! 1918: *match = 0;
! 1919: }
! 1920: f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
! 1921: if (f->child != NULL) {
! 1922: *rs = &f->child->ruleset;
! 1923: *r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
! 1924: if (*r == NULL)
! 1925: continue;
! 1926: else
! 1927: break;
! 1928: }
! 1929: }
! 1930: (*depth)--;
! 1931: if (*depth == 0 && a != NULL)
! 1932: *a = NULL;
! 1933: *rs = f->rs;
! 1934: if (f->r->anchor->match || (match != NULL && *match))
! 1935: quick = f->r->quick;
! 1936: *r = TAILQ_NEXT(f->r, entries);
! 1937: } while (*r == NULL);
! 1938:
! 1939: return (quick);
! 1940: }
! 1941:
! 1942: #ifdef INET6
! 1943: void
! 1944: pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
! 1945: struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
! 1946: {
! 1947: switch (af) {
! 1948: #ifdef INET
! 1949: case AF_INET:
! 1950: naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
! 1951: ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
! 1952: break;
! 1953: #endif /* INET */
! 1954: case AF_INET6:
! 1955: naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
! 1956: ((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
! 1957: naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
! 1958: ((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
! 1959: naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
! 1960: ((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
! 1961: naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
! 1962: ((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
! 1963: break;
! 1964: }
! 1965: }
! 1966:
! 1967: void
! 1968: pf_addr_inc(struct pf_addr *addr, sa_family_t af)
! 1969: {
! 1970: switch (af) {
! 1971: #ifdef INET
! 1972: case AF_INET:
! 1973: addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
! 1974: break;
! 1975: #endif /* INET */
! 1976: case AF_INET6:
! 1977: if (addr->addr32[3] == 0xffffffff) {
! 1978: addr->addr32[3] = 0;
! 1979: if (addr->addr32[2] == 0xffffffff) {
! 1980: addr->addr32[2] = 0;
! 1981: if (addr->addr32[1] == 0xffffffff) {
! 1982: addr->addr32[1] = 0;
! 1983: addr->addr32[0] =
! 1984: htonl(ntohl(addr->addr32[0]) + 1);
! 1985: } else
! 1986: addr->addr32[1] =
! 1987: htonl(ntohl(addr->addr32[1]) + 1);
! 1988: } else
! 1989: addr->addr32[2] =
! 1990: htonl(ntohl(addr->addr32[2]) + 1);
! 1991: } else
! 1992: addr->addr32[3] =
! 1993: htonl(ntohl(addr->addr32[3]) + 1);
! 1994: break;
! 1995: }
! 1996: }
! 1997: #endif /* INET6 */
! 1998:
! 1999: #define mix(a,b,c) \
! 2000: do { \
! 2001: a -= b; a -= c; a ^= (c >> 13); \
! 2002: b -= c; b -= a; b ^= (a << 8); \
! 2003: c -= a; c -= b; c ^= (b >> 13); \
! 2004: a -= b; a -= c; a ^= (c >> 12); \
! 2005: b -= c; b -= a; b ^= (a << 16); \
! 2006: c -= a; c -= b; c ^= (b >> 5); \
! 2007: a -= b; a -= c; a ^= (c >> 3); \
! 2008: b -= c; b -= a; b ^= (a << 10); \
! 2009: c -= a; c -= b; c ^= (b >> 15); \
! 2010: } while (0)
! 2011:
! 2012: /*
! 2013: * hash function based on bridge_hash in if_bridge.c
! 2014: */
! 2015: void
! 2016: pf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
! 2017: struct pf_poolhashkey *key, sa_family_t af)
! 2018: {
! 2019: u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
! 2020:
! 2021: switch (af) {
! 2022: #ifdef INET
! 2023: case AF_INET:
! 2024: a += inaddr->addr32[0];
! 2025: b += key->key32[1];
! 2026: mix(a, b, c);
! 2027: hash->addr32[0] = c + key->key32[2];
! 2028: break;
! 2029: #endif /* INET */
! 2030: #ifdef INET6
! 2031: case AF_INET6:
! 2032: a += inaddr->addr32[0];
! 2033: b += inaddr->addr32[2];
! 2034: mix(a, b, c);
! 2035: hash->addr32[0] = c;
! 2036: a += inaddr->addr32[1];
! 2037: b += inaddr->addr32[3];
! 2038: c += key->key32[1];
! 2039: mix(a, b, c);
! 2040: hash->addr32[1] = c;
! 2041: a += inaddr->addr32[2];
! 2042: b += inaddr->addr32[1];
! 2043: c += key->key32[2];
! 2044: mix(a, b, c);
! 2045: hash->addr32[2] = c;
! 2046: a += inaddr->addr32[3];
! 2047: b += inaddr->addr32[0];
! 2048: c += key->key32[3];
! 2049: mix(a, b, c);
! 2050: hash->addr32[3] = c;
! 2051: break;
! 2052: #endif /* INET6 */
! 2053: }
! 2054: }
! 2055:
! 2056: int
! 2057: pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
! 2058: struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
! 2059: {
! 2060: unsigned char hash[16];
! 2061: struct pf_pool *rpool = &r->rpool;
! 2062: struct pf_addr *raddr = &rpool->cur->addr.v.a.addr;
! 2063: struct pf_addr *rmask = &rpool->cur->addr.v.a.mask;
! 2064: struct pf_pooladdr *acur = rpool->cur;
! 2065: struct pf_src_node k;
! 2066:
! 2067: if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
! 2068: (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
! 2069: k.af = af;
! 2070: PF_ACPY(&k.addr, saddr, af);
! 2071: if (r->rule_flag & PFRULE_RULESRCTRACK ||
! 2072: r->rpool.opts & PF_POOL_STICKYADDR)
! 2073: k.rule.ptr = r;
! 2074: else
! 2075: k.rule.ptr = NULL;
! 2076: pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
! 2077: *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
! 2078: if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
! 2079: PF_ACPY(naddr, &(*sn)->raddr, af);
! 2080: if (pf_status.debug >= PF_DEBUG_MISC) {
! 2081: printf("pf_map_addr: src tracking maps ");
! 2082: pf_print_host(&k.addr, 0, af);
! 2083: printf(" to ");
! 2084: pf_print_host(naddr, 0, af);
! 2085: printf("\n");
! 2086: }
! 2087: return (0);
! 2088: }
! 2089: }
! 2090:
! 2091: if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
! 2092: return (1);
! 2093: if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
! 2094: switch (af) {
! 2095: #ifdef INET
! 2096: case AF_INET:
! 2097: if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
! 2098: (rpool->opts & PF_POOL_TYPEMASK) !=
! 2099: PF_POOL_ROUNDROBIN)
! 2100: return (1);
! 2101: raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
! 2102: rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
! 2103: break;
! 2104: #endif /* INET */
! 2105: #ifdef INET6
! 2106: case AF_INET6:
! 2107: if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
! 2108: (rpool->opts & PF_POOL_TYPEMASK) !=
! 2109: PF_POOL_ROUNDROBIN)
! 2110: return (1);
! 2111: raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
! 2112: rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
! 2113: break;
! 2114: #endif /* INET6 */
! 2115: }
! 2116: } else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
! 2117: if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
! 2118: return (1); /* unsupported */
! 2119: } else {
! 2120: raddr = &rpool->cur->addr.v.a.addr;
! 2121: rmask = &rpool->cur->addr.v.a.mask;
! 2122: }
! 2123:
! 2124: switch (rpool->opts & PF_POOL_TYPEMASK) {
! 2125: case PF_POOL_NONE:
! 2126: PF_ACPY(naddr, raddr, af);
! 2127: break;
! 2128: case PF_POOL_BITMASK:
! 2129: PF_POOLMASK(naddr, raddr, rmask, saddr, af);
! 2130: break;
! 2131: case PF_POOL_RANDOM:
! 2132: if (init_addr != NULL && PF_AZERO(init_addr, af)) {
! 2133: switch (af) {
! 2134: #ifdef INET
! 2135: case AF_INET:
! 2136: rpool->counter.addr32[0] = htonl(arc4random());
! 2137: break;
! 2138: #endif /* INET */
! 2139: #ifdef INET6
! 2140: case AF_INET6:
! 2141: if (rmask->addr32[3] != 0xffffffff)
! 2142: rpool->counter.addr32[3] =
! 2143: htonl(arc4random());
! 2144: else
! 2145: break;
! 2146: if (rmask->addr32[2] != 0xffffffff)
! 2147: rpool->counter.addr32[2] =
! 2148: htonl(arc4random());
! 2149: else
! 2150: break;
! 2151: if (rmask->addr32[1] != 0xffffffff)
! 2152: rpool->counter.addr32[1] =
! 2153: htonl(arc4random());
! 2154: else
! 2155: break;
! 2156: if (rmask->addr32[0] != 0xffffffff)
! 2157: rpool->counter.addr32[0] =
! 2158: htonl(arc4random());
! 2159: break;
! 2160: #endif /* INET6 */
! 2161: }
! 2162: PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
! 2163: PF_ACPY(init_addr, naddr, af);
! 2164:
! 2165: } else {
! 2166: PF_AINC(&rpool->counter, af);
! 2167: PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
! 2168: }
! 2169: break;
! 2170: case PF_POOL_SRCHASH:
! 2171: pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
! 2172: PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
! 2173: break;
! 2174: case PF_POOL_ROUNDROBIN:
! 2175: if (rpool->cur->addr.type == PF_ADDR_TABLE) {
! 2176: if (!pfr_pool_get(rpool->cur->addr.p.tbl,
! 2177: &rpool->tblidx, &rpool->counter,
! 2178: &raddr, &rmask, af))
! 2179: goto get_addr;
! 2180: } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
! 2181: if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
! 2182: &rpool->tblidx, &rpool->counter,
! 2183: &raddr, &rmask, af))
! 2184: goto get_addr;
! 2185: } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
! 2186: goto get_addr;
! 2187:
! 2188: try_next:
! 2189: if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
! 2190: rpool->cur = TAILQ_FIRST(&rpool->list);
! 2191: if (rpool->cur->addr.type == PF_ADDR_TABLE) {
! 2192: rpool->tblidx = -1;
! 2193: if (pfr_pool_get(rpool->cur->addr.p.tbl,
! 2194: &rpool->tblidx, &rpool->counter,
! 2195: &raddr, &rmask, af)) {
! 2196: /* table contains no address of type 'af' */
! 2197: if (rpool->cur != acur)
! 2198: goto try_next;
! 2199: return (1);
! 2200: }
! 2201: } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
! 2202: rpool->tblidx = -1;
! 2203: if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
! 2204: &rpool->tblidx, &rpool->counter,
! 2205: &raddr, &rmask, af)) {
! 2206: /* table contains no address of type 'af' */
! 2207: if (rpool->cur != acur)
! 2208: goto try_next;
! 2209: return (1);
! 2210: }
! 2211: } else {
! 2212: raddr = &rpool->cur->addr.v.a.addr;
! 2213: rmask = &rpool->cur->addr.v.a.mask;
! 2214: PF_ACPY(&rpool->counter, raddr, af);
! 2215: }
! 2216:
! 2217: get_addr:
! 2218: PF_ACPY(naddr, &rpool->counter, af);
! 2219: if (init_addr != NULL && PF_AZERO(init_addr, af))
! 2220: PF_ACPY(init_addr, naddr, af);
! 2221: PF_AINC(&rpool->counter, af);
! 2222: break;
! 2223: }
! 2224: if (*sn != NULL)
! 2225: PF_ACPY(&(*sn)->raddr, naddr, af);
! 2226:
! 2227: if (pf_status.debug >= PF_DEBUG_MISC &&
! 2228: (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
! 2229: printf("pf_map_addr: selected address ");
! 2230: pf_print_host(naddr, 0, af);
! 2231: printf("\n");
! 2232: }
! 2233:
! 2234: return (0);
! 2235: }
! 2236:
! 2237: int
! 2238: pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
! 2239: struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
! 2240: struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
! 2241: struct pf_src_node **sn)
! 2242: {
! 2243: struct pf_state_key_cmp key;
! 2244: struct pf_addr init_addr;
! 2245: u_int16_t cut;
! 2246:
! 2247: bzero(&init_addr, sizeof(init_addr));
! 2248: if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
! 2249: return (1);
! 2250:
! 2251: if (proto == IPPROTO_ICMP) {
! 2252: low = 1;
! 2253: high = 65535;
! 2254: }
! 2255:
! 2256: do {
! 2257: key.af = af;
! 2258: key.proto = proto;
! 2259: PF_ACPY(&key.ext.addr, daddr, key.af);
! 2260: PF_ACPY(&key.gwy.addr, naddr, key.af);
! 2261: key.ext.port = dport;
! 2262:
! 2263: /*
! 2264: * port search; start random, step;
! 2265: * similar 2 portloop in in_pcbbind
! 2266: */
! 2267: if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
! 2268: proto == IPPROTO_ICMP)) {
! 2269: key.gwy.port = dport;
! 2270: if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
! 2271: return (0);
! 2272: } else if (low == 0 && high == 0) {
! 2273: key.gwy.port = *nport;
! 2274: if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
! 2275: return (0);
! 2276: } else if (low == high) {
! 2277: key.gwy.port = htons(low);
! 2278: if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
! 2279: *nport = htons(low);
! 2280: return (0);
! 2281: }
! 2282: } else {
! 2283: u_int16_t tmp;
! 2284:
! 2285: if (low > high) {
! 2286: tmp = low;
! 2287: low = high;
! 2288: high = tmp;
! 2289: }
! 2290: /* low < high */
! 2291: cut = htonl(arc4random()) % (1 + high - low) + low;
! 2292: /* low <= cut <= high */
! 2293: for (tmp = cut; tmp <= high; ++(tmp)) {
! 2294: key.gwy.port = htons(tmp);
! 2295: if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
! 2296: NULL) {
! 2297: *nport = htons(tmp);
! 2298: return (0);
! 2299: }
! 2300: }
! 2301: for (tmp = cut - 1; tmp >= low; --(tmp)) {
! 2302: key.gwy.port = htons(tmp);
! 2303: if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
! 2304: NULL) {
! 2305: *nport = htons(tmp);
! 2306: return (0);
! 2307: }
! 2308: }
! 2309: }
! 2310:
! 2311: switch (r->rpool.opts & PF_POOL_TYPEMASK) {
! 2312: case PF_POOL_RANDOM:
! 2313: case PF_POOL_ROUNDROBIN:
! 2314: if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
! 2315: return (1);
! 2316: break;
! 2317: case PF_POOL_NONE:
! 2318: case PF_POOL_SRCHASH:
! 2319: case PF_POOL_BITMASK:
! 2320: default:
! 2321: return (1);
! 2322: }
! 2323: } while (! PF_AEQ(&init_addr, naddr, af) );
! 2324:
! 2325: return (1); /* none available */
! 2326: }
! 2327:
! 2328: struct pf_rule *
! 2329: pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
! 2330: int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
! 2331: struct pf_addr *daddr, u_int16_t dport, int rs_num)
! 2332: {
! 2333: struct pf_rule *r, *rm = NULL;
! 2334: struct pf_ruleset *ruleset = NULL;
! 2335: int tag = -1;
! 2336: int rtableid = -1;
! 2337: int asd = 0;
! 2338:
! 2339: r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
! 2340: while (r && rm == NULL) {
! 2341: struct pf_rule_addr *src = NULL, *dst = NULL;
! 2342: struct pf_addr_wrap *xdst = NULL;
! 2343:
! 2344: if (r->action == PF_BINAT && direction == PF_IN) {
! 2345: src = &r->dst;
! 2346: if (r->rpool.cur != NULL)
! 2347: xdst = &r->rpool.cur->addr;
! 2348: } else {
! 2349: src = &r->src;
! 2350: dst = &r->dst;
! 2351: }
! 2352:
! 2353: r->evaluations++;
! 2354: if (pfi_kif_match(r->kif, kif) == r->ifnot)
! 2355: r = r->skip[PF_SKIP_IFP].ptr;
! 2356: else if (r->direction && r->direction != direction)
! 2357: r = r->skip[PF_SKIP_DIR].ptr;
! 2358: else if (r->af && r->af != pd->af)
! 2359: r = r->skip[PF_SKIP_AF].ptr;
! 2360: else if (r->proto && r->proto != pd->proto)
! 2361: r = r->skip[PF_SKIP_PROTO].ptr;
! 2362: else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
! 2363: src->neg, kif))
! 2364: r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
! 2365: PF_SKIP_DST_ADDR].ptr;
! 2366: else if (src->port_op && !pf_match_port(src->port_op,
! 2367: src->port[0], src->port[1], sport))
! 2368: r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
! 2369: PF_SKIP_DST_PORT].ptr;
! 2370: else if (dst != NULL &&
! 2371: PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
! 2372: r = r->skip[PF_SKIP_DST_ADDR].ptr;
! 2373: else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
! 2374: 0, NULL))
! 2375: r = TAILQ_NEXT(r, entries);
! 2376: else if (dst != NULL && dst->port_op &&
! 2377: !pf_match_port(dst->port_op, dst->port[0],
! 2378: dst->port[1], dport))
! 2379: r = r->skip[PF_SKIP_DST_PORT].ptr;
! 2380: else if (r->match_tag && !pf_match_tag(m, r, &tag))
! 2381: r = TAILQ_NEXT(r, entries);
! 2382: else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
! 2383: IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
! 2384: off, pd->hdr.tcp), r->os_fingerprint)))
! 2385: r = TAILQ_NEXT(r, entries);
! 2386: else {
! 2387: if (r->tag)
! 2388: tag = r->tag;
! 2389: if (r->rtableid >= 0)
! 2390: rtableid = r->rtableid;
! 2391: if (r->anchor == NULL) {
! 2392: rm = r;
! 2393: } else
! 2394: pf_step_into_anchor(&asd, &ruleset, rs_num,
! 2395: &r, NULL, NULL);
! 2396: }
! 2397: if (r == NULL)
! 2398: pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
! 2399: NULL, NULL);
! 2400: }
! 2401: if (pf_tag_packet(m, tag, rtableid))
! 2402: return (NULL);
! 2403: if (rm != NULL && (rm->action == PF_NONAT ||
! 2404: rm->action == PF_NORDR || rm->action == PF_NOBINAT))
! 2405: return (NULL);
! 2406: return (rm);
! 2407: }
! 2408:
! 2409: struct pf_rule *
! 2410: pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
! 2411: struct pfi_kif *kif, struct pf_src_node **sn,
! 2412: struct pf_addr *saddr, u_int16_t sport,
! 2413: struct pf_addr *daddr, u_int16_t dport,
! 2414: struct pf_addr *naddr, u_int16_t *nport)
! 2415: {
! 2416: struct pf_rule *r = NULL;
! 2417:
! 2418: if (direction == PF_OUT) {
! 2419: r = pf_match_translation(pd, m, off, direction, kif, saddr,
! 2420: sport, daddr, dport, PF_RULESET_BINAT);
! 2421: if (r == NULL)
! 2422: r = pf_match_translation(pd, m, off, direction, kif,
! 2423: saddr, sport, daddr, dport, PF_RULESET_NAT);
! 2424: } else {
! 2425: r = pf_match_translation(pd, m, off, direction, kif, saddr,
! 2426: sport, daddr, dport, PF_RULESET_RDR);
! 2427: if (r == NULL)
! 2428: r = pf_match_translation(pd, m, off, direction, kif,
! 2429: saddr, sport, daddr, dport, PF_RULESET_BINAT);
! 2430: }
! 2431:
! 2432: if (r != NULL) {
! 2433: switch (r->action) {
! 2434: case PF_NONAT:
! 2435: case PF_NOBINAT:
! 2436: case PF_NORDR:
! 2437: return (NULL);
! 2438: case PF_NAT:
! 2439: if (pf_get_sport(pd->af, pd->proto, r, saddr,
! 2440: daddr, dport, naddr, nport, r->rpool.proxy_port[0],
! 2441: r->rpool.proxy_port[1], sn)) {
! 2442: DPFPRINTF(PF_DEBUG_MISC,
! 2443: ("pf: NAT proxy port allocation "
! 2444: "(%u-%u) failed\n",
! 2445: r->rpool.proxy_port[0],
! 2446: r->rpool.proxy_port[1]));
! 2447: return (NULL);
! 2448: }
! 2449: break;
! 2450: case PF_BINAT:
! 2451: switch (direction) {
! 2452: case PF_OUT:
! 2453: if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
! 2454: switch (pd->af) {
! 2455: #ifdef INET
! 2456: case AF_INET:
! 2457: if (r->rpool.cur->addr.p.dyn->
! 2458: pfid_acnt4 < 1)
! 2459: return (NULL);
! 2460: PF_POOLMASK(naddr,
! 2461: &r->rpool.cur->addr.p.dyn->
! 2462: pfid_addr4,
! 2463: &r->rpool.cur->addr.p.dyn->
! 2464: pfid_mask4,
! 2465: saddr, AF_INET);
! 2466: break;
! 2467: #endif /* INET */
! 2468: #ifdef INET6
! 2469: case AF_INET6:
! 2470: if (r->rpool.cur->addr.p.dyn->
! 2471: pfid_acnt6 < 1)
! 2472: return (NULL);
! 2473: PF_POOLMASK(naddr,
! 2474: &r->rpool.cur->addr.p.dyn->
! 2475: pfid_addr6,
! 2476: &r->rpool.cur->addr.p.dyn->
! 2477: pfid_mask6,
! 2478: saddr, AF_INET6);
! 2479: break;
! 2480: #endif /* INET6 */
! 2481: }
! 2482: } else
! 2483: PF_POOLMASK(naddr,
! 2484: &r->rpool.cur->addr.v.a.addr,
! 2485: &r->rpool.cur->addr.v.a.mask,
! 2486: saddr, pd->af);
! 2487: break;
! 2488: case PF_IN:
! 2489: if (r->src.addr.type == PF_ADDR_DYNIFTL) {
! 2490: switch (pd->af) {
! 2491: #ifdef INET
! 2492: case AF_INET:
! 2493: if (r->src.addr.p.dyn->
! 2494: pfid_acnt4 < 1)
! 2495: return (NULL);
! 2496: PF_POOLMASK(naddr,
! 2497: &r->src.addr.p.dyn->
! 2498: pfid_addr4,
! 2499: &r->src.addr.p.dyn->
! 2500: pfid_mask4,
! 2501: daddr, AF_INET);
! 2502: break;
! 2503: #endif /* INET */
! 2504: #ifdef INET6
! 2505: case AF_INET6:
! 2506: if (r->src.addr.p.dyn->
! 2507: pfid_acnt6 < 1)
! 2508: return (NULL);
! 2509: PF_POOLMASK(naddr,
! 2510: &r->src.addr.p.dyn->
! 2511: pfid_addr6,
! 2512: &r->src.addr.p.dyn->
! 2513: pfid_mask6,
! 2514: daddr, AF_INET6);
! 2515: break;
! 2516: #endif /* INET6 */
! 2517: }
! 2518: } else
! 2519: PF_POOLMASK(naddr,
! 2520: &r->src.addr.v.a.addr,
! 2521: &r->src.addr.v.a.mask, daddr,
! 2522: pd->af);
! 2523: break;
! 2524: }
! 2525: break;
! 2526: case PF_RDR: {
! 2527: if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
! 2528: return (NULL);
! 2529: if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
! 2530: PF_POOL_BITMASK)
! 2531: PF_POOLMASK(naddr, naddr,
! 2532: &r->rpool.cur->addr.v.a.mask, daddr,
! 2533: pd->af);
! 2534:
! 2535: if (r->rpool.proxy_port[1]) {
! 2536: u_int32_t tmp_nport;
! 2537:
! 2538: tmp_nport = ((ntohs(dport) -
! 2539: ntohs(r->dst.port[0])) %
! 2540: (r->rpool.proxy_port[1] -
! 2541: r->rpool.proxy_port[0] + 1)) +
! 2542: r->rpool.proxy_port[0];
! 2543:
! 2544: /* wrap around if necessary */
! 2545: if (tmp_nport > 65535)
! 2546: tmp_nport -= 65535;
! 2547: *nport = htons((u_int16_t)tmp_nport);
! 2548: } else if (r->rpool.proxy_port[0])
! 2549: *nport = htons(r->rpool.proxy_port[0]);
! 2550: break;
! 2551: }
! 2552: default:
! 2553: return (NULL);
! 2554: }
! 2555: }
! 2556:
! 2557: return (r);
! 2558: }
! 2559:
! 2560: int
! 2561: pf_socket_lookup(int direction, struct pf_pdesc *pd)
! 2562: {
! 2563: struct pf_addr *saddr, *daddr;
! 2564: u_int16_t sport, dport;
! 2565: struct inpcbtable *tb;
! 2566: struct inpcb *inp;
! 2567:
! 2568: if (pd == NULL)
! 2569: return (-1);
! 2570: pd->lookup.uid = UID_MAX;
! 2571: pd->lookup.gid = GID_MAX;
! 2572: pd->lookup.pid = NO_PID;
! 2573: switch (pd->proto) {
! 2574: case IPPROTO_TCP:
! 2575: if (pd->hdr.tcp == NULL)
! 2576: return (-1);
! 2577: sport = pd->hdr.tcp->th_sport;
! 2578: dport = pd->hdr.tcp->th_dport;
! 2579: tb = &tcbtable;
! 2580: break;
! 2581: case IPPROTO_UDP:
! 2582: if (pd->hdr.udp == NULL)
! 2583: return (-1);
! 2584: sport = pd->hdr.udp->uh_sport;
! 2585: dport = pd->hdr.udp->uh_dport;
! 2586: tb = &udbtable;
! 2587: break;
! 2588: default:
! 2589: return (-1);
! 2590: }
! 2591: if (direction == PF_IN) {
! 2592: saddr = pd->src;
! 2593: daddr = pd->dst;
! 2594: } else {
! 2595: u_int16_t p;
! 2596:
! 2597: p = sport;
! 2598: sport = dport;
! 2599: dport = p;
! 2600: saddr = pd->dst;
! 2601: daddr = pd->src;
! 2602: }
! 2603: switch (pd->af) {
! 2604: #ifdef INET
! 2605: case AF_INET:
! 2606: inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
! 2607: if (inp == NULL) {
! 2608: inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
! 2609: if (inp == NULL)
! 2610: return (-1);
! 2611: }
! 2612: break;
! 2613: #endif /* INET */
! 2614: #ifdef INET6
! 2615: case AF_INET6:
! 2616: inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
! 2617: dport);
! 2618: if (inp == NULL) {
! 2619: inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
! 2620: if (inp == NULL)
! 2621: return (-1);
! 2622: }
! 2623: break;
! 2624: #endif /* INET6 */
! 2625:
! 2626: default:
! 2627: return (-1);
! 2628: }
! 2629: pd->lookup.uid = inp->inp_socket->so_euid;
! 2630: pd->lookup.gid = inp->inp_socket->so_egid;
! 2631: pd->lookup.pid = inp->inp_socket->so_cpid;
! 2632: return (1);
! 2633: }
! 2634:
! 2635: u_int8_t
! 2636: pf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
! 2637: {
! 2638: int hlen;
! 2639: u_int8_t hdr[60];
! 2640: u_int8_t *opt, optlen;
! 2641: u_int8_t wscale = 0;
! 2642:
! 2643: hlen = th_off << 2; /* hlen <= sizeof(hdr) */
! 2644: if (hlen <= sizeof(struct tcphdr))
! 2645: return (0);
! 2646: if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
! 2647: return (0);
! 2648: opt = hdr + sizeof(struct tcphdr);
! 2649: hlen -= sizeof(struct tcphdr);
! 2650: while (hlen >= 3) {
! 2651: switch (*opt) {
! 2652: case TCPOPT_EOL:
! 2653: case TCPOPT_NOP:
! 2654: ++opt;
! 2655: --hlen;
! 2656: break;
! 2657: case TCPOPT_WINDOW:
! 2658: wscale = opt[2];
! 2659: if (wscale > TCP_MAX_WINSHIFT)
! 2660: wscale = TCP_MAX_WINSHIFT;
! 2661: wscale |= PF_WSCALE_FLAG;
! 2662: /* FALLTHROUGH */
! 2663: default:
! 2664: optlen = opt[1];
! 2665: if (optlen < 2)
! 2666: optlen = 2;
! 2667: hlen -= optlen;
! 2668: opt += optlen;
! 2669: break;
! 2670: }
! 2671: }
! 2672: return (wscale);
! 2673: }
! 2674:
! 2675: u_int16_t
! 2676: pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
! 2677: {
! 2678: int hlen;
! 2679: u_int8_t hdr[60];
! 2680: u_int8_t *opt, optlen;
! 2681: u_int16_t mss = tcp_mssdflt;
! 2682:
! 2683: hlen = th_off << 2; /* hlen <= sizeof(hdr) */
! 2684: if (hlen <= sizeof(struct tcphdr))
! 2685: return (0);
! 2686: if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
! 2687: return (0);
! 2688: opt = hdr + sizeof(struct tcphdr);
! 2689: hlen -= sizeof(struct tcphdr);
! 2690: while (hlen >= TCPOLEN_MAXSEG) {
! 2691: switch (*opt) {
! 2692: case TCPOPT_EOL:
! 2693: case TCPOPT_NOP:
! 2694: ++opt;
! 2695: --hlen;
! 2696: break;
! 2697: case TCPOPT_MAXSEG:
! 2698: bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
! 2699: NTOHS(mss);
! 2700: /* FALLTHROUGH */
! 2701: default:
! 2702: optlen = opt[1];
! 2703: if (optlen < 2)
! 2704: optlen = 2;
! 2705: hlen -= optlen;
! 2706: opt += optlen;
! 2707: break;
! 2708: }
! 2709: }
! 2710: return (mss);
! 2711: }
! 2712:
! 2713: u_int16_t
! 2714: pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
! 2715: {
! 2716: #ifdef INET
! 2717: struct sockaddr_in *dst;
! 2718: struct route ro;
! 2719: #endif /* INET */
! 2720: #ifdef INET6
! 2721: struct sockaddr_in6 *dst6;
! 2722: struct route_in6 ro6;
! 2723: #endif /* INET6 */
! 2724: struct rtentry *rt = NULL;
! 2725: int hlen;
! 2726: u_int16_t mss = tcp_mssdflt;
! 2727:
! 2728: switch (af) {
! 2729: #ifdef INET
! 2730: case AF_INET:
! 2731: hlen = sizeof(struct ip);
! 2732: bzero(&ro, sizeof(ro));
! 2733: dst = (struct sockaddr_in *)&ro.ro_dst;
! 2734: dst->sin_family = AF_INET;
! 2735: dst->sin_len = sizeof(*dst);
! 2736: dst->sin_addr = addr->v4;
! 2737: rtalloc_noclone(&ro, NO_CLONING);
! 2738: rt = ro.ro_rt;
! 2739: break;
! 2740: #endif /* INET */
! 2741: #ifdef INET6
! 2742: case AF_INET6:
! 2743: hlen = sizeof(struct ip6_hdr);
! 2744: bzero(&ro6, sizeof(ro6));
! 2745: dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
! 2746: dst6->sin6_family = AF_INET6;
! 2747: dst6->sin6_len = sizeof(*dst6);
! 2748: dst6->sin6_addr = addr->v6;
! 2749: rtalloc_noclone((struct route *)&ro6, NO_CLONING);
! 2750: rt = ro6.ro_rt;
! 2751: break;
! 2752: #endif /* INET6 */
! 2753: }
! 2754:
! 2755: if (rt && rt->rt_ifp) {
! 2756: mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
! 2757: mss = max(tcp_mssdflt, mss);
! 2758: RTFREE(rt);
! 2759: }
! 2760: mss = min(mss, offer);
! 2761: mss = max(mss, 64); /* sanity - at least max opt space */
! 2762: return (mss);
! 2763: }
! 2764:
! 2765: void
! 2766: pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
! 2767: {
! 2768: struct pf_rule *r = s->rule.ptr;
! 2769:
! 2770: s->rt_kif = NULL;
! 2771: if (!r->rt || r->rt == PF_FASTROUTE)
! 2772: return;
! 2773: switch (s->state_key->af) {
! 2774: #ifdef INET
! 2775: case AF_INET:
! 2776: pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
! 2777: &s->nat_src_node);
! 2778: s->rt_kif = r->rpool.cur->kif;
! 2779: break;
! 2780: #endif /* INET */
! 2781: #ifdef INET6
! 2782: case AF_INET6:
! 2783: pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
! 2784: &s->nat_src_node);
! 2785: s->rt_kif = r->rpool.cur->kif;
! 2786: break;
! 2787: #endif /* INET6 */
! 2788: }
! 2789: }
! 2790:
! 2791: void
! 2792: pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail)
! 2793: {
! 2794: s->state_key = sk;
! 2795: sk->refcnt++;
! 2796:
! 2797: /* list is sorted, if-bound states before floating */
! 2798: if (tail)
! 2799: TAILQ_INSERT_TAIL(&sk->states, s, next);
! 2800: else
! 2801: TAILQ_INSERT_HEAD(&sk->states, s, next);
! 2802: }
! 2803:
! 2804: void
! 2805: pf_detach_state(struct pf_state *s, int flags)
! 2806: {
! 2807: struct pf_state_key *sk = s->state_key;
! 2808:
! 2809: if (sk == NULL)
! 2810: return;
! 2811:
! 2812: s->state_key = NULL;
! 2813: TAILQ_REMOVE(&sk->states, s, next);
! 2814: if (--sk->refcnt == 0) {
! 2815: if (!(flags & PF_DT_SKIP_EXTGWY))
! 2816: RB_REMOVE(pf_state_tree_ext_gwy,
! 2817: &pf_statetbl_ext_gwy, sk);
! 2818: if (!(flags & PF_DT_SKIP_LANEXT))
! 2819: RB_REMOVE(pf_state_tree_lan_ext,
! 2820: &pf_statetbl_lan_ext, sk);
! 2821: pool_put(&pf_state_key_pl, sk);
! 2822: }
! 2823: }
! 2824:
! 2825: struct pf_state_key *
! 2826: pf_alloc_state_key(struct pf_state *s)
! 2827: {
! 2828: struct pf_state_key *sk;
! 2829:
! 2830: if ((sk = pool_get(&pf_state_key_pl, PR_NOWAIT)) == NULL)
! 2831: return (NULL);
! 2832: bzero(sk, sizeof(*sk));
! 2833: TAILQ_INIT(&sk->states);
! 2834: pf_attach_state(sk, s, 0);
! 2835:
! 2836: return (sk);
! 2837: }
! 2838:
! 2839: int
! 2840: pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
! 2841: struct pfi_kif *kif, struct mbuf *m, int off, void *h,
! 2842: struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
! 2843: struct ifqueue *ifq)
! 2844: {
! 2845: struct pf_rule *nr = NULL;
! 2846: struct pf_addr *saddr = pd->src, *daddr = pd->dst;
! 2847: u_int16_t bport, nport = 0;
! 2848: sa_family_t af = pd->af;
! 2849: struct pf_rule *r, *a = NULL;
! 2850: struct pf_ruleset *ruleset = NULL;
! 2851: struct pf_src_node *nsn = NULL;
! 2852: struct tcphdr *th = pd->hdr.tcp;
! 2853: u_short reason;
! 2854: int rewrite = 0, hdrlen = 0;
! 2855: int tag = -1, rtableid = -1;
! 2856: int asd = 0;
! 2857: int match = 0;
! 2858: int state_icmp = 0;
! 2859: u_int16_t mss = tcp_mssdflt;
! 2860: u_int16_t sport, dport;
! 2861: u_int8_t icmptype = 0, icmpcode = 0;
! 2862:
! 2863: if (direction == PF_IN && pf_check_congestion(ifq)) {
! 2864: REASON_SET(&reason, PFRES_CONGEST);
! 2865: return (PF_DROP);
! 2866: }
! 2867:
! 2868: sport = dport = hdrlen = 0;
! 2869:
! 2870: switch (pd->proto) {
! 2871: case IPPROTO_TCP:
! 2872: sport = th->th_sport;
! 2873: dport = th->th_dport;
! 2874: hdrlen = sizeof(*th);
! 2875: break;
! 2876: case IPPROTO_UDP:
! 2877: sport = pd->hdr.udp->uh_sport;
! 2878: dport = pd->hdr.udp->uh_dport;
! 2879: hdrlen = sizeof(*pd->hdr.udp);
! 2880: break;
! 2881: #ifdef INET
! 2882: case IPPROTO_ICMP:
! 2883: if (pd->af != AF_INET)
! 2884: break;
! 2885: sport = dport = pd->hdr.icmp->icmp_id;
! 2886: icmptype = pd->hdr.icmp->icmp_type;
! 2887: icmpcode = pd->hdr.icmp->icmp_code;
! 2888:
! 2889: if (icmptype == ICMP_UNREACH ||
! 2890: icmptype == ICMP_SOURCEQUENCH ||
! 2891: icmptype == ICMP_REDIRECT ||
! 2892: icmptype == ICMP_TIMXCEED ||
! 2893: icmptype == ICMP_PARAMPROB)
! 2894: state_icmp++;
! 2895: break;
! 2896: #endif /* INET */
! 2897: #ifdef INET6
! 2898: case IPPROTO_ICMPV6:
! 2899: if (pd->af != AF_INET6)
! 2900: break;
! 2901: sport = dport = pd->hdr.icmp6->icmp6_id;
! 2902: hdrlen = sizeof(*pd->hdr.icmp6);
! 2903: icmptype = pd->hdr.icmp6->icmp6_type;
! 2904: icmpcode = pd->hdr.icmp6->icmp6_code;
! 2905:
! 2906: if (icmptype == ICMP6_DST_UNREACH ||
! 2907: icmptype == ICMP6_PACKET_TOO_BIG ||
! 2908: icmptype == ICMP6_TIME_EXCEEDED ||
! 2909: icmptype == ICMP6_PARAM_PROB)
! 2910: state_icmp++;
! 2911: break;
! 2912: #endif /* INET6 */
! 2913: }
! 2914:
! 2915: r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
! 2916:
! 2917: if (direction == PF_OUT) {
! 2918: bport = nport = sport;
! 2919: /* check outgoing packet for BINAT/NAT */
! 2920: if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
! 2921: saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
! 2922: PF_ACPY(&pd->baddr, saddr, af);
! 2923: switch (pd->proto) {
! 2924: case IPPROTO_TCP:
! 2925: pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
! 2926: &th->th_sum, &pd->naddr, nport, 0, af);
! 2927: sport = th->th_sport;
! 2928: rewrite++;
! 2929: break;
! 2930: case IPPROTO_UDP:
! 2931: pf_change_ap(saddr, &pd->hdr.udp->uh_sport,
! 2932: pd->ip_sum, &pd->hdr.udp->uh_sum,
! 2933: &pd->naddr, nport, 1, af);
! 2934: sport = pd->hdr.udp->uh_sport;
! 2935: rewrite++;
! 2936: break;
! 2937: #ifdef INET
! 2938: case IPPROTO_ICMP:
! 2939: pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
! 2940: pd->naddr.v4.s_addr, 0);
! 2941: pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
! 2942: pd->hdr.icmp->icmp_cksum, sport, nport, 0);
! 2943: pd->hdr.icmp->icmp_id = nport;
! 2944: m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
! 2945: break;
! 2946: #endif /* INET */
! 2947: #ifdef INET6
! 2948: case IPPROTO_ICMPV6:
! 2949: pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
! 2950: &pd->naddr, 0);
! 2951: rewrite++;
! 2952: break;
! 2953: #endif /* INET */
! 2954: default:
! 2955: switch (af) {
! 2956: #ifdef INET
! 2957: case AF_INET:
! 2958: pf_change_a(&saddr->v4.s_addr,
! 2959: pd->ip_sum, pd->naddr.v4.s_addr, 0);
! 2960: break;
! 2961: #endif /* INET */
! 2962: #ifdef INET6
! 2963: case AF_INET6:
! 2964: PF_ACPY(saddr, &pd->naddr, af);
! 2965: break;
! 2966: #endif /* INET */
! 2967: }
! 2968: break;
! 2969: }
! 2970:
! 2971: if (nr->natpass)
! 2972: r = NULL;
! 2973: pd->nat_rule = nr;
! 2974: }
! 2975: } else {
! 2976: bport = nport = dport;
! 2977: /* check incoming packet for BINAT/RDR */
! 2978: if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
! 2979: saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) {
! 2980: PF_ACPY(&pd->baddr, daddr, af);
! 2981: switch (pd->proto) {
! 2982: case IPPROTO_TCP:
! 2983: pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
! 2984: &th->th_sum, &pd->naddr, nport, 0, af);
! 2985: dport = th->th_dport;
! 2986: rewrite++;
! 2987: break;
! 2988: case IPPROTO_UDP:
! 2989: pf_change_ap(daddr, &pd->hdr.udp->uh_dport,
! 2990: pd->ip_sum, &pd->hdr.udp->uh_sum,
! 2991: &pd->naddr, nport, 1, af);
! 2992: dport = pd->hdr.udp->uh_dport;
! 2993: rewrite++;
! 2994: break;
! 2995: #ifdef INET
! 2996: case IPPROTO_ICMP:
! 2997: pf_change_a(&daddr->v4.s_addr, pd->ip_sum,
! 2998: pd->naddr.v4.s_addr, 0);
! 2999: break;
! 3000: #endif /* INET */
! 3001: #ifdef INET6
! 3002: case IPPROTO_ICMPV6:
! 3003: pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
! 3004: &pd->naddr, 0);
! 3005: rewrite++;
! 3006: break;
! 3007: #endif /* INET6 */
! 3008: default:
! 3009: switch (af) {
! 3010: #ifdef INET
! 3011: case AF_INET:
! 3012: pf_change_a(&daddr->v4.s_addr,
! 3013: pd->ip_sum, pd->naddr.v4.s_addr, 0);
! 3014: break;
! 3015: #endif /* INET */
! 3016: #ifdef INET6
! 3017: case AF_INET6:
! 3018: PF_ACPY(daddr, &pd->naddr, af);
! 3019: break;
! 3020: #endif /* INET */
! 3021: }
! 3022: break;
! 3023: }
! 3024:
! 3025: if (nr->natpass)
! 3026: r = NULL;
! 3027: pd->nat_rule = nr;
! 3028: }
! 3029: }
! 3030:
! 3031: while (r != NULL) {
! 3032: r->evaluations++;
! 3033: if (pfi_kif_match(r->kif, kif) == r->ifnot)
! 3034: r = r->skip[PF_SKIP_IFP].ptr;
! 3035: else if (r->direction && r->direction != direction)
! 3036: r = r->skip[PF_SKIP_DIR].ptr;
! 3037: else if (r->af && r->af != af)
! 3038: r = r->skip[PF_SKIP_AF].ptr;
! 3039: else if (r->proto && r->proto != pd->proto)
! 3040: r = r->skip[PF_SKIP_PROTO].ptr;
! 3041: else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
! 3042: r->src.neg, kif))
! 3043: r = r->skip[PF_SKIP_SRC_ADDR].ptr;
! 3044: /* tcp/udp only. port_op always 0 in other cases */
! 3045: else if (r->src.port_op && !pf_match_port(r->src.port_op,
! 3046: r->src.port[0], r->src.port[1], sport))
! 3047: r = r->skip[PF_SKIP_SRC_PORT].ptr;
! 3048: else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
! 3049: r->dst.neg, NULL))
! 3050: r = r->skip[PF_SKIP_DST_ADDR].ptr;
! 3051: /* tcp/udp only. port_op always 0 in other cases */
! 3052: else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
! 3053: r->dst.port[0], r->dst.port[1], dport))
! 3054: r = r->skip[PF_SKIP_DST_PORT].ptr;
! 3055: /* icmp only. type always 0 in other cases */
! 3056: else if (r->type && r->type != icmptype + 1)
! 3057: r = TAILQ_NEXT(r, entries);
! 3058: /* icmp only. type always 0 in other cases */
! 3059: else if (r->code && r->code != icmpcode + 1)
! 3060: r = TAILQ_NEXT(r, entries);
! 3061: else if (r->tos && !(r->tos == pd->tos))
! 3062: r = TAILQ_NEXT(r, entries);
! 3063: else if (r->rule_flag & PFRULE_FRAGMENT)
! 3064: r = TAILQ_NEXT(r, entries);
! 3065: else if (pd->proto == IPPROTO_TCP &&
! 3066: (r->flagset & th->th_flags) != r->flags)
! 3067: r = TAILQ_NEXT(r, entries);
! 3068: /* tcp/udp only. uid.op always 0 in other cases */
! 3069: else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
! 3070: pf_socket_lookup(direction, pd), 1)) &&
! 3071: !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
! 3072: pd->lookup.uid))
! 3073: r = TAILQ_NEXT(r, entries);
! 3074: /* tcp/udp only. gid.op always 0 in other cases */
! 3075: else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
! 3076: pf_socket_lookup(direction, pd), 1)) &&
! 3077: !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
! 3078: pd->lookup.gid))
! 3079: r = TAILQ_NEXT(r, entries);
! 3080: else if (r->prob && r->prob <= arc4random())
! 3081: r = TAILQ_NEXT(r, entries);
! 3082: else if (r->match_tag && !pf_match_tag(m, r, &tag))
! 3083: r = TAILQ_NEXT(r, entries);
! 3084: else if (r->os_fingerprint != PF_OSFP_ANY &&
! 3085: (pd->proto != IPPROTO_TCP || !pf_osfp_match(
! 3086: pf_osfp_fingerprint(pd, m, off, th),
! 3087: r->os_fingerprint)))
! 3088: r = TAILQ_NEXT(r, entries);
! 3089: else {
! 3090: if (r->tag)
! 3091: tag = r->tag;
! 3092: if (r->rtableid >= 0)
! 3093: rtableid = r->rtableid;
! 3094: if (r->anchor == NULL) {
! 3095: match = 1;
! 3096: *rm = r;
! 3097: *am = a;
! 3098: *rsm = ruleset;
! 3099: if ((*rm)->quick)
! 3100: break;
! 3101: r = TAILQ_NEXT(r, entries);
! 3102: } else
! 3103: pf_step_into_anchor(&asd, &ruleset,
! 3104: PF_RULESET_FILTER, &r, &a, &match);
! 3105: }
! 3106: if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
! 3107: PF_RULESET_FILTER, &r, &a, &match))
! 3108: break;
! 3109: }
! 3110: r = *rm;
! 3111: a = *am;
! 3112: ruleset = *rsm;
! 3113:
! 3114: REASON_SET(&reason, PFRES_MATCH);
! 3115:
! 3116: if (r->log || (nr != NULL && nr->log)) {
! 3117: if (rewrite)
! 3118: m_copyback(m, off, hdrlen, pd->hdr.any);
! 3119: PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr,
! 3120: a, ruleset, pd);
! 3121: }
! 3122:
! 3123: if ((r->action == PF_DROP) &&
! 3124: ((r->rule_flag & PFRULE_RETURNRST) ||
! 3125: (r->rule_flag & PFRULE_RETURNICMP) ||
! 3126: (r->rule_flag & PFRULE_RETURN))) {
! 3127: /* undo NAT changes, if they have taken place */
! 3128: if (nr != NULL) {
! 3129: if (direction == PF_OUT) {
! 3130: switch (pd->proto) {
! 3131: case IPPROTO_TCP:
! 3132: pf_change_ap(saddr, &th->th_sport,
! 3133: pd->ip_sum, &th->th_sum,
! 3134: &pd->baddr, bport, 0, af);
! 3135: sport = th->th_sport;
! 3136: rewrite++;
! 3137: break;
! 3138: case IPPROTO_UDP:
! 3139: pf_change_ap(saddr,
! 3140: &pd->hdr.udp->uh_sport, pd->ip_sum,
! 3141: &pd->hdr.udp->uh_sum, &pd->baddr,
! 3142: bport, 1, af);
! 3143: sport = pd->hdr.udp->uh_sport;
! 3144: rewrite++;
! 3145: break;
! 3146: case IPPROTO_ICMP:
! 3147: #ifdef INET6
! 3148: case IPPROTO_ICMPV6:
! 3149: #endif
! 3150: /* nothing! */
! 3151: break;
! 3152: default:
! 3153: switch (af) {
! 3154: case AF_INET:
! 3155: pf_change_a(&saddr->v4.s_addr,
! 3156: pd->ip_sum,
! 3157: pd->baddr.v4.s_addr, 0);
! 3158: break;
! 3159: case AF_INET6:
! 3160: PF_ACPY(saddr, &pd->baddr, af);
! 3161: break;
! 3162: }
! 3163: }
! 3164: } else {
! 3165: switch (pd->proto) {
! 3166: case IPPROTO_TCP:
! 3167: pf_change_ap(daddr, &th->th_dport,
! 3168: pd->ip_sum, &th->th_sum,
! 3169: &pd->baddr, bport, 0, af);
! 3170: dport = th->th_dport;
! 3171: rewrite++;
! 3172: break;
! 3173: case IPPROTO_UDP:
! 3174: pf_change_ap(daddr,
! 3175: &pd->hdr.udp->uh_dport, pd->ip_sum,
! 3176: &pd->hdr.udp->uh_sum, &pd->baddr,
! 3177: bport, 1, af);
! 3178: dport = pd->hdr.udp->uh_dport;
! 3179: rewrite++;
! 3180: break;
! 3181: case IPPROTO_ICMP:
! 3182: #ifdef INET6
! 3183: case IPPROTO_ICMPV6:
! 3184: #endif
! 3185: /* nothing! */
! 3186: break;
! 3187: default:
! 3188: switch (af) {
! 3189: case AF_INET:
! 3190: pf_change_a(&daddr->v4.s_addr,
! 3191: pd->ip_sum,
! 3192: pd->baddr.v4.s_addr, 0);
! 3193: break;
! 3194: case AF_INET6:
! 3195: PF_ACPY(daddr, &pd->baddr, af);
! 3196: break;
! 3197: }
! 3198: }
! 3199: }
! 3200: }
! 3201: if (pd->proto == IPPROTO_TCP &&
! 3202: ((r->rule_flag & PFRULE_RETURNRST) ||
! 3203: (r->rule_flag & PFRULE_RETURN)) &&
! 3204: !(th->th_flags & TH_RST)) {
! 3205: u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
! 3206: struct ip *h = mtod(m, struct ip *);
! 3207:
! 3208: if (pf_check_proto_cksum(m, off,
! 3209: ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET))
! 3210: REASON_SET(&reason, PFRES_PROTCKSUM);
! 3211: else {
! 3212: if (th->th_flags & TH_SYN)
! 3213: ack++;
! 3214: if (th->th_flags & TH_FIN)
! 3215: ack++;
! 3216: pf_send_tcp(r, af, pd->dst,
! 3217: pd->src, th->th_dport, th->th_sport,
! 3218: ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
! 3219: r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp);
! 3220: }
! 3221: } else if ((af == AF_INET) && r->return_icmp)
! 3222: pf_send_icmp(m, r->return_icmp >> 8,
! 3223: r->return_icmp & 255, af, r);
! 3224: else if ((af == AF_INET6) && r->return_icmp6)
! 3225: pf_send_icmp(m, r->return_icmp6 >> 8,
! 3226: r->return_icmp6 & 255, af, r);
! 3227: }
! 3228:
! 3229: if (r->action == PF_DROP)
! 3230: return (PF_DROP);
! 3231:
! 3232: if (pf_tag_packet(m, tag, rtableid)) {
! 3233: REASON_SET(&reason, PFRES_MEMORY);
! 3234: return (PF_DROP);
! 3235: }
! 3236:
! 3237: if (!state_icmp && (r->keep_state || nr != NULL ||
! 3238: (pd->flags & PFDESC_TCP_NORM))) {
! 3239: /* create new state */
! 3240: u_int16_t len;
! 3241: struct pf_state *s = NULL;
! 3242: struct pf_state_key *sk = NULL;
! 3243: struct pf_src_node *sn = NULL;
! 3244:
! 3245: /* check maximums */
! 3246: if (r->max_states && (r->states >= r->max_states)) {
! 3247: pf_status.lcounters[LCNT_STATES]++;
! 3248: REASON_SET(&reason, PFRES_MAXSTATES);
! 3249: goto cleanup;
! 3250: }
! 3251: /* src node for filter rule */
! 3252: if ((r->rule_flag & PFRULE_SRCTRACK ||
! 3253: r->rpool.opts & PF_POOL_STICKYADDR) &&
! 3254: pf_insert_src_node(&sn, r, saddr, af) != 0) {
! 3255: REASON_SET(&reason, PFRES_SRCLIMIT);
! 3256: goto cleanup;
! 3257: }
! 3258: /* src node for translation rule */
! 3259: if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
! 3260: ((direction == PF_OUT &&
! 3261: pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
! 3262: (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
! 3263: REASON_SET(&reason, PFRES_SRCLIMIT);
! 3264: goto cleanup;
! 3265: }
! 3266: s = pool_get(&pf_state_pl, PR_NOWAIT);
! 3267: if (s == NULL) {
! 3268: REASON_SET(&reason, PFRES_MEMORY);
! 3269: cleanup:
! 3270: if (sn != NULL && sn->states == 0 && sn->expire == 0) {
! 3271: RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
! 3272: pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
! 3273: pf_status.src_nodes--;
! 3274: pool_put(&pf_src_tree_pl, sn);
! 3275: }
! 3276: if (nsn != sn && nsn != NULL && nsn->states == 0 &&
! 3277: nsn->expire == 0) {
! 3278: RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
! 3279: pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
! 3280: pf_status.src_nodes--;
! 3281: pool_put(&pf_src_tree_pl, nsn);
! 3282: }
! 3283: if (sk != NULL) {
! 3284: pool_put(&pf_state_key_pl, sk);
! 3285: }
! 3286: return (PF_DROP);
! 3287: }
! 3288: bzero(s, sizeof(*s));
! 3289: s->rule.ptr = r;
! 3290: s->nat_rule.ptr = nr;
! 3291: s->anchor.ptr = a;
! 3292: STATE_INC_COUNTERS(s);
! 3293: s->allow_opts = r->allow_opts;
! 3294: s->log = r->log & PF_LOG_ALL;
! 3295: if (nr != NULL)
! 3296: s->log |= nr->log & PF_LOG_ALL;
! 3297: switch (pd->proto) {
! 3298: case IPPROTO_TCP:
! 3299: len = pd->tot_len - off - (th->th_off << 2);
! 3300: s->src.seqlo = ntohl(th->th_seq);
! 3301: s->src.seqhi = s->src.seqlo + len + 1;
! 3302: if ((th->th_flags & (TH_SYN|TH_ACK)) ==
! 3303: TH_SYN && r->keep_state == PF_STATE_MODULATE) {
! 3304: /* Generate sequence number modulator */
! 3305: while ((s->src.seqdiff =
! 3306: tcp_rndiss_next() - s->src.seqlo) == 0)
! 3307: ;
! 3308: pf_change_a(&th->th_seq, &th->th_sum,
! 3309: htonl(s->src.seqlo + s->src.seqdiff), 0);
! 3310: rewrite = 1;
! 3311: } else
! 3312: s->src.seqdiff = 0;
! 3313: if (th->th_flags & TH_SYN) {
! 3314: s->src.seqhi++;
! 3315: s->src.wscale = pf_get_wscale(m, off,
! 3316: th->th_off, af);
! 3317: }
! 3318: s->src.max_win = MAX(ntohs(th->th_win), 1);
! 3319: if (s->src.wscale & PF_WSCALE_MASK) {
! 3320: /* Remove scale factor from initial window */
! 3321: int win = s->src.max_win;
! 3322: win += 1 << (s->src.wscale & PF_WSCALE_MASK);
! 3323: s->src.max_win = (win - 1) >>
! 3324: (s->src.wscale & PF_WSCALE_MASK);
! 3325: }
! 3326: if (th->th_flags & TH_FIN)
! 3327: s->src.seqhi++;
! 3328: s->dst.seqhi = 1;
! 3329: s->dst.max_win = 1;
! 3330: s->src.state = TCPS_SYN_SENT;
! 3331: s->dst.state = TCPS_CLOSED;
! 3332: s->timeout = PFTM_TCP_FIRST_PACKET;
! 3333: break;
! 3334: case IPPROTO_UDP:
! 3335: s->src.state = PFUDPS_SINGLE;
! 3336: s->dst.state = PFUDPS_NO_TRAFFIC;
! 3337: s->timeout = PFTM_UDP_FIRST_PACKET;
! 3338: break;
! 3339: case IPPROTO_ICMP:
! 3340: #ifdef INET6
! 3341: case IPPROTO_ICMPV6:
! 3342: #endif
! 3343: s->timeout = PFTM_ICMP_FIRST_PACKET;
! 3344: break;
! 3345: default:
! 3346: s->src.state = PFOTHERS_SINGLE;
! 3347: s->dst.state = PFOTHERS_NO_TRAFFIC;
! 3348: s->timeout = PFTM_OTHER_FIRST_PACKET;
! 3349: }
! 3350:
! 3351: s->creation = time_second;
! 3352: s->expire = time_second;
! 3353:
! 3354: if (sn != NULL) {
! 3355: s->src_node = sn;
! 3356: s->src_node->states++;
! 3357: }
! 3358: if (nsn != NULL) {
! 3359: PF_ACPY(&nsn->raddr, &pd->naddr, af);
! 3360: s->nat_src_node = nsn;
! 3361: s->nat_src_node->states++;
! 3362: }
! 3363: if (pd->proto == IPPROTO_TCP) {
! 3364: if ((pd->flags & PFDESC_TCP_NORM) &&
! 3365: pf_normalize_tcp_init(m, off, pd, th, &s->src,
! 3366: &s->dst)) {
! 3367: REASON_SET(&reason, PFRES_MEMORY);
! 3368: pf_src_tree_remove_state(s);
! 3369: STATE_DEC_COUNTERS(s);
! 3370: pool_put(&pf_state_pl, s);
! 3371: return (PF_DROP);
! 3372: }
! 3373: if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
! 3374: pf_normalize_tcp_stateful(m, off, pd, &reason,
! 3375: th, s, &s->src, &s->dst, &rewrite)) {
! 3376: /* This really shouldn't happen!!! */
! 3377: DPFPRINTF(PF_DEBUG_URGENT,
! 3378: ("pf_normalize_tcp_stateful failed on "
! 3379: "first pkt"));
! 3380: pf_normalize_tcp_cleanup(s);
! 3381: pf_src_tree_remove_state(s);
! 3382: STATE_DEC_COUNTERS(s);
! 3383: pool_put(&pf_state_pl, s);
! 3384: return (PF_DROP);
! 3385: }
! 3386: }
! 3387:
! 3388: if ((sk = pf_alloc_state_key(s)) == NULL) {
! 3389: REASON_SET(&reason, PFRES_MEMORY);
! 3390: goto cleanup;
! 3391: }
! 3392:
! 3393: sk->proto = pd->proto;
! 3394: sk->direction = direction;
! 3395: sk->af = af;
! 3396: if (direction == PF_OUT) {
! 3397: PF_ACPY(&sk->gwy.addr, saddr, af);
! 3398: PF_ACPY(&sk->ext.addr, daddr, af);
! 3399: switch (pd->proto) {
! 3400: case IPPROTO_ICMP:
! 3401: #ifdef INET6
! 3402: case IPPROTO_ICMPV6:
! 3403: #endif
! 3404: sk->gwy.port = nport;
! 3405: sk->ext.port = 0;
! 3406: break;
! 3407: default:
! 3408: sk->gwy.port = sport;
! 3409: sk->ext.port = dport;
! 3410: }
! 3411: if (nr != NULL) {
! 3412: PF_ACPY(&sk->lan.addr, &pd->baddr, af);
! 3413: sk->lan.port = bport;
! 3414: } else {
! 3415: PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af);
! 3416: sk->lan.port = sk->gwy.port;
! 3417: }
! 3418: } else {
! 3419: PF_ACPY(&sk->lan.addr, daddr, af);
! 3420: PF_ACPY(&sk->ext.addr, saddr, af);
! 3421: switch (pd->proto) {
! 3422: case IPPROTO_ICMP:
! 3423: #ifdef INET6
! 3424: case IPPROTO_ICMPV6:
! 3425: #endif
! 3426: sk->lan.port = nport;
! 3427: sk->ext.port = 0;
! 3428: break;
! 3429: default:
! 3430: sk->lan.port = dport;
! 3431: sk->ext.port = sport;
! 3432: }
! 3433: if (nr != NULL) {
! 3434: PF_ACPY(&sk->gwy.addr, &pd->baddr, af);
! 3435: sk->gwy.port = bport;
! 3436: } else {
! 3437: PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af);
! 3438: sk->gwy.port = sk->lan.port;
! 3439: }
! 3440: }
! 3441:
! 3442: pf_set_rt_ifp(s, saddr); /* needs s->state_key set */
! 3443:
! 3444: if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
! 3445: if (pd->proto == IPPROTO_TCP)
! 3446: pf_normalize_tcp_cleanup(s);
! 3447: REASON_SET(&reason, PFRES_STATEINS);
! 3448: pf_src_tree_remove_state(s);
! 3449: STATE_DEC_COUNTERS(s);
! 3450: pool_put(&pf_state_pl, s);
! 3451: return (PF_DROP);
! 3452: } else
! 3453: *sm = s;
! 3454: if (tag > 0) {
! 3455: pf_tag_ref(tag);
! 3456: s->tag = tag;
! 3457: }
! 3458: if (pd->proto == IPPROTO_TCP &&
! 3459: (th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
! 3460: r->keep_state == PF_STATE_SYNPROXY) {
! 3461: s->src.state = PF_TCPS_PROXY_SRC;
! 3462: if (nr != NULL) {
! 3463: if (direction == PF_OUT) {
! 3464: pf_change_ap(saddr, &th->th_sport,
! 3465: pd->ip_sum, &th->th_sum, &pd->baddr,
! 3466: bport, 0, af);
! 3467: sport = th->th_sport;
! 3468: } else {
! 3469: pf_change_ap(daddr, &th->th_dport,
! 3470: pd->ip_sum, &th->th_sum, &pd->baddr,
! 3471: bport, 0, af);
! 3472: sport = th->th_dport;
! 3473: }
! 3474: }
! 3475: s->src.seqhi = htonl(arc4random());
! 3476: /* Find mss option */
! 3477: mss = pf_get_mss(m, off, th->th_off, af);
! 3478: mss = pf_calc_mss(saddr, af, mss);
! 3479: mss = pf_calc_mss(daddr, af, mss);
! 3480: s->src.mss = mss;
! 3481: pf_send_tcp(r, af, daddr, saddr, th->th_dport,
! 3482: th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
! 3483: TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
! 3484: REASON_SET(&reason, PFRES_SYNPROXY);
! 3485: return (PF_SYNPROXY_DROP);
! 3486: }
! 3487: }
! 3488:
! 3489: /* copy back packet headers if we performed NAT operations */
! 3490: if (rewrite)
! 3491: m_copyback(m, off, hdrlen, pd->hdr.any);
! 3492:
! 3493: return (PF_PASS);
! 3494: }
! 3495:
! 3496: int
! 3497: pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
! 3498: struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
! 3499: struct pf_ruleset **rsm)
! 3500: {
! 3501: struct pf_rule *r, *a = NULL;
! 3502: struct pf_ruleset *ruleset = NULL;
! 3503: sa_family_t af = pd->af;
! 3504: u_short reason;
! 3505: int tag = -1;
! 3506: int asd = 0;
! 3507: int match = 0;
! 3508:
! 3509: r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
! 3510: while (r != NULL) {
! 3511: r->evaluations++;
! 3512: if (pfi_kif_match(r->kif, kif) == r->ifnot)
! 3513: r = r->skip[PF_SKIP_IFP].ptr;
! 3514: else if (r->direction && r->direction != direction)
! 3515: r = r->skip[PF_SKIP_DIR].ptr;
! 3516: else if (r->af && r->af != af)
! 3517: r = r->skip[PF_SKIP_AF].ptr;
! 3518: else if (r->proto && r->proto != pd->proto)
! 3519: r = r->skip[PF_SKIP_PROTO].ptr;
! 3520: else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
! 3521: r->src.neg, kif))
! 3522: r = r->skip[PF_SKIP_SRC_ADDR].ptr;
! 3523: else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
! 3524: r->dst.neg, NULL))
! 3525: r = r->skip[PF_SKIP_DST_ADDR].ptr;
! 3526: else if (r->tos && !(r->tos == pd->tos))
! 3527: r = TAILQ_NEXT(r, entries);
! 3528: else if (r->src.port_op || r->dst.port_op ||
! 3529: r->flagset || r->type || r->code ||
! 3530: r->os_fingerprint != PF_OSFP_ANY)
! 3531: r = TAILQ_NEXT(r, entries);
! 3532: else if (r->prob && r->prob <= arc4random())
! 3533: r = TAILQ_NEXT(r, entries);
! 3534: else if (r->match_tag && !pf_match_tag(m, r, &tag))
! 3535: r = TAILQ_NEXT(r, entries);
! 3536: else {
! 3537: if (r->anchor == NULL) {
! 3538: match = 1;
! 3539: *rm = r;
! 3540: *am = a;
! 3541: *rsm = ruleset;
! 3542: if ((*rm)->quick)
! 3543: break;
! 3544: r = TAILQ_NEXT(r, entries);
! 3545: } else
! 3546: pf_step_into_anchor(&asd, &ruleset,
! 3547: PF_RULESET_FILTER, &r, &a, &match);
! 3548: }
! 3549: if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset,
! 3550: PF_RULESET_FILTER, &r, &a, &match))
! 3551: break;
! 3552: }
! 3553: r = *rm;
! 3554: a = *am;
! 3555: ruleset = *rsm;
! 3556:
! 3557: REASON_SET(&reason, PFRES_MATCH);
! 3558:
! 3559: if (r->log)
! 3560: PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset,
! 3561: pd);
! 3562:
! 3563: if (r->action != PF_PASS)
! 3564: return (PF_DROP);
! 3565:
! 3566: if (pf_tag_packet(m, tag, -1)) {
! 3567: REASON_SET(&reason, PFRES_MEMORY);
! 3568: return (PF_DROP);
! 3569: }
! 3570:
! 3571: return (PF_PASS);
! 3572: }
! 3573:
! 3574: int
! 3575: pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
! 3576: struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
! 3577: u_short *reason)
! 3578: {
! 3579: struct pf_state_key_cmp key;
! 3580: struct tcphdr *th = pd->hdr.tcp;
! 3581: u_int16_t win = ntohs(th->th_win);
! 3582: u_int32_t ack, end, seq, orig_seq;
! 3583: u_int8_t sws, dws;
! 3584: int ackskew;
! 3585: int copyback = 0;
! 3586: struct pf_state_peer *src, *dst;
! 3587:
! 3588: key.af = pd->af;
! 3589: key.proto = IPPROTO_TCP;
! 3590: if (direction == PF_IN) {
! 3591: PF_ACPY(&key.ext.addr, pd->src, key.af);
! 3592: PF_ACPY(&key.gwy.addr, pd->dst, key.af);
! 3593: key.ext.port = th->th_sport;
! 3594: key.gwy.port = th->th_dport;
! 3595: } else {
! 3596: PF_ACPY(&key.lan.addr, pd->src, key.af);
! 3597: PF_ACPY(&key.ext.addr, pd->dst, key.af);
! 3598: key.lan.port = th->th_sport;
! 3599: key.ext.port = th->th_dport;
! 3600: }
! 3601:
! 3602: STATE_LOOKUP();
! 3603:
! 3604: if (direction == (*state)->state_key->direction) {
! 3605: src = &(*state)->src;
! 3606: dst = &(*state)->dst;
! 3607: } else {
! 3608: src = &(*state)->dst;
! 3609: dst = &(*state)->src;
! 3610: }
! 3611:
! 3612: if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
! 3613: if (direction != (*state)->state_key->direction) {
! 3614: REASON_SET(reason, PFRES_SYNPROXY);
! 3615: return (PF_SYNPROXY_DROP);
! 3616: }
! 3617: if (th->th_flags & TH_SYN) {
! 3618: if (ntohl(th->th_seq) != (*state)->src.seqlo) {
! 3619: REASON_SET(reason, PFRES_SYNPROXY);
! 3620: return (PF_DROP);
! 3621: }
! 3622: pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
! 3623: pd->src, th->th_dport, th->th_sport,
! 3624: (*state)->src.seqhi, ntohl(th->th_seq) + 1,
! 3625: TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
! 3626: 0, NULL, NULL);
! 3627: REASON_SET(reason, PFRES_SYNPROXY);
! 3628: return (PF_SYNPROXY_DROP);
! 3629: } else if (!(th->th_flags & TH_ACK) ||
! 3630: (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
! 3631: (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
! 3632: REASON_SET(reason, PFRES_SYNPROXY);
! 3633: return (PF_DROP);
! 3634: } else if ((*state)->src_node != NULL &&
! 3635: pf_src_connlimit(state)) {
! 3636: REASON_SET(reason, PFRES_SRCLIMIT);
! 3637: return (PF_DROP);
! 3638: } else
! 3639: (*state)->src.state = PF_TCPS_PROXY_DST;
! 3640: }
! 3641: if ((*state)->src.state == PF_TCPS_PROXY_DST) {
! 3642: struct pf_state_host *src, *dst;
! 3643:
! 3644: if (direction == PF_OUT) {
! 3645: src = &(*state)->state_key->gwy;
! 3646: dst = &(*state)->state_key->ext;
! 3647: } else {
! 3648: src = &(*state)->state_key->ext;
! 3649: dst = &(*state)->state_key->lan;
! 3650: }
! 3651: if (direction == (*state)->state_key->direction) {
! 3652: if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
! 3653: (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
! 3654: (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
! 3655: REASON_SET(reason, PFRES_SYNPROXY);
! 3656: return (PF_DROP);
! 3657: }
! 3658: (*state)->src.max_win = MAX(ntohs(th->th_win), 1);
! 3659: if ((*state)->dst.seqhi == 1)
! 3660: (*state)->dst.seqhi = htonl(arc4random());
! 3661: pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
! 3662: &dst->addr, src->port, dst->port,
! 3663: (*state)->dst.seqhi, 0, TH_SYN, 0,
! 3664: (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL);
! 3665: REASON_SET(reason, PFRES_SYNPROXY);
! 3666: return (PF_SYNPROXY_DROP);
! 3667: } else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
! 3668: (TH_SYN|TH_ACK)) ||
! 3669: (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
! 3670: REASON_SET(reason, PFRES_SYNPROXY);
! 3671: return (PF_DROP);
! 3672: } else {
! 3673: (*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
! 3674: (*state)->dst.seqlo = ntohl(th->th_seq);
! 3675: pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
! 3676: pd->src, th->th_dport, th->th_sport,
! 3677: ntohl(th->th_ack), ntohl(th->th_seq) + 1,
! 3678: TH_ACK, (*state)->src.max_win, 0, 0, 0,
! 3679: (*state)->tag, NULL, NULL);
! 3680: pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
! 3681: &dst->addr, src->port, dst->port,
! 3682: (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
! 3683: TH_ACK, (*state)->dst.max_win, 0, 0, 1,
! 3684: 0, NULL, NULL);
! 3685: (*state)->src.seqdiff = (*state)->dst.seqhi -
! 3686: (*state)->src.seqlo;
! 3687: (*state)->dst.seqdiff = (*state)->src.seqhi -
! 3688: (*state)->dst.seqlo;
! 3689: (*state)->src.seqhi = (*state)->src.seqlo +
! 3690: (*state)->dst.max_win;
! 3691: (*state)->dst.seqhi = (*state)->dst.seqlo +
! 3692: (*state)->src.max_win;
! 3693: (*state)->src.wscale = (*state)->dst.wscale = 0;
! 3694: (*state)->src.state = (*state)->dst.state =
! 3695: TCPS_ESTABLISHED;
! 3696: REASON_SET(reason, PFRES_SYNPROXY);
! 3697: return (PF_SYNPROXY_DROP);
! 3698: }
! 3699: }
! 3700:
! 3701: if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
! 3702: sws = src->wscale & PF_WSCALE_MASK;
! 3703: dws = dst->wscale & PF_WSCALE_MASK;
! 3704: } else
! 3705: sws = dws = 0;
! 3706:
! 3707: /*
! 3708: * Sequence tracking algorithm from Guido van Rooij's paper:
! 3709: * http://www.madison-gurkha.com/publications/tcp_filtering/
! 3710: * tcp_filtering.ps
! 3711: */
! 3712:
! 3713: orig_seq = seq = ntohl(th->th_seq);
! 3714: if (src->seqlo == 0) {
! 3715: /* First packet from this end. Set its state */
! 3716:
! 3717: if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
! 3718: src->scrub == NULL) {
! 3719: if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
! 3720: REASON_SET(reason, PFRES_MEMORY);
! 3721: return (PF_DROP);
! 3722: }
! 3723: }
! 3724:
! 3725: /* Deferred generation of sequence number modulator */
! 3726: if (dst->seqdiff && !src->seqdiff) {
! 3727: while ((src->seqdiff = tcp_rndiss_next() - seq) == 0)
! 3728: ;
! 3729: ack = ntohl(th->th_ack) - dst->seqdiff;
! 3730: pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
! 3731: src->seqdiff), 0);
! 3732: pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
! 3733: copyback = 1;
! 3734: } else {
! 3735: ack = ntohl(th->th_ack);
! 3736: }
! 3737:
! 3738: end = seq + pd->p_len;
! 3739: if (th->th_flags & TH_SYN) {
! 3740: end++;
! 3741: if (dst->wscale & PF_WSCALE_FLAG) {
! 3742: src->wscale = pf_get_wscale(m, off, th->th_off,
! 3743: pd->af);
! 3744: if (src->wscale & PF_WSCALE_FLAG) {
! 3745: /* Remove scale factor from initial
! 3746: * window */
! 3747: sws = src->wscale & PF_WSCALE_MASK;
! 3748: win = ((u_int32_t)win + (1 << sws) - 1)
! 3749: >> sws;
! 3750: dws = dst->wscale & PF_WSCALE_MASK;
! 3751: } else {
! 3752: /* fixup other window */
! 3753: dst->max_win <<= dst->wscale &
! 3754: PF_WSCALE_MASK;
! 3755: /* in case of a retrans SYN|ACK */
! 3756: dst->wscale = 0;
! 3757: }
! 3758: }
! 3759: }
! 3760: if (th->th_flags & TH_FIN)
! 3761: end++;
! 3762:
! 3763: src->seqlo = seq;
! 3764: if (src->state < TCPS_SYN_SENT)
! 3765: src->state = TCPS_SYN_SENT;
! 3766:
! 3767: /*
! 3768: * May need to slide the window (seqhi may have been set by
! 3769: * the crappy stack check or if we picked up the connection
! 3770: * after establishment)
! 3771: */
! 3772: if (src->seqhi == 1 ||
! 3773: SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
! 3774: src->seqhi = end + MAX(1, dst->max_win << dws);
! 3775: if (win > src->max_win)
! 3776: src->max_win = win;
! 3777:
! 3778: } else {
! 3779: ack = ntohl(th->th_ack) - dst->seqdiff;
! 3780: if (src->seqdiff) {
! 3781: /* Modulate sequence numbers */
! 3782: pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
! 3783: src->seqdiff), 0);
! 3784: pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
! 3785: copyback = 1;
! 3786: }
! 3787: end = seq + pd->p_len;
! 3788: if (th->th_flags & TH_SYN)
! 3789: end++;
! 3790: if (th->th_flags & TH_FIN)
! 3791: end++;
! 3792: }
! 3793:
! 3794: if ((th->th_flags & TH_ACK) == 0) {
! 3795: /* Let it pass through the ack skew check */
! 3796: ack = dst->seqlo;
! 3797: } else if ((ack == 0 &&
! 3798: (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
! 3799: /* broken tcp stacks do not set ack */
! 3800: (dst->state < TCPS_SYN_SENT)) {
! 3801: /*
! 3802: * Many stacks (ours included) will set the ACK number in an
! 3803: * FIN|ACK if the SYN times out -- no sequence to ACK.
! 3804: */
! 3805: ack = dst->seqlo;
! 3806: }
! 3807:
! 3808: if (seq == end) {
! 3809: /* Ease sequencing restrictions on no data packets */
! 3810: seq = src->seqlo;
! 3811: end = seq;
! 3812: }
! 3813:
! 3814: ackskew = dst->seqlo - ack;
! 3815:
! 3816:
! 3817: /*
! 3818: * Need to demodulate the sequence numbers in any TCP SACK options
! 3819: * (Selective ACK). We could optionally validate the SACK values
! 3820: * against the current ACK window, either forwards or backwards, but
! 3821: * I'm not confident that SACK has been implemented properly
! 3822: * everywhere. It wouldn't surprise me if several stacks accidently
! 3823: * SACK too far backwards of previously ACKed data. There really aren't
! 3824: * any security implications of bad SACKing unless the target stack
! 3825: * doesn't validate the option length correctly. Someone trying to
! 3826: * spoof into a TCP connection won't bother blindly sending SACK
! 3827: * options anyway.
! 3828: */
! 3829: if (dst->seqdiff && (th->th_off << 2) > sizeof(struct tcphdr)) {
! 3830: if (pf_modulate_sack(m, off, pd, th, dst))
! 3831: copyback = 1;
! 3832: }
! 3833:
! 3834:
! 3835: #define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */
! 3836: if (SEQ_GEQ(src->seqhi, end) &&
! 3837: /* Last octet inside other's window space */
! 3838: SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
! 3839: /* Retrans: not more than one window back */
! 3840: (ackskew >= -MAXACKWINDOW) &&
! 3841: /* Acking not more than one reassembled fragment backwards */
! 3842: (ackskew <= (MAXACKWINDOW << sws)) &&
! 3843: /* Acking not more than one window forward */
! 3844: ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
! 3845: (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) {
! 3846: /* Require an exact/+1 sequence match on resets when possible */
! 3847:
! 3848: if (dst->scrub || src->scrub) {
! 3849: if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
! 3850: *state, src, dst, ©back))
! 3851: return (PF_DROP);
! 3852: }
! 3853:
! 3854: /* update max window */
! 3855: if (src->max_win < win)
! 3856: src->max_win = win;
! 3857: /* synchronize sequencing */
! 3858: if (SEQ_GT(end, src->seqlo))
! 3859: src->seqlo = end;
! 3860: /* slide the window of what the other end can send */
! 3861: if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
! 3862: dst->seqhi = ack + MAX((win << sws), 1);
! 3863:
! 3864:
! 3865: /* update states */
! 3866: if (th->th_flags & TH_SYN)
! 3867: if (src->state < TCPS_SYN_SENT)
! 3868: src->state = TCPS_SYN_SENT;
! 3869: if (th->th_flags & TH_FIN)
! 3870: if (src->state < TCPS_CLOSING)
! 3871: src->state = TCPS_CLOSING;
! 3872: if (th->th_flags & TH_ACK) {
! 3873: if (dst->state == TCPS_SYN_SENT) {
! 3874: dst->state = TCPS_ESTABLISHED;
! 3875: if (src->state == TCPS_ESTABLISHED &&
! 3876: (*state)->src_node != NULL &&
! 3877: pf_src_connlimit(state)) {
! 3878: REASON_SET(reason, PFRES_SRCLIMIT);
! 3879: return (PF_DROP);
! 3880: }
! 3881: } else if (dst->state == TCPS_CLOSING)
! 3882: dst->state = TCPS_FIN_WAIT_2;
! 3883: }
! 3884: if (th->th_flags & TH_RST)
! 3885: src->state = dst->state = TCPS_TIME_WAIT;
! 3886:
! 3887: /* update expire time */
! 3888: (*state)->expire = time_second;
! 3889: if (src->state >= TCPS_FIN_WAIT_2 &&
! 3890: dst->state >= TCPS_FIN_WAIT_2)
! 3891: (*state)->timeout = PFTM_TCP_CLOSED;
! 3892: else if (src->state >= TCPS_CLOSING &&
! 3893: dst->state >= TCPS_CLOSING)
! 3894: (*state)->timeout = PFTM_TCP_FIN_WAIT;
! 3895: else if (src->state < TCPS_ESTABLISHED ||
! 3896: dst->state < TCPS_ESTABLISHED)
! 3897: (*state)->timeout = PFTM_TCP_OPENING;
! 3898: else if (src->state >= TCPS_CLOSING ||
! 3899: dst->state >= TCPS_CLOSING)
! 3900: (*state)->timeout = PFTM_TCP_CLOSING;
! 3901: else
! 3902: (*state)->timeout = PFTM_TCP_ESTABLISHED;
! 3903:
! 3904: /* Fall through to PASS packet */
! 3905:
! 3906: } else if ((dst->state < TCPS_SYN_SENT ||
! 3907: dst->state >= TCPS_FIN_WAIT_2 ||
! 3908: src->state >= TCPS_FIN_WAIT_2) &&
! 3909: SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
! 3910: /* Within a window forward of the originating packet */
! 3911: SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
! 3912: /* Within a window backward of the originating packet */
! 3913:
! 3914: /*
! 3915: * This currently handles three situations:
! 3916: * 1) Stupid stacks will shotgun SYNs before their peer
! 3917: * replies.
! 3918: * 2) When PF catches an already established stream (the
! 3919: * firewall rebooted, the state table was flushed, routes
! 3920: * changed...)
! 3921: * 3) Packets get funky immediately after the connection
! 3922: * closes (this should catch Solaris spurious ACK|FINs
! 3923: * that web servers like to spew after a close)
! 3924: *
! 3925: * This must be a little more careful than the above code
! 3926: * since packet floods will also be caught here. We don't
! 3927: * update the TTL here to mitigate the damage of a packet
! 3928: * flood and so the same code can handle awkward establishment
! 3929: * and a loosened connection close.
! 3930: * In the establishment case, a correct peer response will
! 3931: * validate the connection, go through the normal state code
! 3932: * and keep updating the state TTL.
! 3933: */
! 3934:
! 3935: if (pf_status.debug >= PF_DEBUG_MISC) {
! 3936: printf("pf: loose state match: ");
! 3937: pf_print_state(*state);
! 3938: pf_print_flags(th->th_flags);
! 3939: printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
! 3940: "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len,
! 3941: ackskew, (*state)->packets[0],
! 3942: (*state)->packets[1]);
! 3943: }
! 3944:
! 3945: if (dst->scrub || src->scrub) {
! 3946: if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
! 3947: *state, src, dst, ©back))
! 3948: return (PF_DROP);
! 3949: }
! 3950:
! 3951: /* update max window */
! 3952: if (src->max_win < win)
! 3953: src->max_win = win;
! 3954: /* synchronize sequencing */
! 3955: if (SEQ_GT(end, src->seqlo))
! 3956: src->seqlo = end;
! 3957: /* slide the window of what the other end can send */
! 3958: if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
! 3959: dst->seqhi = ack + MAX((win << sws), 1);
! 3960:
! 3961: /*
! 3962: * Cannot set dst->seqhi here since this could be a shotgunned
! 3963: * SYN and not an already established connection.
! 3964: */
! 3965:
! 3966: if (th->th_flags & TH_FIN)
! 3967: if (src->state < TCPS_CLOSING)
! 3968: src->state = TCPS_CLOSING;
! 3969: if (th->th_flags & TH_RST)
! 3970: src->state = dst->state = TCPS_TIME_WAIT;
! 3971:
! 3972: /* Fall through to PASS packet */
! 3973:
! 3974: } else {
! 3975: if ((*state)->dst.state == TCPS_SYN_SENT &&
! 3976: (*state)->src.state == TCPS_SYN_SENT) {
! 3977: /* Send RST for state mismatches during handshake */
! 3978: if (!(th->th_flags & TH_RST))
! 3979: pf_send_tcp((*state)->rule.ptr, pd->af,
! 3980: pd->dst, pd->src, th->th_dport,
! 3981: th->th_sport, ntohl(th->th_ack), 0,
! 3982: TH_RST, 0, 0,
! 3983: (*state)->rule.ptr->return_ttl, 1, 0,
! 3984: pd->eh, kif->pfik_ifp);
! 3985: src->seqlo = 0;
! 3986: src->seqhi = 1;
! 3987: src->max_win = 1;
! 3988: } else if (pf_status.debug >= PF_DEBUG_MISC) {
! 3989: printf("pf: BAD state: ");
! 3990: pf_print_state(*state);
! 3991: pf_print_flags(th->th_flags);
! 3992: printf(" seq=%u (%u) ack=%u len=%u ackskew=%d "
! 3993: "pkts=%llu:%llu dir=%s,%s\n",
! 3994: seq, orig_seq, ack, pd->p_len, ackskew,
! 3995: (*state)->packets[0], (*state)->packets[1],
! 3996: direction == PF_IN ? "in" : "out",
! 3997: direction == (*state)->state_key->direction ?
! 3998: "fwd" : "rev");
! 3999: printf("pf: State failure on: %c %c %c %c | %c %c\n",
! 4000: SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
! 4001: SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
! 4002: ' ': '2',
! 4003: (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
! 4004: (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
! 4005: SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
! 4006: SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
! 4007: }
! 4008: REASON_SET(reason, PFRES_BADSTATE);
! 4009: return (PF_DROP);
! 4010: }
! 4011:
! 4012: /* Any packets which have gotten here are to be passed */
! 4013:
! 4014: /* translate source/destination address, if necessary */
! 4015: if (STATE_TRANSLATE((*state)->state_key)) {
! 4016: if (direction == PF_OUT)
! 4017: pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
! 4018: &th->th_sum, &(*state)->state_key->gwy.addr,
! 4019: (*state)->state_key->gwy.port, 0, pd->af);
! 4020: else
! 4021: pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
! 4022: &th->th_sum, &(*state)->state_key->lan.addr,
! 4023: (*state)->state_key->lan.port, 0, pd->af);
! 4024: m_copyback(m, off, sizeof(*th), th);
! 4025: } else if (copyback) {
! 4026: /* Copyback sequence modulation or stateful scrub changes */
! 4027: m_copyback(m, off, sizeof(*th), th);
! 4028: }
! 4029:
! 4030: return (PF_PASS);
! 4031: }
! 4032:
! 4033: int
! 4034: pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
! 4035: struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
! 4036: {
! 4037: struct pf_state_peer *src, *dst;
! 4038: struct pf_state_key_cmp key;
! 4039: struct udphdr *uh = pd->hdr.udp;
! 4040:
! 4041: key.af = pd->af;
! 4042: key.proto = IPPROTO_UDP;
! 4043: if (direction == PF_IN) {
! 4044: PF_ACPY(&key.ext.addr, pd->src, key.af);
! 4045: PF_ACPY(&key.gwy.addr, pd->dst, key.af);
! 4046: key.ext.port = uh->uh_sport;
! 4047: key.gwy.port = uh->uh_dport;
! 4048: } else {
! 4049: PF_ACPY(&key.lan.addr, pd->src, key.af);
! 4050: PF_ACPY(&key.ext.addr, pd->dst, key.af);
! 4051: key.lan.port = uh->uh_sport;
! 4052: key.ext.port = uh->uh_dport;
! 4053: }
! 4054:
! 4055: STATE_LOOKUP();
! 4056:
! 4057: if (direction == (*state)->state_key->direction) {
! 4058: src = &(*state)->src;
! 4059: dst = &(*state)->dst;
! 4060: } else {
! 4061: src = &(*state)->dst;
! 4062: dst = &(*state)->src;
! 4063: }
! 4064:
! 4065: /* update states */
! 4066: if (src->state < PFUDPS_SINGLE)
! 4067: src->state = PFUDPS_SINGLE;
! 4068: if (dst->state == PFUDPS_SINGLE)
! 4069: dst->state = PFUDPS_MULTIPLE;
! 4070:
! 4071: /* update expire time */
! 4072: (*state)->expire = time_second;
! 4073: if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
! 4074: (*state)->timeout = PFTM_UDP_MULTIPLE;
! 4075: else
! 4076: (*state)->timeout = PFTM_UDP_SINGLE;
! 4077:
! 4078: /* translate source/destination address, if necessary */
! 4079: if (STATE_TRANSLATE((*state)->state_key)) {
! 4080: if (direction == PF_OUT)
! 4081: pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
! 4082: &uh->uh_sum, &(*state)->state_key->gwy.addr,
! 4083: (*state)->state_key->gwy.port, 1, pd->af);
! 4084: else
! 4085: pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
! 4086: &uh->uh_sum, &(*state)->state_key->lan.addr,
! 4087: (*state)->state_key->lan.port, 1, pd->af);
! 4088: m_copyback(m, off, sizeof(*uh), uh);
! 4089: }
! 4090:
! 4091: return (PF_PASS);
! 4092: }
! 4093:
! 4094: int
! 4095: pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
! 4096: struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
! 4097: {
! 4098: struct pf_addr *saddr = pd->src, *daddr = pd->dst;
! 4099: u_int16_t icmpid, *icmpsum;
! 4100: u_int8_t icmptype;
! 4101: int state_icmp = 0;
! 4102: struct pf_state_key_cmp key;
! 4103:
! 4104: switch (pd->proto) {
! 4105: #ifdef INET
! 4106: case IPPROTO_ICMP:
! 4107: icmptype = pd->hdr.icmp->icmp_type;
! 4108: icmpid = pd->hdr.icmp->icmp_id;
! 4109: icmpsum = &pd->hdr.icmp->icmp_cksum;
! 4110:
! 4111: if (icmptype == ICMP_UNREACH ||
! 4112: icmptype == ICMP_SOURCEQUENCH ||
! 4113: icmptype == ICMP_REDIRECT ||
! 4114: icmptype == ICMP_TIMXCEED ||
! 4115: icmptype == ICMP_PARAMPROB)
! 4116: state_icmp++;
! 4117: break;
! 4118: #endif /* INET */
! 4119: #ifdef INET6
! 4120: case IPPROTO_ICMPV6:
! 4121: icmptype = pd->hdr.icmp6->icmp6_type;
! 4122: icmpid = pd->hdr.icmp6->icmp6_id;
! 4123: icmpsum = &pd->hdr.icmp6->icmp6_cksum;
! 4124:
! 4125: if (icmptype == ICMP6_DST_UNREACH ||
! 4126: icmptype == ICMP6_PACKET_TOO_BIG ||
! 4127: icmptype == ICMP6_TIME_EXCEEDED ||
! 4128: icmptype == ICMP6_PARAM_PROB)
! 4129: state_icmp++;
! 4130: break;
! 4131: #endif /* INET6 */
! 4132: }
! 4133:
! 4134: if (!state_icmp) {
! 4135:
! 4136: /*
! 4137: * ICMP query/reply message not related to a TCP/UDP packet.
! 4138: * Search for an ICMP state.
! 4139: */
! 4140: key.af = pd->af;
! 4141: key.proto = pd->proto;
! 4142: if (direction == PF_IN) {
! 4143: PF_ACPY(&key.ext.addr, pd->src, key.af);
! 4144: PF_ACPY(&key.gwy.addr, pd->dst, key.af);
! 4145: key.ext.port = 0;
! 4146: key.gwy.port = icmpid;
! 4147: } else {
! 4148: PF_ACPY(&key.lan.addr, pd->src, key.af);
! 4149: PF_ACPY(&key.ext.addr, pd->dst, key.af);
! 4150: key.lan.port = icmpid;
! 4151: key.ext.port = 0;
! 4152: }
! 4153:
! 4154: STATE_LOOKUP();
! 4155:
! 4156: (*state)->expire = time_second;
! 4157: (*state)->timeout = PFTM_ICMP_ERROR_REPLY;
! 4158:
! 4159: /* translate source/destination address, if necessary */
! 4160: if (STATE_TRANSLATE((*state)->state_key)) {
! 4161: if (direction == PF_OUT) {
! 4162: switch (pd->af) {
! 4163: #ifdef INET
! 4164: case AF_INET:
! 4165: pf_change_a(&saddr->v4.s_addr,
! 4166: pd->ip_sum,
! 4167: (*state)->state_key->gwy.addr.v4.s_addr, 0);
! 4168: pd->hdr.icmp->icmp_cksum =
! 4169: pf_cksum_fixup(
! 4170: pd->hdr.icmp->icmp_cksum, icmpid,
! 4171: (*state)->state_key->gwy.port, 0);
! 4172: pd->hdr.icmp->icmp_id =
! 4173: (*state)->state_key->gwy.port;
! 4174: m_copyback(m, off, ICMP_MINLEN,
! 4175: pd->hdr.icmp);
! 4176: break;
! 4177: #endif /* INET */
! 4178: #ifdef INET6
! 4179: case AF_INET6:
! 4180: pf_change_a6(saddr,
! 4181: &pd->hdr.icmp6->icmp6_cksum,
! 4182: &(*state)->state_key->gwy.addr, 0);
! 4183: m_copyback(m, off,
! 4184: sizeof(struct icmp6_hdr),
! 4185: pd->hdr.icmp6);
! 4186: break;
! 4187: #endif /* INET6 */
! 4188: }
! 4189: } else {
! 4190: switch (pd->af) {
! 4191: #ifdef INET
! 4192: case AF_INET:
! 4193: pf_change_a(&daddr->v4.s_addr,
! 4194: pd->ip_sum,
! 4195: (*state)->state_key->lan.addr.v4.s_addr, 0);
! 4196: pd->hdr.icmp->icmp_cksum =
! 4197: pf_cksum_fixup(
! 4198: pd->hdr.icmp->icmp_cksum, icmpid,
! 4199: (*state)->state_key->lan.port, 0);
! 4200: pd->hdr.icmp->icmp_id =
! 4201: (*state)->state_key->lan.port;
! 4202: m_copyback(m, off, ICMP_MINLEN,
! 4203: pd->hdr.icmp);
! 4204: break;
! 4205: #endif /* INET */
! 4206: #ifdef INET6
! 4207: case AF_INET6:
! 4208: pf_change_a6(daddr,
! 4209: &pd->hdr.icmp6->icmp6_cksum,
! 4210: &(*state)->state_key->lan.addr, 0);
! 4211: m_copyback(m, off,
! 4212: sizeof(struct icmp6_hdr),
! 4213: pd->hdr.icmp6);
! 4214: break;
! 4215: #endif /* INET6 */
! 4216: }
! 4217: }
! 4218: }
! 4219:
! 4220: return (PF_PASS);
! 4221:
! 4222: } else {
! 4223: /*
! 4224: * ICMP error message in response to a TCP/UDP packet.
! 4225: * Extract the inner TCP/UDP header and search for that state.
! 4226: */
! 4227:
! 4228: struct pf_pdesc pd2;
! 4229: #ifdef INET
! 4230: struct ip h2;
! 4231: #endif /* INET */
! 4232: #ifdef INET6
! 4233: struct ip6_hdr h2_6;
! 4234: int terminal = 0;
! 4235: #endif /* INET6 */
! 4236: int ipoff2;
! 4237: int off2;
! 4238:
! 4239: pd2.af = pd->af;
! 4240: switch (pd->af) {
! 4241: #ifdef INET
! 4242: case AF_INET:
! 4243: /* offset of h2 in mbuf chain */
! 4244: ipoff2 = off + ICMP_MINLEN;
! 4245:
! 4246: if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
! 4247: NULL, reason, pd2.af)) {
! 4248: DPFPRINTF(PF_DEBUG_MISC,
! 4249: ("pf: ICMP error message too short "
! 4250: "(ip)\n"));
! 4251: return (PF_DROP);
! 4252: }
! 4253: /*
! 4254: * ICMP error messages don't refer to non-first
! 4255: * fragments
! 4256: */
! 4257: if (h2.ip_off & htons(IP_OFFMASK)) {
! 4258: REASON_SET(reason, PFRES_FRAG);
! 4259: return (PF_DROP);
! 4260: }
! 4261:
! 4262: /* offset of protocol header that follows h2 */
! 4263: off2 = ipoff2 + (h2.ip_hl << 2);
! 4264:
! 4265: pd2.proto = h2.ip_p;
! 4266: pd2.src = (struct pf_addr *)&h2.ip_src;
! 4267: pd2.dst = (struct pf_addr *)&h2.ip_dst;
! 4268: pd2.ip_sum = &h2.ip_sum;
! 4269: break;
! 4270: #endif /* INET */
! 4271: #ifdef INET6
! 4272: case AF_INET6:
! 4273: ipoff2 = off + sizeof(struct icmp6_hdr);
! 4274:
! 4275: if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
! 4276: NULL, reason, pd2.af)) {
! 4277: DPFPRINTF(PF_DEBUG_MISC,
! 4278: ("pf: ICMP error message too short "
! 4279: "(ip6)\n"));
! 4280: return (PF_DROP);
! 4281: }
! 4282: pd2.proto = h2_6.ip6_nxt;
! 4283: pd2.src = (struct pf_addr *)&h2_6.ip6_src;
! 4284: pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
! 4285: pd2.ip_sum = NULL;
! 4286: off2 = ipoff2 + sizeof(h2_6);
! 4287: do {
! 4288: switch (pd2.proto) {
! 4289: case IPPROTO_FRAGMENT:
! 4290: /*
! 4291: * ICMPv6 error messages for
! 4292: * non-first fragments
! 4293: */
! 4294: REASON_SET(reason, PFRES_FRAG);
! 4295: return (PF_DROP);
! 4296: case IPPROTO_AH:
! 4297: case IPPROTO_HOPOPTS:
! 4298: case IPPROTO_ROUTING:
! 4299: case IPPROTO_DSTOPTS: {
! 4300: /* get next header and header length */
! 4301: struct ip6_ext opt6;
! 4302:
! 4303: if (!pf_pull_hdr(m, off2, &opt6,
! 4304: sizeof(opt6), NULL, reason,
! 4305: pd2.af)) {
! 4306: DPFPRINTF(PF_DEBUG_MISC,
! 4307: ("pf: ICMPv6 short opt\n"));
! 4308: return (PF_DROP);
! 4309: }
! 4310: if (pd2.proto == IPPROTO_AH)
! 4311: off2 += (opt6.ip6e_len + 2) * 4;
! 4312: else
! 4313: off2 += (opt6.ip6e_len + 1) * 8;
! 4314: pd2.proto = opt6.ip6e_nxt;
! 4315: /* goto the next header */
! 4316: break;
! 4317: }
! 4318: default:
! 4319: terminal++;
! 4320: break;
! 4321: }
! 4322: } while (!terminal);
! 4323: break;
! 4324: #endif /* INET6 */
! 4325: }
! 4326:
! 4327: switch (pd2.proto) {
! 4328: case IPPROTO_TCP: {
! 4329: struct tcphdr th;
! 4330: u_int32_t seq;
! 4331: struct pf_state_peer *src, *dst;
! 4332: u_int8_t dws;
! 4333: int copyback = 0;
! 4334:
! 4335: /*
! 4336: * Only the first 8 bytes of the TCP header can be
! 4337: * expected. Don't access any TCP header fields after
! 4338: * th_seq, an ackskew test is not possible.
! 4339: */
! 4340: if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
! 4341: pd2.af)) {
! 4342: DPFPRINTF(PF_DEBUG_MISC,
! 4343: ("pf: ICMP error message too short "
! 4344: "(tcp)\n"));
! 4345: return (PF_DROP);
! 4346: }
! 4347:
! 4348: key.af = pd2.af;
! 4349: key.proto = IPPROTO_TCP;
! 4350: if (direction == PF_IN) {
! 4351: PF_ACPY(&key.ext.addr, pd2.dst, key.af);
! 4352: PF_ACPY(&key.gwy.addr, pd2.src, key.af);
! 4353: key.ext.port = th.th_dport;
! 4354: key.gwy.port = th.th_sport;
! 4355: } else {
! 4356: PF_ACPY(&key.lan.addr, pd2.dst, key.af);
! 4357: PF_ACPY(&key.ext.addr, pd2.src, key.af);
! 4358: key.lan.port = th.th_dport;
! 4359: key.ext.port = th.th_sport;
! 4360: }
! 4361:
! 4362: STATE_LOOKUP();
! 4363:
! 4364: if (direction == (*state)->state_key->direction) {
! 4365: src = &(*state)->dst;
! 4366: dst = &(*state)->src;
! 4367: } else {
! 4368: src = &(*state)->src;
! 4369: dst = &(*state)->dst;
! 4370: }
! 4371:
! 4372: if (src->wscale && dst->wscale)
! 4373: dws = dst->wscale & PF_WSCALE_MASK;
! 4374: else
! 4375: dws = 0;
! 4376:
! 4377: /* Demodulate sequence number */
! 4378: seq = ntohl(th.th_seq) - src->seqdiff;
! 4379: if (src->seqdiff) {
! 4380: pf_change_a(&th.th_seq, icmpsum,
! 4381: htonl(seq), 0);
! 4382: copyback = 1;
! 4383: }
! 4384:
! 4385: if (!SEQ_GEQ(src->seqhi, seq) ||
! 4386: !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
! 4387: if (pf_status.debug >= PF_DEBUG_MISC) {
! 4388: printf("pf: BAD ICMP %d:%d ",
! 4389: icmptype, pd->hdr.icmp->icmp_code);
! 4390: pf_print_host(pd->src, 0, pd->af);
! 4391: printf(" -> ");
! 4392: pf_print_host(pd->dst, 0, pd->af);
! 4393: printf(" state: ");
! 4394: pf_print_state(*state);
! 4395: printf(" seq=%u\n", seq);
! 4396: }
! 4397: REASON_SET(reason, PFRES_BADSTATE);
! 4398: return (PF_DROP);
! 4399: }
! 4400:
! 4401: if (STATE_TRANSLATE((*state)->state_key)) {
! 4402: if (direction == PF_IN) {
! 4403: pf_change_icmp(pd2.src, &th.th_sport,
! 4404: daddr, &(*state)->state_key->lan.addr,
! 4405: (*state)->state_key->lan.port, NULL,
! 4406: pd2.ip_sum, icmpsum,
! 4407: pd->ip_sum, 0, pd2.af);
! 4408: } else {
! 4409: pf_change_icmp(pd2.dst, &th.th_dport,
! 4410: saddr, &(*state)->state_key->gwy.addr,
! 4411: (*state)->state_key->gwy.port, NULL,
! 4412: pd2.ip_sum, icmpsum,
! 4413: pd->ip_sum, 0, pd2.af);
! 4414: }
! 4415: copyback = 1;
! 4416: }
! 4417:
! 4418: if (copyback) {
! 4419: switch (pd2.af) {
! 4420: #ifdef INET
! 4421: case AF_INET:
! 4422: m_copyback(m, off, ICMP_MINLEN,
! 4423: pd->hdr.icmp);
! 4424: m_copyback(m, ipoff2, sizeof(h2),
! 4425: &h2);
! 4426: break;
! 4427: #endif /* INET */
! 4428: #ifdef INET6
! 4429: case AF_INET6:
! 4430: m_copyback(m, off,
! 4431: sizeof(struct icmp6_hdr),
! 4432: pd->hdr.icmp6);
! 4433: m_copyback(m, ipoff2, sizeof(h2_6),
! 4434: &h2_6);
! 4435: break;
! 4436: #endif /* INET6 */
! 4437: }
! 4438: m_copyback(m, off2, 8, &th);
! 4439: }
! 4440:
! 4441: return (PF_PASS);
! 4442: break;
! 4443: }
! 4444: case IPPROTO_UDP: {
! 4445: struct udphdr uh;
! 4446:
! 4447: if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
! 4448: NULL, reason, pd2.af)) {
! 4449: DPFPRINTF(PF_DEBUG_MISC,
! 4450: ("pf: ICMP error message too short "
! 4451: "(udp)\n"));
! 4452: return (PF_DROP);
! 4453: }
! 4454:
! 4455: key.af = pd2.af;
! 4456: key.proto = IPPROTO_UDP;
! 4457: if (direction == PF_IN) {
! 4458: PF_ACPY(&key.ext.addr, pd2.dst, key.af);
! 4459: PF_ACPY(&key.gwy.addr, pd2.src, key.af);
! 4460: key.ext.port = uh.uh_dport;
! 4461: key.gwy.port = uh.uh_sport;
! 4462: } else {
! 4463: PF_ACPY(&key.lan.addr, pd2.dst, key.af);
! 4464: PF_ACPY(&key.ext.addr, pd2.src, key.af);
! 4465: key.lan.port = uh.uh_dport;
! 4466: key.ext.port = uh.uh_sport;
! 4467: }
! 4468:
! 4469: STATE_LOOKUP();
! 4470:
! 4471: if (STATE_TRANSLATE((*state)->state_key)) {
! 4472: if (direction == PF_IN) {
! 4473: pf_change_icmp(pd2.src, &uh.uh_sport,
! 4474: daddr,
! 4475: &(*state)->state_key->lan.addr,
! 4476: (*state)->state_key->lan.port,
! 4477: &uh.uh_sum,
! 4478: pd2.ip_sum, icmpsum,
! 4479: pd->ip_sum, 1, pd2.af);
! 4480: } else {
! 4481: pf_change_icmp(pd2.dst, &uh.uh_dport,
! 4482: saddr,
! 4483: &(*state)->state_key->gwy.addr,
! 4484: (*state)->state_key->gwy.port, &uh.uh_sum,
! 4485: pd2.ip_sum, icmpsum,
! 4486: pd->ip_sum, 1, pd2.af);
! 4487: }
! 4488: switch (pd2.af) {
! 4489: #ifdef INET
! 4490: case AF_INET:
! 4491: m_copyback(m, off, ICMP_MINLEN,
! 4492: pd->hdr.icmp);
! 4493: m_copyback(m, ipoff2, sizeof(h2), &h2);
! 4494: break;
! 4495: #endif /* INET */
! 4496: #ifdef INET6
! 4497: case AF_INET6:
! 4498: m_copyback(m, off,
! 4499: sizeof(struct icmp6_hdr),
! 4500: pd->hdr.icmp6);
! 4501: m_copyback(m, ipoff2, sizeof(h2_6),
! 4502: &h2_6);
! 4503: break;
! 4504: #endif /* INET6 */
! 4505: }
! 4506: m_copyback(m, off2, sizeof(uh), &uh);
! 4507: }
! 4508:
! 4509: return (PF_PASS);
! 4510: break;
! 4511: }
! 4512: #ifdef INET
! 4513: case IPPROTO_ICMP: {
! 4514: struct icmp iih;
! 4515:
! 4516: if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
! 4517: NULL, reason, pd2.af)) {
! 4518: DPFPRINTF(PF_DEBUG_MISC,
! 4519: ("pf: ICMP error message too short i"
! 4520: "(icmp)\n"));
! 4521: return (PF_DROP);
! 4522: }
! 4523:
! 4524: key.af = pd2.af;
! 4525: key.proto = IPPROTO_ICMP;
! 4526: if (direction == PF_IN) {
! 4527: PF_ACPY(&key.ext.addr, pd2.dst, key.af);
! 4528: PF_ACPY(&key.gwy.addr, pd2.src, key.af);
! 4529: key.ext.port = 0;
! 4530: key.gwy.port = iih.icmp_id;
! 4531: } else {
! 4532: PF_ACPY(&key.lan.addr, pd2.dst, key.af);
! 4533: PF_ACPY(&key.ext.addr, pd2.src, key.af);
! 4534: key.lan.port = iih.icmp_id;
! 4535: key.ext.port = 0;
! 4536: }
! 4537:
! 4538: STATE_LOOKUP();
! 4539:
! 4540: if (STATE_TRANSLATE((*state)->state_key)) {
! 4541: if (direction == PF_IN) {
! 4542: pf_change_icmp(pd2.src, &iih.icmp_id,
! 4543: daddr,
! 4544: &(*state)->state_key->lan.addr,
! 4545: (*state)->state_key->lan.port, NULL,
! 4546: pd2.ip_sum, icmpsum,
! 4547: pd->ip_sum, 0, AF_INET);
! 4548: } else {
! 4549: pf_change_icmp(pd2.dst, &iih.icmp_id,
! 4550: saddr,
! 4551: &(*state)->state_key->gwy.addr,
! 4552: (*state)->state_key->gwy.port, NULL,
! 4553: pd2.ip_sum, icmpsum,
! 4554: pd->ip_sum, 0, AF_INET);
! 4555: }
! 4556: m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
! 4557: m_copyback(m, ipoff2, sizeof(h2), &h2);
! 4558: m_copyback(m, off2, ICMP_MINLEN, &iih);
! 4559: }
! 4560:
! 4561: return (PF_PASS);
! 4562: break;
! 4563: }
! 4564: #endif /* INET */
! 4565: #ifdef INET6
! 4566: case IPPROTO_ICMPV6: {
! 4567: struct icmp6_hdr iih;
! 4568:
! 4569: if (!pf_pull_hdr(m, off2, &iih,
! 4570: sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
! 4571: DPFPRINTF(PF_DEBUG_MISC,
! 4572: ("pf: ICMP error message too short "
! 4573: "(icmp6)\n"));
! 4574: return (PF_DROP);
! 4575: }
! 4576:
! 4577: key.af = pd2.af;
! 4578: key.proto = IPPROTO_ICMPV6;
! 4579: if (direction == PF_IN) {
! 4580: PF_ACPY(&key.ext.addr, pd2.dst, key.af);
! 4581: PF_ACPY(&key.gwy.addr, pd2.src, key.af);
! 4582: key.ext.port = 0;
! 4583: key.gwy.port = iih.icmp6_id;
! 4584: } else {
! 4585: PF_ACPY(&key.lan.addr, pd2.dst, key.af);
! 4586: PF_ACPY(&key.ext.addr, pd2.src, key.af);
! 4587: key.lan.port = iih.icmp6_id;
! 4588: key.ext.port = 0;
! 4589: }
! 4590:
! 4591: STATE_LOOKUP();
! 4592:
! 4593: if (STATE_TRANSLATE((*state)->state_key)) {
! 4594: if (direction == PF_IN) {
! 4595: pf_change_icmp(pd2.src, &iih.icmp6_id,
! 4596: daddr,
! 4597: &(*state)->state_key->lan.addr,
! 4598: (*state)->state_key->lan.port, NULL,
! 4599: pd2.ip_sum, icmpsum,
! 4600: pd->ip_sum, 0, AF_INET6);
! 4601: } else {
! 4602: pf_change_icmp(pd2.dst, &iih.icmp6_id,
! 4603: saddr, &(*state)->state_key->gwy.addr,
! 4604: (*state)->state_key->gwy.port, NULL,
! 4605: pd2.ip_sum, icmpsum,
! 4606: pd->ip_sum, 0, AF_INET6);
! 4607: }
! 4608: m_copyback(m, off, sizeof(struct icmp6_hdr),
! 4609: pd->hdr.icmp6);
! 4610: m_copyback(m, ipoff2, sizeof(h2_6), &h2_6);
! 4611: m_copyback(m, off2, sizeof(struct icmp6_hdr),
! 4612: &iih);
! 4613: }
! 4614:
! 4615: return (PF_PASS);
! 4616: break;
! 4617: }
! 4618: #endif /* INET6 */
! 4619: default: {
! 4620: key.af = pd2.af;
! 4621: key.proto = pd2.proto;
! 4622: if (direction == PF_IN) {
! 4623: PF_ACPY(&key.ext.addr, pd2.dst, key.af);
! 4624: PF_ACPY(&key.gwy.addr, pd2.src, key.af);
! 4625: key.ext.port = 0;
! 4626: key.gwy.port = 0;
! 4627: } else {
! 4628: PF_ACPY(&key.lan.addr, pd2.dst, key.af);
! 4629: PF_ACPY(&key.ext.addr, pd2.src, key.af);
! 4630: key.lan.port = 0;
! 4631: key.ext.port = 0;
! 4632: }
! 4633:
! 4634: STATE_LOOKUP();
! 4635:
! 4636: if (STATE_TRANSLATE((*state)->state_key)) {
! 4637: if (direction == PF_IN) {
! 4638: pf_change_icmp(pd2.src, NULL,
! 4639: daddr,
! 4640: &(*state)->state_key->lan.addr,
! 4641: 0, NULL,
! 4642: pd2.ip_sum, icmpsum,
! 4643: pd->ip_sum, 0, pd2.af);
! 4644: } else {
! 4645: pf_change_icmp(pd2.dst, NULL,
! 4646: saddr,
! 4647: &(*state)->state_key->gwy.addr,
! 4648: 0, NULL,
! 4649: pd2.ip_sum, icmpsum,
! 4650: pd->ip_sum, 0, pd2.af);
! 4651: }
! 4652: switch (pd2.af) {
! 4653: #ifdef INET
! 4654: case AF_INET:
! 4655: m_copyback(m, off, ICMP_MINLEN,
! 4656: pd->hdr.icmp);
! 4657: m_copyback(m, ipoff2, sizeof(h2), &h2);
! 4658: break;
! 4659: #endif /* INET */
! 4660: #ifdef INET6
! 4661: case AF_INET6:
! 4662: m_copyback(m, off,
! 4663: sizeof(struct icmp6_hdr),
! 4664: pd->hdr.icmp6);
! 4665: m_copyback(m, ipoff2, sizeof(h2_6),
! 4666: &h2_6);
! 4667: break;
! 4668: #endif /* INET6 */
! 4669: }
! 4670: }
! 4671:
! 4672: return (PF_PASS);
! 4673: break;
! 4674: }
! 4675: }
! 4676: }
! 4677: }
! 4678:
! 4679: int
! 4680: pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
! 4681: struct pf_pdesc *pd)
! 4682: {
! 4683: struct pf_state_peer *src, *dst;
! 4684: struct pf_state_key_cmp key;
! 4685:
! 4686: key.af = pd->af;
! 4687: key.proto = pd->proto;
! 4688: if (direction == PF_IN) {
! 4689: PF_ACPY(&key.ext.addr, pd->src, key.af);
! 4690: PF_ACPY(&key.gwy.addr, pd->dst, key.af);
! 4691: key.ext.port = 0;
! 4692: key.gwy.port = 0;
! 4693: } else {
! 4694: PF_ACPY(&key.lan.addr, pd->src, key.af);
! 4695: PF_ACPY(&key.ext.addr, pd->dst, key.af);
! 4696: key.lan.port = 0;
! 4697: key.ext.port = 0;
! 4698: }
! 4699:
! 4700: STATE_LOOKUP();
! 4701:
! 4702: if (direction == (*state)->state_key->direction) {
! 4703: src = &(*state)->src;
! 4704: dst = &(*state)->dst;
! 4705: } else {
! 4706: src = &(*state)->dst;
! 4707: dst = &(*state)->src;
! 4708: }
! 4709:
! 4710: /* update states */
! 4711: if (src->state < PFOTHERS_SINGLE)
! 4712: src->state = PFOTHERS_SINGLE;
! 4713: if (dst->state == PFOTHERS_SINGLE)
! 4714: dst->state = PFOTHERS_MULTIPLE;
! 4715:
! 4716: /* update expire time */
! 4717: (*state)->expire = time_second;
! 4718: if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
! 4719: (*state)->timeout = PFTM_OTHER_MULTIPLE;
! 4720: else
! 4721: (*state)->timeout = PFTM_OTHER_SINGLE;
! 4722:
! 4723: /* translate source/destination address, if necessary */
! 4724: if (STATE_TRANSLATE((*state)->state_key)) {
! 4725: if (direction == PF_OUT)
! 4726: switch (pd->af) {
! 4727: #ifdef INET
! 4728: case AF_INET:
! 4729: pf_change_a(&pd->src->v4.s_addr,
! 4730: pd->ip_sum,
! 4731: (*state)->state_key->gwy.addr.v4.s_addr,
! 4732: 0);
! 4733: break;
! 4734: #endif /* INET */
! 4735: #ifdef INET6
! 4736: case AF_INET6:
! 4737: PF_ACPY(pd->src,
! 4738: &(*state)->state_key->gwy.addr, pd->af);
! 4739: break;
! 4740: #endif /* INET6 */
! 4741: }
! 4742: else
! 4743: switch (pd->af) {
! 4744: #ifdef INET
! 4745: case AF_INET:
! 4746: pf_change_a(&pd->dst->v4.s_addr,
! 4747: pd->ip_sum,
! 4748: (*state)->state_key->lan.addr.v4.s_addr,
! 4749: 0);
! 4750: break;
! 4751: #endif /* INET */
! 4752: #ifdef INET6
! 4753: case AF_INET6:
! 4754: PF_ACPY(pd->dst,
! 4755: &(*state)->state_key->lan.addr, pd->af);
! 4756: break;
! 4757: #endif /* INET6 */
! 4758: }
! 4759: }
! 4760:
! 4761: return (PF_PASS);
! 4762: }
! 4763:
! 4764: /*
! 4765: * ipoff and off are measured from the start of the mbuf chain.
! 4766: * h must be at "ipoff" on the mbuf chain.
! 4767: */
! 4768: void *
! 4769: pf_pull_hdr(struct mbuf *m, int off, void *p, int len,
! 4770: u_short *actionp, u_short *reasonp, sa_family_t af)
! 4771: {
! 4772: switch (af) {
! 4773: #ifdef INET
! 4774: case AF_INET: {
! 4775: struct ip *h = mtod(m, struct ip *);
! 4776: u_int16_t fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
! 4777:
! 4778: if (fragoff) {
! 4779: if (fragoff >= len)
! 4780: ACTION_SET(actionp, PF_PASS);
! 4781: else {
! 4782: ACTION_SET(actionp, PF_DROP);
! 4783: REASON_SET(reasonp, PFRES_FRAG);
! 4784: }
! 4785: return (NULL);
! 4786: }
! 4787: if (m->m_pkthdr.len < off + len ||
! 4788: ntohs(h->ip_len) < off + len) {
! 4789: ACTION_SET(actionp, PF_DROP);
! 4790: REASON_SET(reasonp, PFRES_SHORT);
! 4791: return (NULL);
! 4792: }
! 4793: break;
! 4794: }
! 4795: #endif /* INET */
! 4796: #ifdef INET6
! 4797: case AF_INET6: {
! 4798: struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
! 4799:
! 4800: if (m->m_pkthdr.len < off + len ||
! 4801: (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
! 4802: (unsigned)(off + len)) {
! 4803: ACTION_SET(actionp, PF_DROP);
! 4804: REASON_SET(reasonp, PFRES_SHORT);
! 4805: return (NULL);
! 4806: }
! 4807: break;
! 4808: }
! 4809: #endif /* INET6 */
! 4810: }
! 4811: m_copydata(m, off, len, p);
! 4812: return (p);
! 4813: }
! 4814:
! 4815: int
! 4816: pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
! 4817: {
! 4818: struct sockaddr_in *dst;
! 4819: int ret = 1;
! 4820: int check_mpath;
! 4821: extern int ipmultipath;
! 4822: #ifdef INET6
! 4823: extern int ip6_multipath;
! 4824: struct sockaddr_in6 *dst6;
! 4825: struct route_in6 ro;
! 4826: #else
! 4827: struct route ro;
! 4828: #endif
! 4829: struct radix_node *rn;
! 4830: struct rtentry *rt;
! 4831: struct ifnet *ifp;
! 4832:
! 4833: check_mpath = 0;
! 4834: bzero(&ro, sizeof(ro));
! 4835: switch (af) {
! 4836: case AF_INET:
! 4837: dst = satosin(&ro.ro_dst);
! 4838: dst->sin_family = AF_INET;
! 4839: dst->sin_len = sizeof(*dst);
! 4840: dst->sin_addr = addr->v4;
! 4841: if (ipmultipath)
! 4842: check_mpath = 1;
! 4843: break;
! 4844: #ifdef INET6
! 4845: case AF_INET6:
! 4846: dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
! 4847: dst6->sin6_family = AF_INET6;
! 4848: dst6->sin6_len = sizeof(*dst6);
! 4849: dst6->sin6_addr = addr->v6;
! 4850: if (ip6_multipath)
! 4851: check_mpath = 1;
! 4852: break;
! 4853: #endif /* INET6 */
! 4854: default:
! 4855: return (0);
! 4856: }
! 4857:
! 4858: /* Skip checks for ipsec interfaces */
! 4859: if (kif != NULL && kif->pfik_ifp->if_type == IFT_ENC)
! 4860: goto out;
! 4861:
! 4862: rtalloc_noclone((struct route *)&ro, NO_CLONING);
! 4863:
! 4864: if (ro.ro_rt != NULL) {
! 4865: /* No interface given, this is a no-route check */
! 4866: if (kif == NULL)
! 4867: goto out;
! 4868:
! 4869: if (kif->pfik_ifp == NULL) {
! 4870: ret = 0;
! 4871: goto out;
! 4872: }
! 4873:
! 4874: /* Perform uRPF check if passed input interface */
! 4875: ret = 0;
! 4876: rn = (struct radix_node *)ro.ro_rt;
! 4877: do {
! 4878: rt = (struct rtentry *)rn;
! 4879: if (rt->rt_ifp->if_type == IFT_CARP)
! 4880: ifp = rt->rt_ifp->if_carpdev;
! 4881: else
! 4882: ifp = rt->rt_ifp;
! 4883:
! 4884: if (kif->pfik_ifp == ifp)
! 4885: ret = 1;
! 4886: rn = rn_mpath_next(rn);
! 4887: } while (check_mpath == 1 && rn != NULL && ret == 0);
! 4888: } else
! 4889: ret = 0;
! 4890: out:
! 4891: if (ro.ro_rt != NULL)
! 4892: RTFREE(ro.ro_rt);
! 4893: return (ret);
! 4894: }
! 4895:
! 4896: int
! 4897: pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
! 4898: {
! 4899: struct sockaddr_in *dst;
! 4900: #ifdef INET6
! 4901: struct sockaddr_in6 *dst6;
! 4902: struct route_in6 ro;
! 4903: #else
! 4904: struct route ro;
! 4905: #endif
! 4906: int ret = 0;
! 4907:
! 4908: bzero(&ro, sizeof(ro));
! 4909: switch (af) {
! 4910: case AF_INET:
! 4911: dst = satosin(&ro.ro_dst);
! 4912: dst->sin_family = AF_INET;
! 4913: dst->sin_len = sizeof(*dst);
! 4914: dst->sin_addr = addr->v4;
! 4915: break;
! 4916: #ifdef INET6
! 4917: case AF_INET6:
! 4918: dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
! 4919: dst6->sin6_family = AF_INET6;
! 4920: dst6->sin6_len = sizeof(*dst6);
! 4921: dst6->sin6_addr = addr->v6;
! 4922: break;
! 4923: #endif /* INET6 */
! 4924: default:
! 4925: return (0);
! 4926: }
! 4927:
! 4928: rtalloc_noclone((struct route *)&ro, NO_CLONING);
! 4929:
! 4930: if (ro.ro_rt != NULL) {
! 4931: if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
! 4932: ret = 1;
! 4933: RTFREE(ro.ro_rt);
! 4934: }
! 4935:
! 4936: return (ret);
! 4937: }
! 4938:
! 4939: #ifdef INET
! 4940: void
! 4941: pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
! 4942: struct pf_state *s, struct pf_pdesc *pd)
! 4943: {
! 4944: struct mbuf *m0, *m1;
! 4945: struct route iproute;
! 4946: struct route *ro = NULL;
! 4947: struct sockaddr_in *dst;
! 4948: struct ip *ip;
! 4949: struct ifnet *ifp = NULL;
! 4950: struct pf_addr naddr;
! 4951: struct pf_src_node *sn = NULL;
! 4952: int error = 0;
! 4953: #ifdef IPSEC
! 4954: struct m_tag *mtag;
! 4955: #endif /* IPSEC */
! 4956:
! 4957: if (m == NULL || *m == NULL || r == NULL ||
! 4958: (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
! 4959: panic("pf_route: invalid parameters");
! 4960:
! 4961: if ((*m)->m_pkthdr.pf.routed++ > 3) {
! 4962: m0 = *m;
! 4963: *m = NULL;
! 4964: goto bad;
! 4965: }
! 4966:
! 4967: if (r->rt == PF_DUPTO) {
! 4968: if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
! 4969: return;
! 4970: } else {
! 4971: if ((r->rt == PF_REPLYTO) == (r->direction == dir))
! 4972: return;
! 4973: m0 = *m;
! 4974: }
! 4975:
! 4976: if (m0->m_len < sizeof(struct ip)) {
! 4977: DPFPRINTF(PF_DEBUG_URGENT,
! 4978: ("pf_route: m0->m_len < sizeof(struct ip)\n"));
! 4979: goto bad;
! 4980: }
! 4981:
! 4982: ip = mtod(m0, struct ip *);
! 4983:
! 4984: ro = &iproute;
! 4985: bzero((caddr_t)ro, sizeof(*ro));
! 4986: dst = satosin(&ro->ro_dst);
! 4987: dst->sin_family = AF_INET;
! 4988: dst->sin_len = sizeof(*dst);
! 4989: dst->sin_addr = ip->ip_dst;
! 4990:
! 4991: if (r->rt == PF_FASTROUTE) {
! 4992: rtalloc(ro);
! 4993: if (ro->ro_rt == 0) {
! 4994: ipstat.ips_noroute++;
! 4995: goto bad;
! 4996: }
! 4997:
! 4998: ifp = ro->ro_rt->rt_ifp;
! 4999: ro->ro_rt->rt_use++;
! 5000:
! 5001: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
! 5002: dst = satosin(ro->ro_rt->rt_gateway);
! 5003: } else {
! 5004: if (TAILQ_EMPTY(&r->rpool.list)) {
! 5005: DPFPRINTF(PF_DEBUG_URGENT,
! 5006: ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
! 5007: goto bad;
! 5008: }
! 5009: if (s == NULL) {
! 5010: pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
! 5011: &naddr, NULL, &sn);
! 5012: if (!PF_AZERO(&naddr, AF_INET))
! 5013: dst->sin_addr.s_addr = naddr.v4.s_addr;
! 5014: ifp = r->rpool.cur->kif ?
! 5015: r->rpool.cur->kif->pfik_ifp : NULL;
! 5016: } else {
! 5017: if (!PF_AZERO(&s->rt_addr, AF_INET))
! 5018: dst->sin_addr.s_addr =
! 5019: s->rt_addr.v4.s_addr;
! 5020: ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
! 5021: }
! 5022: }
! 5023: if (ifp == NULL)
! 5024: goto bad;
! 5025:
! 5026: if (oifp != ifp) {
! 5027: if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
! 5028: goto bad;
! 5029: else if (m0 == NULL)
! 5030: goto done;
! 5031: if (m0->m_len < sizeof(struct ip)) {
! 5032: DPFPRINTF(PF_DEBUG_URGENT,
! 5033: ("pf_route: m0->m_len < sizeof(struct ip)\n"));
! 5034: goto bad;
! 5035: }
! 5036: ip = mtod(m0, struct ip *);
! 5037: }
! 5038:
! 5039: /* Copied from ip_output. */
! 5040: #ifdef IPSEC
! 5041: /*
! 5042: * If deferred crypto processing is needed, check that the
! 5043: * interface supports it.
! 5044: */
! 5045: if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
! 5046: != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
! 5047: /* Notify IPsec to do its own crypto. */
! 5048: ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
! 5049: goto bad;
! 5050: }
! 5051: #endif /* IPSEC */
! 5052:
! 5053: /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
! 5054: if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
! 5055: if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
! 5056: ifp->if_bridge != NULL) {
! 5057: in_delayed_cksum(m0);
! 5058: m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
! 5059: }
! 5060: } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
! 5061: if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
! 5062: ifp->if_bridge != NULL) {
! 5063: in_delayed_cksum(m0);
! 5064: m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
! 5065: }
! 5066: }
! 5067:
! 5068: if (ntohs(ip->ip_len) <= ifp->if_mtu) {
! 5069: if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
! 5070: ifp->if_bridge == NULL) {
! 5071: m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
! 5072: ipstat.ips_outhwcsum++;
! 5073: } else {
! 5074: ip->ip_sum = 0;
! 5075: ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
! 5076: }
! 5077: /* Update relevant hardware checksum stats for TCP/UDP */
! 5078: if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
! 5079: tcpstat.tcps_outhwcsum++;
! 5080: else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
! 5081: udpstat.udps_outhwcsum++;
! 5082: error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
! 5083: goto done;
! 5084: }
! 5085:
! 5086: /*
! 5087: * Too large for interface; fragment if possible.
! 5088: * Must be able to put at least 8 bytes per fragment.
! 5089: */
! 5090: if (ip->ip_off & htons(IP_DF)) {
! 5091: ipstat.ips_cantfrag++;
! 5092: if (r->rt != PF_DUPTO) {
! 5093: icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
! 5094: ifp->if_mtu);
! 5095: goto done;
! 5096: } else
! 5097: goto bad;
! 5098: }
! 5099:
! 5100: m1 = m0;
! 5101: error = ip_fragment(m0, ifp, ifp->if_mtu);
! 5102: if (error) {
! 5103: m0 = NULL;
! 5104: goto bad;
! 5105: }
! 5106:
! 5107: for (m0 = m1; m0; m0 = m1) {
! 5108: m1 = m0->m_nextpkt;
! 5109: m0->m_nextpkt = 0;
! 5110: if (error == 0)
! 5111: error = (*ifp->if_output)(ifp, m0, sintosa(dst),
! 5112: NULL);
! 5113: else
! 5114: m_freem(m0);
! 5115: }
! 5116:
! 5117: if (error == 0)
! 5118: ipstat.ips_fragmented++;
! 5119:
! 5120: done:
! 5121: if (r->rt != PF_DUPTO)
! 5122: *m = NULL;
! 5123: if (ro == &iproute && ro->ro_rt)
! 5124: RTFREE(ro->ro_rt);
! 5125: return;
! 5126:
! 5127: bad:
! 5128: m_freem(m0);
! 5129: goto done;
! 5130: }
! 5131: #endif /* INET */
! 5132:
! 5133: #ifdef INET6
! 5134: void
! 5135: pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
! 5136: struct pf_state *s, struct pf_pdesc *pd)
! 5137: {
! 5138: struct mbuf *m0;
! 5139: struct route_in6 ip6route;
! 5140: struct route_in6 *ro;
! 5141: struct sockaddr_in6 *dst;
! 5142: struct ip6_hdr *ip6;
! 5143: struct ifnet *ifp = NULL;
! 5144: struct pf_addr naddr;
! 5145: struct pf_src_node *sn = NULL;
! 5146: int error = 0;
! 5147:
! 5148: if (m == NULL || *m == NULL || r == NULL ||
! 5149: (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
! 5150: panic("pf_route6: invalid parameters");
! 5151:
! 5152: if ((*m)->m_pkthdr.pf.routed++ > 3) {
! 5153: m0 = *m;
! 5154: *m = NULL;
! 5155: goto bad;
! 5156: }
! 5157:
! 5158: if (r->rt == PF_DUPTO) {
! 5159: if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
! 5160: return;
! 5161: } else {
! 5162: if ((r->rt == PF_REPLYTO) == (r->direction == dir))
! 5163: return;
! 5164: m0 = *m;
! 5165: }
! 5166:
! 5167: if (m0->m_len < sizeof(struct ip6_hdr)) {
! 5168: DPFPRINTF(PF_DEBUG_URGENT,
! 5169: ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
! 5170: goto bad;
! 5171: }
! 5172: ip6 = mtod(m0, struct ip6_hdr *);
! 5173:
! 5174: ro = &ip6route;
! 5175: bzero((caddr_t)ro, sizeof(*ro));
! 5176: dst = (struct sockaddr_in6 *)&ro->ro_dst;
! 5177: dst->sin6_family = AF_INET6;
! 5178: dst->sin6_len = sizeof(*dst);
! 5179: dst->sin6_addr = ip6->ip6_dst;
! 5180:
! 5181: /* Cheat. XXX why only in the v6 case??? */
! 5182: if (r->rt == PF_FASTROUTE) {
! 5183: m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
! 5184: ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
! 5185: return;
! 5186: }
! 5187:
! 5188: if (TAILQ_EMPTY(&r->rpool.list)) {
! 5189: DPFPRINTF(PF_DEBUG_URGENT,
! 5190: ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
! 5191: goto bad;
! 5192: }
! 5193: if (s == NULL) {
! 5194: pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
! 5195: &naddr, NULL, &sn);
! 5196: if (!PF_AZERO(&naddr, AF_INET6))
! 5197: PF_ACPY((struct pf_addr *)&dst->sin6_addr,
! 5198: &naddr, AF_INET6);
! 5199: ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
! 5200: } else {
! 5201: if (!PF_AZERO(&s->rt_addr, AF_INET6))
! 5202: PF_ACPY((struct pf_addr *)&dst->sin6_addr,
! 5203: &s->rt_addr, AF_INET6);
! 5204: ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
! 5205: }
! 5206: if (ifp == NULL)
! 5207: goto bad;
! 5208:
! 5209: if (oifp != ifp) {
! 5210: if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
! 5211: goto bad;
! 5212: else if (m0 == NULL)
! 5213: goto done;
! 5214: if (m0->m_len < sizeof(struct ip6_hdr)) {
! 5215: DPFPRINTF(PF_DEBUG_URGENT,
! 5216: ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
! 5217: goto bad;
! 5218: }
! 5219: ip6 = mtod(m0, struct ip6_hdr *);
! 5220: }
! 5221:
! 5222: /*
! 5223: * If the packet is too large for the outgoing interface,
! 5224: * send back an icmp6 error.
! 5225: */
! 5226: if (IN6_IS_SCOPE_EMBED(&dst->sin6_addr))
! 5227: dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
! 5228: if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
! 5229: error = nd6_output(ifp, ifp, m0, dst, NULL);
! 5230: } else {
! 5231: in6_ifstat_inc(ifp, ifs6_in_toobig);
! 5232: if (r->rt != PF_DUPTO)
! 5233: icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
! 5234: else
! 5235: goto bad;
! 5236: }
! 5237:
! 5238: done:
! 5239: if (r->rt != PF_DUPTO)
! 5240: *m = NULL;
! 5241: return;
! 5242:
! 5243: bad:
! 5244: m_freem(m0);
! 5245: goto done;
! 5246: }
! 5247: #endif /* INET6 */
! 5248:
! 5249:
! 5250: /*
! 5251: * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
! 5252: * off is the offset where the protocol header starts
! 5253: * len is the total length of protocol header plus payload
! 5254: * returns 0 when the checksum is valid, otherwise returns 1.
! 5255: */
! 5256: int
! 5257: pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
! 5258: sa_family_t af)
! 5259: {
! 5260: u_int16_t flag_ok, flag_bad;
! 5261: u_int16_t sum;
! 5262:
! 5263: switch (p) {
! 5264: case IPPROTO_TCP:
! 5265: flag_ok = M_TCP_CSUM_IN_OK;
! 5266: flag_bad = M_TCP_CSUM_IN_BAD;
! 5267: break;
! 5268: case IPPROTO_UDP:
! 5269: flag_ok = M_UDP_CSUM_IN_OK;
! 5270: flag_bad = M_UDP_CSUM_IN_BAD;
! 5271: break;
! 5272: case IPPROTO_ICMP:
! 5273: #ifdef INET6
! 5274: case IPPROTO_ICMPV6:
! 5275: #endif /* INET6 */
! 5276: flag_ok = flag_bad = 0;
! 5277: break;
! 5278: default:
! 5279: return (1);
! 5280: }
! 5281: if (m->m_pkthdr.csum_flags & flag_ok)
! 5282: return (0);
! 5283: if (m->m_pkthdr.csum_flags & flag_bad)
! 5284: return (1);
! 5285: if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
! 5286: return (1);
! 5287: if (m->m_pkthdr.len < off + len)
! 5288: return (1);
! 5289: switch (af) {
! 5290: #ifdef INET
! 5291: case AF_INET:
! 5292: if (p == IPPROTO_ICMP) {
! 5293: if (m->m_len < off)
! 5294: return (1);
! 5295: m->m_data += off;
! 5296: m->m_len -= off;
! 5297: sum = in_cksum(m, len);
! 5298: m->m_data -= off;
! 5299: m->m_len += off;
! 5300: } else {
! 5301: if (m->m_len < sizeof(struct ip))
! 5302: return (1);
! 5303: sum = in4_cksum(m, p, off, len);
! 5304: }
! 5305: break;
! 5306: #endif /* INET */
! 5307: #ifdef INET6
! 5308: case AF_INET6:
! 5309: if (m->m_len < sizeof(struct ip6_hdr))
! 5310: return (1);
! 5311: sum = in6_cksum(m, p, off, len);
! 5312: break;
! 5313: #endif /* INET6 */
! 5314: default:
! 5315: return (1);
! 5316: }
! 5317: if (sum) {
! 5318: m->m_pkthdr.csum_flags |= flag_bad;
! 5319: switch (p) {
! 5320: case IPPROTO_TCP:
! 5321: tcpstat.tcps_rcvbadsum++;
! 5322: break;
! 5323: case IPPROTO_UDP:
! 5324: udpstat.udps_badsum++;
! 5325: break;
! 5326: case IPPROTO_ICMP:
! 5327: icmpstat.icps_checksum++;
! 5328: break;
! 5329: #ifdef INET6
! 5330: case IPPROTO_ICMPV6:
! 5331: icmp6stat.icp6s_checksum++;
! 5332: break;
! 5333: #endif /* INET6 */
! 5334: }
! 5335: return (1);
! 5336: }
! 5337: m->m_pkthdr.csum_flags |= flag_ok;
! 5338: return (0);
! 5339: }
! 5340:
! 5341: #ifdef INET
! 5342: int
! 5343: pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
! 5344: struct ether_header *eh)
! 5345: {
! 5346: struct pfi_kif *kif;
! 5347: u_short action, reason = 0, log = 0;
! 5348: struct mbuf *m = *m0;
! 5349: struct ip *h;
! 5350: struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
! 5351: struct pf_state *s = NULL;
! 5352: struct pf_state_key *sk = NULL;
! 5353: struct pf_ruleset *ruleset = NULL;
! 5354: struct pf_pdesc pd;
! 5355: int off, dirndx, pqid = 0;
! 5356:
! 5357: if (!pf_status.running)
! 5358: return (PF_PASS);
! 5359:
! 5360: memset(&pd, 0, sizeof(pd));
! 5361: if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
! 5362: kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
! 5363: else
! 5364: kif = (struct pfi_kif *)ifp->if_pf_kif;
! 5365:
! 5366: if (kif == NULL) {
! 5367: DPFPRINTF(PF_DEBUG_URGENT,
! 5368: ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
! 5369: return (PF_DROP);
! 5370: }
! 5371: if (kif->pfik_flags & PFI_IFLAG_SKIP)
! 5372: return (PF_PASS);
! 5373:
! 5374: #ifdef DIAGNOSTIC
! 5375: if ((m->m_flags & M_PKTHDR) == 0)
! 5376: panic("non-M_PKTHDR is passed to pf_test");
! 5377: #endif /* DIAGNOSTIC */
! 5378:
! 5379: if (m->m_pkthdr.len < (int)sizeof(*h)) {
! 5380: action = PF_DROP;
! 5381: REASON_SET(&reason, PFRES_SHORT);
! 5382: log = 1;
! 5383: goto done;
! 5384: }
! 5385:
! 5386: if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
! 5387: return (PF_PASS);
! 5388:
! 5389: /* We do IP header normalization and packet reassembly here */
! 5390: if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
! 5391: action = PF_DROP;
! 5392: goto done;
! 5393: }
! 5394: m = *m0; /* pf_normalize messes with m0 */
! 5395: h = mtod(m, struct ip *);
! 5396:
! 5397: off = h->ip_hl << 2;
! 5398: if (off < (int)sizeof(*h)) {
! 5399: action = PF_DROP;
! 5400: REASON_SET(&reason, PFRES_SHORT);
! 5401: log = 1;
! 5402: goto done;
! 5403: }
! 5404:
! 5405: pd.src = (struct pf_addr *)&h->ip_src;
! 5406: pd.dst = (struct pf_addr *)&h->ip_dst;
! 5407: PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
! 5408: pd.ip_sum = &h->ip_sum;
! 5409: pd.proto = h->ip_p;
! 5410: pd.af = AF_INET;
! 5411: pd.tos = h->ip_tos;
! 5412: pd.tot_len = ntohs(h->ip_len);
! 5413: pd.eh = eh;
! 5414:
! 5415: /* handle fragments that didn't get reassembled by normalization */
! 5416: if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
! 5417: action = pf_test_fragment(&r, dir, kif, m, h,
! 5418: &pd, &a, &ruleset);
! 5419: goto done;
! 5420: }
! 5421:
! 5422: switch (h->ip_p) {
! 5423:
! 5424: case IPPROTO_TCP: {
! 5425: struct tcphdr th;
! 5426:
! 5427: pd.hdr.tcp = &th;
! 5428: if (!pf_pull_hdr(m, off, &th, sizeof(th),
! 5429: &action, &reason, AF_INET)) {
! 5430: log = action != PF_PASS;
! 5431: goto done;
! 5432: }
! 5433: pd.p_len = pd.tot_len - off - (th.th_off << 2);
! 5434: if ((th.th_flags & TH_ACK) && pd.p_len == 0)
! 5435: pqid = 1;
! 5436: action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
! 5437: if (action == PF_DROP)
! 5438: goto done;
! 5439: action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
! 5440: &reason);
! 5441: if (action == PF_PASS) {
! 5442: #if NPFSYNC
! 5443: pfsync_update_state(s);
! 5444: #endif /* NPFSYNC */
! 5445: r = s->rule.ptr;
! 5446: a = s->anchor.ptr;
! 5447: log = s->log;
! 5448: } else if (s == NULL)
! 5449: action = pf_test_rule(&r, &s, dir, kif,
! 5450: m, off, h, &pd, &a, &ruleset, &ipintrq);
! 5451: break;
! 5452: }
! 5453:
! 5454: case IPPROTO_UDP: {
! 5455: struct udphdr uh;
! 5456:
! 5457: pd.hdr.udp = &uh;
! 5458: if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
! 5459: &action, &reason, AF_INET)) {
! 5460: log = action != PF_PASS;
! 5461: goto done;
! 5462: }
! 5463: if (uh.uh_dport == 0 ||
! 5464: ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
! 5465: ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
! 5466: action = PF_DROP;
! 5467: REASON_SET(&reason, PFRES_SHORT);
! 5468: goto done;
! 5469: }
! 5470: action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
! 5471: if (action == PF_PASS) {
! 5472: #if NPFSYNC
! 5473: pfsync_update_state(s);
! 5474: #endif /* NPFSYNC */
! 5475: r = s->rule.ptr;
! 5476: a = s->anchor.ptr;
! 5477: log = s->log;
! 5478: } else if (s == NULL)
! 5479: action = pf_test_rule(&r, &s, dir, kif,
! 5480: m, off, h, &pd, &a, &ruleset, &ipintrq);
! 5481: break;
! 5482: }
! 5483:
! 5484: case IPPROTO_ICMP: {
! 5485: struct icmp ih;
! 5486:
! 5487: pd.hdr.icmp = &ih;
! 5488: if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
! 5489: &action, &reason, AF_INET)) {
! 5490: log = action != PF_PASS;
! 5491: goto done;
! 5492: }
! 5493: action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
! 5494: &reason);
! 5495: if (action == PF_PASS) {
! 5496: #if NPFSYNC
! 5497: pfsync_update_state(s);
! 5498: #endif /* NPFSYNC */
! 5499: r = s->rule.ptr;
! 5500: a = s->anchor.ptr;
! 5501: log = s->log;
! 5502: } else if (s == NULL)
! 5503: action = pf_test_rule(&r, &s, dir, kif,
! 5504: m, off, h, &pd, &a, &ruleset, &ipintrq);
! 5505: break;
! 5506: }
! 5507:
! 5508: default:
! 5509: action = pf_test_state_other(&s, dir, kif, &pd);
! 5510: if (action == PF_PASS) {
! 5511: #if NPFSYNC
! 5512: pfsync_update_state(s);
! 5513: #endif /* NPFSYNC */
! 5514: r = s->rule.ptr;
! 5515: a = s->anchor.ptr;
! 5516: log = s->log;
! 5517: } else if (s == NULL)
! 5518: action = pf_test_rule(&r, &s, dir, kif, m, off, h,
! 5519: &pd, &a, &ruleset, &ipintrq);
! 5520: break;
! 5521: }
! 5522:
! 5523: done:
! 5524: if (action == PF_PASS && h->ip_hl > 5 &&
! 5525: !((s && s->allow_opts) || r->allow_opts)) {
! 5526: action = PF_DROP;
! 5527: REASON_SET(&reason, PFRES_IPOPTIONS);
! 5528: log = 1;
! 5529: DPFPRINTF(PF_DEBUG_MISC,
! 5530: ("pf: dropping packet with ip options\n"));
! 5531: }
! 5532:
! 5533: if ((s && s->tag) || r->rtableid)
! 5534: pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
! 5535:
! 5536: #ifdef ALTQ
! 5537: if (action == PF_PASS && r->qid) {
! 5538: if (pqid || (pd.tos & IPTOS_LOWDELAY))
! 5539: m->m_pkthdr.pf.qid = r->pqid;
! 5540: else
! 5541: m->m_pkthdr.pf.qid = r->qid;
! 5542: /* add hints for ecn */
! 5543: m->m_pkthdr.pf.hdr = h;
! 5544: }
! 5545: #endif /* ALTQ */
! 5546:
! 5547: /*
! 5548: * connections redirected to loopback should not match sockets
! 5549: * bound specifically to loopback due to security implications,
! 5550: * see tcp_input() and in_pcblookup_listen().
! 5551: */
! 5552: if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
! 5553: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
! 5554: (s->nat_rule.ptr->action == PF_RDR ||
! 5555: s->nat_rule.ptr->action == PF_BINAT) &&
! 5556: (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
! 5557: m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
! 5558:
! 5559: if (log) {
! 5560: struct pf_rule *lr;
! 5561:
! 5562: if (s != NULL && s->nat_rule.ptr != NULL &&
! 5563: s->nat_rule.ptr->log & PF_LOG_ALL)
! 5564: lr = s->nat_rule.ptr;
! 5565: else
! 5566: lr = r;
! 5567: PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, lr, a, ruleset,
! 5568: &pd);
! 5569: }
! 5570:
! 5571: kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
! 5572: kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
! 5573:
! 5574: if (action == PF_PASS || r->action == PF_DROP) {
! 5575: dirndx = (dir == PF_OUT);
! 5576: r->packets[dirndx]++;
! 5577: r->bytes[dirndx] += pd.tot_len;
! 5578: if (a != NULL) {
! 5579: a->packets[dirndx]++;
! 5580: a->bytes[dirndx] += pd.tot_len;
! 5581: }
! 5582: if (s != NULL) {
! 5583: sk = s->state_key;
! 5584: if (s->nat_rule.ptr != NULL) {
! 5585: s->nat_rule.ptr->packets[dirndx]++;
! 5586: s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
! 5587: }
! 5588: if (s->src_node != NULL) {
! 5589: s->src_node->packets[dirndx]++;
! 5590: s->src_node->bytes[dirndx] += pd.tot_len;
! 5591: }
! 5592: if (s->nat_src_node != NULL) {
! 5593: s->nat_src_node->packets[dirndx]++;
! 5594: s->nat_src_node->bytes[dirndx] += pd.tot_len;
! 5595: }
! 5596: dirndx = (dir == sk->direction) ? 0 : 1;
! 5597: s->packets[dirndx]++;
! 5598: s->bytes[dirndx] += pd.tot_len;
! 5599: }
! 5600: tr = r;
! 5601: nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
! 5602: if (nr != NULL) {
! 5603: struct pf_addr *x;
! 5604: /*
! 5605: * XXX: we need to make sure that the addresses
! 5606: * passed to pfr_update_stats() are the same than
! 5607: * the addresses used during matching (pfr_match)
! 5608: */
! 5609: if (r == &pf_default_rule) {
! 5610: tr = nr;
! 5611: x = (sk == NULL || sk->direction == dir) ?
! 5612: &pd.baddr : &pd.naddr;
! 5613: } else
! 5614: x = (sk == NULL || sk->direction == dir) ?
! 5615: &pd.naddr : &pd.baddr;
! 5616: if (x == &pd.baddr || s == NULL) {
! 5617: /* we need to change the address */
! 5618: if (dir == PF_OUT)
! 5619: pd.src = x;
! 5620: else
! 5621: pd.dst = x;
! 5622: }
! 5623: }
! 5624: if (tr->src.addr.type == PF_ADDR_TABLE)
! 5625: pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
! 5626: sk->direction == dir) ?
! 5627: pd.src : pd.dst, pd.af,
! 5628: pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
! 5629: tr->src.neg);
! 5630: if (tr->dst.addr.type == PF_ADDR_TABLE)
! 5631: pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
! 5632: sk->direction == dir) ? pd.dst : pd.src, pd.af,
! 5633: pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
! 5634: tr->dst.neg);
! 5635: }
! 5636:
! 5637:
! 5638: if (action == PF_SYNPROXY_DROP) {
! 5639: m_freem(*m0);
! 5640: *m0 = NULL;
! 5641: action = PF_PASS;
! 5642: } else if (r->rt)
! 5643: /* pf_route can free the mbuf causing *m0 to become NULL */
! 5644: pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
! 5645:
! 5646: return (action);
! 5647: }
! 5648: #endif /* INET */
! 5649:
! 5650: #ifdef INET6
! 5651: int
! 5652: pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
! 5653: struct ether_header *eh)
! 5654: {
! 5655: struct pfi_kif *kif;
! 5656: u_short action, reason = 0, log = 0;
! 5657: struct mbuf *m = *m0, *n = NULL;
! 5658: struct ip6_hdr *h;
! 5659: struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr;
! 5660: struct pf_state *s = NULL;
! 5661: struct pf_state_key *sk = NULL;
! 5662: struct pf_ruleset *ruleset = NULL;
! 5663: struct pf_pdesc pd;
! 5664: int off, terminal = 0, dirndx, rh_cnt = 0;
! 5665:
! 5666: if (!pf_status.running)
! 5667: return (PF_PASS);
! 5668:
! 5669: memset(&pd, 0, sizeof(pd));
! 5670: if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
! 5671: kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif;
! 5672: else
! 5673: kif = (struct pfi_kif *)ifp->if_pf_kif;
! 5674:
! 5675: if (kif == NULL) {
! 5676: DPFPRINTF(PF_DEBUG_URGENT,
! 5677: ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
! 5678: return (PF_DROP);
! 5679: }
! 5680: if (kif->pfik_flags & PFI_IFLAG_SKIP)
! 5681: return (PF_PASS);
! 5682:
! 5683: #ifdef DIAGNOSTIC
! 5684: if ((m->m_flags & M_PKTHDR) == 0)
! 5685: panic("non-M_PKTHDR is passed to pf_test6");
! 5686: #endif /* DIAGNOSTIC */
! 5687:
! 5688: if (m->m_pkthdr.len < (int)sizeof(*h)) {
! 5689: action = PF_DROP;
! 5690: REASON_SET(&reason, PFRES_SHORT);
! 5691: log = 1;
! 5692: goto done;
! 5693: }
! 5694:
! 5695: if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED)
! 5696: return (PF_PASS);
! 5697:
! 5698: /* We do IP header normalization and packet reassembly here */
! 5699: if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
! 5700: action = PF_DROP;
! 5701: goto done;
! 5702: }
! 5703: m = *m0; /* pf_normalize messes with m0 */
! 5704: h = mtod(m, struct ip6_hdr *);
! 5705:
! 5706: #if 1
! 5707: /*
! 5708: * we do not support jumbogram yet. if we keep going, zero ip6_plen
! 5709: * will do something bad, so drop the packet for now.
! 5710: */
! 5711: if (htons(h->ip6_plen) == 0) {
! 5712: action = PF_DROP;
! 5713: REASON_SET(&reason, PFRES_NORM); /*XXX*/
! 5714: goto done;
! 5715: }
! 5716: #endif
! 5717:
! 5718: pd.src = (struct pf_addr *)&h->ip6_src;
! 5719: pd.dst = (struct pf_addr *)&h->ip6_dst;
! 5720: PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
! 5721: pd.ip_sum = NULL;
! 5722: pd.af = AF_INET6;
! 5723: pd.tos = 0;
! 5724: pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
! 5725: pd.eh = eh;
! 5726:
! 5727: off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
! 5728: pd.proto = h->ip6_nxt;
! 5729: do {
! 5730: switch (pd.proto) {
! 5731: case IPPROTO_FRAGMENT:
! 5732: action = pf_test_fragment(&r, dir, kif, m, h,
! 5733: &pd, &a, &ruleset);
! 5734: if (action == PF_DROP)
! 5735: REASON_SET(&reason, PFRES_FRAG);
! 5736: goto done;
! 5737: case IPPROTO_ROUTING: {
! 5738: struct ip6_rthdr rthdr;
! 5739:
! 5740: if (rh_cnt++) {
! 5741: DPFPRINTF(PF_DEBUG_MISC,
! 5742: ("pf: IPv6 more than one rthdr\n"));
! 5743: action = PF_DROP;
! 5744: REASON_SET(&reason, PFRES_IPOPTIONS);
! 5745: log = 1;
! 5746: goto done;
! 5747: }
! 5748: if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
! 5749: &reason, pd.af)) {
! 5750: DPFPRINTF(PF_DEBUG_MISC,
! 5751: ("pf: IPv6 short rthdr\n"));
! 5752: action = PF_DROP;
! 5753: REASON_SET(&reason, PFRES_SHORT);
! 5754: log = 1;
! 5755: goto done;
! 5756: }
! 5757: if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
! 5758: DPFPRINTF(PF_DEBUG_MISC,
! 5759: ("pf: IPv6 rthdr0\n"));
! 5760: action = PF_DROP;
! 5761: REASON_SET(&reason, PFRES_IPOPTIONS);
! 5762: log = 1;
! 5763: goto done;
! 5764: }
! 5765: /* FALLTHROUGH */
! 5766: }
! 5767: case IPPROTO_AH:
! 5768: case IPPROTO_HOPOPTS:
! 5769: case IPPROTO_DSTOPTS: {
! 5770: /* get next header and header length */
! 5771: struct ip6_ext opt6;
! 5772:
! 5773: if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
! 5774: NULL, &reason, pd.af)) {
! 5775: DPFPRINTF(PF_DEBUG_MISC,
! 5776: ("pf: IPv6 short opt\n"));
! 5777: action = PF_DROP;
! 5778: log = 1;
! 5779: goto done;
! 5780: }
! 5781: if (pd.proto == IPPROTO_AH)
! 5782: off += (opt6.ip6e_len + 2) * 4;
! 5783: else
! 5784: off += (opt6.ip6e_len + 1) * 8;
! 5785: pd.proto = opt6.ip6e_nxt;
! 5786: /* goto the next header */
! 5787: break;
! 5788: }
! 5789: default:
! 5790: terminal++;
! 5791: break;
! 5792: }
! 5793: } while (!terminal);
! 5794:
! 5795: /* if there's no routing header, use unmodified mbuf for checksumming */
! 5796: if (!n)
! 5797: n = m;
! 5798:
! 5799: switch (pd.proto) {
! 5800:
! 5801: case IPPROTO_TCP: {
! 5802: struct tcphdr th;
! 5803:
! 5804: pd.hdr.tcp = &th;
! 5805: if (!pf_pull_hdr(m, off, &th, sizeof(th),
! 5806: &action, &reason, AF_INET6)) {
! 5807: log = action != PF_PASS;
! 5808: goto done;
! 5809: }
! 5810: pd.p_len = pd.tot_len - off - (th.th_off << 2);
! 5811: action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
! 5812: if (action == PF_DROP)
! 5813: goto done;
! 5814: action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
! 5815: &reason);
! 5816: if (action == PF_PASS) {
! 5817: #if NPFSYNC
! 5818: pfsync_update_state(s);
! 5819: #endif /* NPFSYNC */
! 5820: r = s->rule.ptr;
! 5821: a = s->anchor.ptr;
! 5822: log = s->log;
! 5823: } else if (s == NULL)
! 5824: action = pf_test_rule(&r, &s, dir, kif,
! 5825: m, off, h, &pd, &a, &ruleset, &ip6intrq);
! 5826: break;
! 5827: }
! 5828:
! 5829: case IPPROTO_UDP: {
! 5830: struct udphdr uh;
! 5831:
! 5832: pd.hdr.udp = &uh;
! 5833: if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
! 5834: &action, &reason, AF_INET6)) {
! 5835: log = action != PF_PASS;
! 5836: goto done;
! 5837: }
! 5838: if (uh.uh_dport == 0 ||
! 5839: ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
! 5840: ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
! 5841: action = PF_DROP;
! 5842: REASON_SET(&reason, PFRES_SHORT);
! 5843: goto done;
! 5844: }
! 5845: action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
! 5846: if (action == PF_PASS) {
! 5847: #if NPFSYNC
! 5848: pfsync_update_state(s);
! 5849: #endif /* NPFSYNC */
! 5850: r = s->rule.ptr;
! 5851: a = s->anchor.ptr;
! 5852: log = s->log;
! 5853: } else if (s == NULL)
! 5854: action = pf_test_rule(&r, &s, dir, kif,
! 5855: m, off, h, &pd, &a, &ruleset, &ip6intrq);
! 5856: break;
! 5857: }
! 5858:
! 5859: case IPPROTO_ICMPV6: {
! 5860: struct icmp6_hdr ih;
! 5861:
! 5862: pd.hdr.icmp6 = &ih;
! 5863: if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
! 5864: &action, &reason, AF_INET6)) {
! 5865: log = action != PF_PASS;
! 5866: goto done;
! 5867: }
! 5868: action = pf_test_state_icmp(&s, dir, kif,
! 5869: m, off, h, &pd, &reason);
! 5870: if (action == PF_PASS) {
! 5871: #if NPFSYNC
! 5872: pfsync_update_state(s);
! 5873: #endif /* NPFSYNC */
! 5874: r = s->rule.ptr;
! 5875: a = s->anchor.ptr;
! 5876: log = s->log;
! 5877: } else if (s == NULL)
! 5878: action = pf_test_rule(&r, &s, dir, kif,
! 5879: m, off, h, &pd, &a, &ruleset, &ip6intrq);
! 5880: break;
! 5881: }
! 5882:
! 5883: default:
! 5884: action = pf_test_state_other(&s, dir, kif, &pd);
! 5885: if (action == PF_PASS) {
! 5886: #if NPFSYNC
! 5887: pfsync_update_state(s);
! 5888: #endif /* NPFSYNC */
! 5889: r = s->rule.ptr;
! 5890: a = s->anchor.ptr;
! 5891: log = s->log;
! 5892: } else if (s == NULL)
! 5893: action = pf_test_rule(&r, &s, dir, kif, m, off, h,
! 5894: &pd, &a, &ruleset, &ip6intrq);
! 5895: break;
! 5896: }
! 5897:
! 5898: done:
! 5899: if (n != m) {
! 5900: m_freem(n);
! 5901: n = NULL;
! 5902: }
! 5903:
! 5904: /* handle dangerous IPv6 extension headers. */
! 5905: if (action == PF_PASS && rh_cnt &&
! 5906: !((s && s->allow_opts) || r->allow_opts)) {
! 5907: action = PF_DROP;
! 5908: REASON_SET(&reason, PFRES_IPOPTIONS);
! 5909: log = 1;
! 5910: DPFPRINTF(PF_DEBUG_MISC,
! 5911: ("pf: dropping packet with dangerous v6 headers\n"));
! 5912: }
! 5913:
! 5914: if ((s && s->tag) || r->rtableid)
! 5915: pf_tag_packet(m, s ? s->tag : 0, r->rtableid);
! 5916:
! 5917: #ifdef ALTQ
! 5918: if (action == PF_PASS && r->qid) {
! 5919: if (pd.tos & IPTOS_LOWDELAY)
! 5920: m->m_pkthdr.pf.qid = r->pqid;
! 5921: else
! 5922: m->m_pkthdr.pf.qid = r->qid;
! 5923: /* add hints for ecn */
! 5924: m->m_pkthdr.pf.hdr = h;
! 5925: }
! 5926: #endif /* ALTQ */
! 5927:
! 5928: if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
! 5929: pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
! 5930: (s->nat_rule.ptr->action == PF_RDR ||
! 5931: s->nat_rule.ptr->action == PF_BINAT) &&
! 5932: IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
! 5933: m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
! 5934:
! 5935: if (log) {
! 5936: struct pf_rule *lr;
! 5937:
! 5938: if (s != NULL && s->nat_rule.ptr != NULL &&
! 5939: s->nat_rule.ptr->log & PF_LOG_ALL)
! 5940: lr = s->nat_rule.ptr;
! 5941: else
! 5942: lr = r;
! 5943: PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, lr, a, ruleset,
! 5944: &pd);
! 5945: }
! 5946:
! 5947: kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
! 5948: kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
! 5949:
! 5950: if (action == PF_PASS || r->action == PF_DROP) {
! 5951: dirndx = (dir == PF_OUT);
! 5952: r->packets[dirndx]++;
! 5953: r->bytes[dirndx] += pd.tot_len;
! 5954: if (a != NULL) {
! 5955: a->packets[dirndx]++;
! 5956: a->bytes[dirndx] += pd.tot_len;
! 5957: }
! 5958: if (s != NULL) {
! 5959: sk = s->state_key;
! 5960: if (s->nat_rule.ptr != NULL) {
! 5961: s->nat_rule.ptr->packets[dirndx]++;
! 5962: s->nat_rule.ptr->bytes[dirndx] += pd.tot_len;
! 5963: }
! 5964: if (s->src_node != NULL) {
! 5965: s->src_node->packets[dirndx]++;
! 5966: s->src_node->bytes[dirndx] += pd.tot_len;
! 5967: }
! 5968: if (s->nat_src_node != NULL) {
! 5969: s->nat_src_node->packets[dirndx]++;
! 5970: s->nat_src_node->bytes[dirndx] += pd.tot_len;
! 5971: }
! 5972: dirndx = (dir == sk->direction) ? 0 : 1;
! 5973: s->packets[dirndx]++;
! 5974: s->bytes[dirndx] += pd.tot_len;
! 5975: }
! 5976: tr = r;
! 5977: nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
! 5978: if (nr != NULL) {
! 5979: struct pf_addr *x;
! 5980: /*
! 5981: * XXX: we need to make sure that the addresses
! 5982: * passed to pfr_update_stats() are the same than
! 5983: * the addresses used during matching (pfr_match)
! 5984: */
! 5985: if (r == &pf_default_rule) {
! 5986: tr = nr;
! 5987: x = (s == NULL || sk->direction == dir) ?
! 5988: &pd.baddr : &pd.naddr;
! 5989: } else {
! 5990: x = (s == NULL || sk->direction == dir) ?
! 5991: &pd.naddr : &pd.baddr;
! 5992: }
! 5993: if (x == &pd.baddr || s == NULL) {
! 5994: if (dir == PF_OUT)
! 5995: pd.src = x;
! 5996: else
! 5997: pd.dst = x;
! 5998: }
! 5999: }
! 6000: if (tr->src.addr.type == PF_ADDR_TABLE)
! 6001: pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL ||
! 6002: sk->direction == dir) ? pd.src : pd.dst, pd.af,
! 6003: pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
! 6004: tr->src.neg);
! 6005: if (tr->dst.addr.type == PF_ADDR_TABLE)
! 6006: pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL ||
! 6007: sk->direction == dir) ? pd.dst : pd.src, pd.af,
! 6008: pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
! 6009: tr->dst.neg);
! 6010: }
! 6011:
! 6012:
! 6013: if (action == PF_SYNPROXY_DROP) {
! 6014: m_freem(*m0);
! 6015: *m0 = NULL;
! 6016: action = PF_PASS;
! 6017: } else if (r->rt)
! 6018: /* pf_route6 can free the mbuf causing *m0 to become NULL */
! 6019: pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
! 6020:
! 6021: return (action);
! 6022: }
! 6023: #endif /* INET6 */
! 6024:
! 6025: int
! 6026: pf_check_congestion(struct ifqueue *ifq)
! 6027: {
! 6028: if (ifq->ifq_congestion)
! 6029: return (1);
! 6030: else
! 6031: return (0);
! 6032: }
CVSweb