if_pfsync.c revision 229851
1/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */ 2 3/* 4 * Copyright (c) 2002 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 31 * 32 * Permission to use, copy, modify, and distribute this software for any 33 * purpose with or without fee is hereby granted, provided that the above 34 * copyright notice and this permission notice appear in all copies. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 37 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 38 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 39 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 41 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 42 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 43 */ 44 45/* 46 * Revisions picked from OpenBSD after revision 1.110 import: 47 * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 48 * 1.120, 1.175 - use monotonic time_uptime 49 * 1.122 - reduce number of updates for non-TCP sessions 50 * 1.170 - SIOCSIFMTU checks 51 */ 52 53#ifdef __FreeBSD__ 54#include "opt_inet.h" 55#include "opt_inet6.h" 56#include "opt_pf.h" 57 58#include <sys/cdefs.h> 59__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 229851 2012-01-09 08:55:23Z glebius $"); 60 61#define NBPFILTER 1 62#endif /* __FreeBSD__ */ 63 64#include <sys/param.h> 65#include <sys/kernel.h> 66#ifdef __FreeBSD__ 67#include <sys/bus.h> 68#include <sys/interrupt.h> 69#include <sys/priv.h> 70#endif 71#include <sys/proc.h> 72#include <sys/systm.h> 73#include <sys/time.h> 74#include <sys/mbuf.h> 75#include <sys/socket.h> 76#ifdef __FreeBSD__ 77#include <sys/endian.h> 78#include <sys/malloc.h> 79#include <sys/module.h> 80#include <sys/sockio.h> 81#include <sys/taskqueue.h> 82#include <sys/lock.h> 83#include <sys/mutex.h> 84#include <sys/protosw.h> 85#else 86#include <sys/ioctl.h> 87#include <sys/timeout.h> 88#endif 89#include <sys/sysctl.h> 90#ifndef __FreeBSD__ 91#include <sys/pool.h> 92#endif 93 94#include <net/if.h> 95#ifdef __FreeBSD__ 96#include <net/if_clone.h> 97#endif 98#include <net/if_types.h> 99#include <net/route.h> 100#include <net/bpf.h> 101#include <net/netisr.h> 102#ifdef __FreeBSD__ 103#include <net/vnet.h> 104#endif 105 106#include <netinet/in.h> 107#include <netinet/if_ether.h> 108#include <netinet/tcp.h> 109#include <netinet/tcp_seq.h> 110 111#ifdef INET 112#include <netinet/in_systm.h> 113#include <netinet/in_var.h> 114#include <netinet/ip.h> 115#include <netinet/ip_var.h> 116#endif 117 118#ifdef INET6 119#include <netinet6/nd6.h> 120#endif /* INET6 */ 121 122#ifdef __FreeBSD__ 123#include <netinet/ip_carp.h> 124#else 125#include "carp.h" 126#if NCARP > 0 127#include <netinet/ip_carp.h> 128#endif 129#endif 130 131#include <net/pfvar.h> 132#include <net/if_pfsync.h> 133 134#ifndef __FreeBSD__ 135#include "bpfilter.h" 136#include "pfsync.h" 137#endif 138 139#define PFSYNC_MINPKT ( \ 140 sizeof(struct ip) + \ 141 sizeof(struct pfsync_header) + \ 142 sizeof(struct pfsync_subheader) + \ 143 sizeof(struct pfsync_eof)) 144 145struct pfsync_pkt { 146 struct ip *ip; 147 struct in_addr src; 148 u_int8_t flags; 149}; 150 151int pfsync_input_hmac(struct mbuf *, int); 152 153int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 154 struct pfsync_state_peer *); 155 156int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 157int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 158int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 159int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 160int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 161int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 162int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 163int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 164int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 165int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 166int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 167 168int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 169 170int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 171 pfsync_in_clr, /* PFSYNC_ACT_CLR */ 172 pfsync_in_ins, /* PFSYNC_ACT_INS */ 173 pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 174 pfsync_in_upd, /* PFSYNC_ACT_UPD */ 175 pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 176 pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 177 pfsync_in_del, /* PFSYNC_ACT_DEL */ 178 pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 179 pfsync_in_error, /* PFSYNC_ACT_INS_F */ 180 pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 181 pfsync_in_bus, /* PFSYNC_ACT_BUS */ 182 pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 183 pfsync_in_eof /* PFSYNC_ACT_EOF */ 184}; 185 186struct pfsync_q { 187 int (*write)(struct pf_state *, struct mbuf *, int); 188 size_t len; 189 u_int8_t action; 190}; 191 192/* we have one of these for every PFSYNC_S_ */ 193int pfsync_out_state(struct pf_state *, struct mbuf *, int); 194int pfsync_out_iack(struct pf_state *, struct mbuf *, int); 195int pfsync_out_upd_c(struct pf_state *, struct mbuf *, int); 196int pfsync_out_del(struct pf_state *, struct mbuf *, int); 197 198struct pfsync_q pfsync_qs[] = { 199 { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 200 { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 201 { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 202 { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 203 { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 204}; 205 206void pfsync_q_ins(struct pf_state *, int); 207void pfsync_q_del(struct pf_state *); 208 209struct pfsync_upd_req_item { 210 TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 211 struct pfsync_upd_req ur_msg; 212}; 213TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item); 214 215struct pfsync_deferral { 216 TAILQ_ENTRY(pfsync_deferral) pd_entry; 217 struct pf_state *pd_st; 218 struct mbuf *pd_m; 219#ifdef __FreeBSD__ 220 struct callout pd_tmo; 221#else 222 struct timeout pd_tmo; 223#endif 224}; 225TAILQ_HEAD(pfsync_deferrals, pfsync_deferral); 226 227#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \ 228 sizeof(struct pfsync_deferral)) 229 230#ifdef notyet 231int pfsync_out_tdb(struct tdb *, struct mbuf *, int); 232#endif 233 234struct pfsync_softc { 235#ifdef __FreeBSD__ 236 struct ifnet *sc_ifp; 237#else 238 struct ifnet sc_if; 239#endif 240 struct ifnet *sc_sync_if; 241 242#ifdef __FreeBSD__ 243 uma_zone_t sc_pool; 244#else 245 struct pool sc_pool; 246#endif 247 248 struct ip_moptions sc_imo; 249 250 struct in_addr sc_sync_peer; 251 u_int8_t sc_maxupdates; 252#ifdef __FreeBSD__ 253 int pfsync_sync_ok; 254#endif 255 256 struct ip sc_template; 257 258 struct pf_state_queue sc_qs[PFSYNC_S_COUNT]; 259 size_t sc_len; 260 261 struct pfsync_upd_reqs sc_upd_req_list; 262 263 struct pfsync_deferrals sc_deferrals; 264 u_int sc_deferred; 265 266 void *sc_plus; 267 size_t sc_pluslen; 268 269 u_int32_t sc_ureq_sent; 270 int sc_bulk_tries; 271#ifdef __FreeBSD__ 272 struct callout sc_bulkfail_tmo; 273#else 274 struct timeout sc_bulkfail_tmo; 275#endif 276 277 u_int32_t sc_ureq_received; 278 struct pf_state *sc_bulk_next; 279 struct pf_state *sc_bulk_last; 280#ifdef __FreeBSD__ 281 struct callout sc_bulk_tmo; 282#else 283 struct timeout sc_bulk_tmo; 284#endif 285 286 TAILQ_HEAD(, tdb) sc_tdb_q; 287 288#ifdef __FreeBSD__ 289 struct callout sc_tmo; 290#else 291 struct timeout sc_tmo; 292#endif 293}; 294 295#ifdef __FreeBSD__ 296static MALLOC_DEFINE(M_PFSYNC, "pfsync", "pfsync data"); 297static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 298#define V_pfsyncif VNET(pfsyncif) 299static VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 300#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 301static VNET_DEFINE(struct pfsyncstats, pfsyncstats); 302#define V_pfsyncstats VNET(pfsyncstats) 303static VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; 304#define V_pfsync_carp_adj VNET(pfsync_carp_adj) 305 306static void pfsyncintr(void *); 307static int pfsync_multicast_setup(struct pfsync_softc *); 308static void pfsync_multicast_cleanup(struct pfsync_softc *); 309static int pfsync_init(void); 310static void pfsync_uninit(void); 311 312SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 313SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 314 &VNET_NAME(pfsyncstats), pfsyncstats, 315 "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 316SYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW, 317 &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 318#else 319struct pfsync_softc *pfsyncif = NULL; 320struct pfsyncstats pfsyncstats; 321#define V_pfsyncstats pfsyncstats 322#endif 323 324void pfsyncattach(int); 325#ifdef __FreeBSD__ 326int pfsync_clone_create(struct if_clone *, int, caddr_t); 327void pfsync_clone_destroy(struct ifnet *); 328#else 329int pfsync_clone_create(struct if_clone *, int); 330int pfsync_clone_destroy(struct ifnet *); 331#endif 332int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 333 struct pf_state_peer *); 334void pfsync_update_net_tdb(struct pfsync_tdb *); 335int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 336#ifdef __FreeBSD__ 337 struct route *); 338#else 339 struct rtentry *); 340#endif 341int pfsyncioctl(struct ifnet *, u_long, caddr_t); 342void pfsyncstart(struct ifnet *); 343 344struct mbuf *pfsync_if_dequeue(struct ifnet *); 345struct mbuf *pfsync_get_mbuf(struct pfsync_softc *); 346 347void pfsync_deferred(struct pf_state *, int); 348void pfsync_undefer(struct pfsync_deferral *, int); 349void pfsync_defer_tmo(void *); 350 351void pfsync_request_update(u_int32_t, u_int64_t); 352void pfsync_update_state_req(struct pf_state *); 353 354void pfsync_drop(struct pfsync_softc *); 355void pfsync_sendout(void); 356void pfsync_send_plus(void *, size_t); 357int pfsync_tdb_sendout(struct pfsync_softc *); 358int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *); 359void pfsync_timeout(void *); 360void pfsync_tdb_timeout(void *); 361void pfsync_send_bus(struct pfsync_softc *, u_int8_t); 362 363void pfsync_bulk_start(void); 364void pfsync_bulk_status(u_int8_t); 365void pfsync_bulk_update(void *); 366void pfsync_bulk_fail(void *); 367 368#ifdef __FreeBSD__ 369/* XXX: ugly */ 370#define betoh64 (unsigned long long)be64toh 371#define timeout_del callout_stop 372#endif 373 374#define PFSYNC_MAX_BULKTRIES 12 375#ifndef __FreeBSD__ 376int pfsync_sync_ok; 377#endif 378 379#ifdef __FreeBSD__ 380VNET_DEFINE(struct ifc_simple_data, pfsync_cloner_data); 381VNET_DEFINE(struct if_clone, pfsync_cloner); 382#define V_pfsync_cloner_data VNET(pfsync_cloner_data) 383#define V_pfsync_cloner VNET(pfsync_cloner) 384IFC_SIMPLE_DECLARE(pfsync, 1); 385#else 386struct if_clone pfsync_cloner = 387 IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 388#endif 389 390void 391pfsyncattach(int npfsync) 392{ 393 if_clone_attach(&pfsync_cloner); 394} 395int 396#ifdef __FreeBSD__ 397pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 398#else 399pfsync_clone_create(struct if_clone *ifc, int unit) 400#endif 401{ 402 struct pfsync_softc *sc; 403 struct ifnet *ifp; 404 int q; 405 406 if (unit != 0) 407 return (EINVAL); 408 409#ifdef __FreeBSD__ 410 sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 411 sc->pfsync_sync_ok = 1; 412#else 413 pfsync_sync_ok = 1; 414 sc = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT | M_ZERO); 415#endif 416 417 for (q = 0; q < PFSYNC_S_COUNT; q++) 418 TAILQ_INIT(&sc->sc_qs[q]); 419 420#ifdef __FreeBSD__ 421 sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, NULL, NULL, NULL, 422 NULL, UMA_ALIGN_PTR, 0); 423#else 424 pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 425#endif 426 TAILQ_INIT(&sc->sc_upd_req_list); 427 TAILQ_INIT(&sc->sc_deferrals); 428 sc->sc_deferred = 0; 429 430 TAILQ_INIT(&sc->sc_tdb_q); 431 432 sc->sc_len = PFSYNC_MINPKT; 433 sc->sc_maxupdates = 128; 434 435#ifndef __FreeBSD__ 436 sc->sc_imo.imo_membership = (struct in_multi **)malloc( 437 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 438 M_WAITOK | M_ZERO); 439 sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 440#endif 441 442#ifdef __FreeBSD__ 443 ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 444 if (ifp == NULL) { 445 uma_zdestroy(sc->sc_pool); 446 free(sc, M_PFSYNC); 447 return (ENOSPC); 448 } 449 if_initname(ifp, ifc->ifc_name, unit); 450#else 451 ifp = &sc->sc_if; 452 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 453#endif 454 ifp->if_softc = sc; 455 ifp->if_ioctl = pfsyncioctl; 456 ifp->if_output = pfsyncoutput; 457 ifp->if_start = pfsyncstart; 458 ifp->if_type = IFT_PFSYNC; 459 ifp->if_snd.ifq_maxlen = ifqmaxlen; 460 ifp->if_hdrlen = sizeof(struct pfsync_header); 461 ifp->if_mtu = ETHERMTU; 462#ifdef __FreeBSD__ 463 callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 464 callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0); 465 callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); 466#else 467 timeout_set(&sc->sc_tmo, pfsync_timeout, sc); 468 timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); 469 timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); 470#endif 471 472 if_attach(ifp); 473#ifndef __FreeBSD__ 474 if_alloc_sadl(ifp); 475 476#if NCARP > 0 477 if_addgroup(ifp, "carp"); 478#endif 479#endif 480 481#if NBPFILTER > 0 482#ifdef __FreeBSD__ 483 bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 484#else 485 bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 486#endif 487#endif 488 489#ifdef __FreeBSD__ 490 V_pfsyncif = sc; 491#else 492 pfsyncif = sc; 493#endif 494 495 return (0); 496} 497 498#ifdef __FreeBSD__ 499void 500#else 501int 502#endif 503pfsync_clone_destroy(struct ifnet *ifp) 504{ 505 struct pfsync_softc *sc = ifp->if_softc; 506 507#ifdef __FreeBSD__ 508 PF_LOCK(); 509#endif 510 timeout_del(&sc->sc_bulkfail_tmo); 511 timeout_del(&sc->sc_bulk_tmo); 512 timeout_del(&sc->sc_tmo); 513#ifdef __FreeBSD__ 514 PF_UNLOCK(); 515 if (!sc->pfsync_sync_ok && carp_demote_adj_p) 516 (*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy"); 517#else 518#if NCARP > 0 519 if (!pfsync_sync_ok) 520 carp_group_demote_adj(&sc->sc_if, -1); 521#endif 522#endif 523#if NBPFILTER > 0 524 bpfdetach(ifp); 525#endif 526 if_detach(ifp); 527 528 pfsync_drop(sc); 529 530 while (sc->sc_deferred > 0) 531 pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 532 533#ifdef __FreeBSD__ 534 UMA_DESTROY(sc->sc_pool); 535#else 536 pool_destroy(&sc->sc_pool); 537#endif 538#ifdef __FreeBSD__ 539 if_free(ifp); 540 if (sc->sc_imo.imo_membership) 541 pfsync_multicast_cleanup(sc); 542 free(sc, M_PFSYNC); 543#else 544 free(sc->sc_imo.imo_membership, M_IPMOPTS); 545 free(sc, M_DEVBUF); 546#endif 547 548#ifdef __FreeBSD__ 549 V_pfsyncif = NULL; 550#else 551 pfsyncif = NULL; 552#endif 553 554#ifndef __FreeBSD__ 555 return (0); 556#endif 557} 558 559struct mbuf * 560pfsync_if_dequeue(struct ifnet *ifp) 561{ 562 struct mbuf *m; 563#ifndef __FreeBSD__ 564 int s; 565#endif 566 567#ifdef __FreeBSD__ 568 IF_LOCK(&ifp->if_snd); 569 _IF_DROP(&ifp->if_snd); 570 _IF_DEQUEUE(&ifp->if_snd, m); 571 IF_UNLOCK(&ifp->if_snd); 572#else 573 s = splnet(); 574 IF_DEQUEUE(&ifp->if_snd, m); 575 splx(s); 576#endif 577 578 return (m); 579} 580 581/* 582 * Start output on the pfsync interface. 583 */ 584void 585pfsyncstart(struct ifnet *ifp) 586{ 587 struct mbuf *m; 588 589 while ((m = pfsync_if_dequeue(ifp)) != NULL) { 590#ifndef __FreeBSD__ 591 IF_DROP(&ifp->if_snd); 592#endif 593 m_freem(m); 594 } 595} 596 597int 598pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 599 struct pf_state_peer *d) 600{ 601 if (s->scrub.scrub_flag && d->scrub == NULL) { 602#ifdef __FreeBSD__ 603 d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 604#else 605 d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 606#endif 607 if (d->scrub == NULL) 608 return (ENOMEM); 609 } 610 611 return (0); 612} 613 614#ifndef __FreeBSD__ 615void 616pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 617{ 618 bzero(sp, sizeof(struct pfsync_state)); 619 620 /* copy from state key */ 621 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 622 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 623 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 624 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 625 sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 626 sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 627 sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 628 sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 629 sp->proto = st->key[PF_SK_WIRE]->proto; 630 sp->af = st->key[PF_SK_WIRE]->af; 631 632 /* copy from state */ 633 strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 634 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 635 sp->creation = htonl(time_uptime - st->creation); 636 sp->expire = pf_state_expires(st); 637 if (sp->expire <= time_second) 638 sp->expire = htonl(0); 639 else 640 sp->expire = htonl(sp->expire - time_second); 641 642 sp->direction = st->direction; 643 sp->log = st->log; 644 sp->timeout = st->timeout; 645 sp->state_flags = st->state_flags; 646 if (st->src_node) 647 sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 648 if (st->nat_src_node) 649 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 650 651 bcopy(&st->id, &sp->id, sizeof(sp->id)); 652 sp->creatorid = st->creatorid; 653 pf_state_peer_hton(&st->src, &sp->src); 654 pf_state_peer_hton(&st->dst, &sp->dst); 655 656 if (st->rule.ptr == NULL) 657 sp->rule = htonl(-1); 658 else 659 sp->rule = htonl(st->rule.ptr->nr); 660 if (st->anchor.ptr == NULL) 661 sp->anchor = htonl(-1); 662 else 663 sp->anchor = htonl(st->anchor.ptr->nr); 664 if (st->nat_rule.ptr == NULL) 665 sp->nat_rule = htonl(-1); 666 else 667 sp->nat_rule = htonl(st->nat_rule.ptr->nr); 668 669 pf_state_counter_hton(st->packets[0], sp->packets[0]); 670 pf_state_counter_hton(st->packets[1], sp->packets[1]); 671 pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 672 pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 673 674} 675#endif 676 677int 678pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 679{ 680 struct pf_state *st = NULL; 681 struct pf_state_key *skw = NULL, *sks = NULL; 682 struct pf_rule *r = NULL; 683 struct pfi_kif *kif; 684 int pool_flags; 685 int error; 686 687 PF_LOCK_ASSERT(); 688 689#ifdef __FreeBSD__ 690 if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { 691#else 692 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 693#endif 694 printf("pfsync_state_import: invalid creator id:" 695 " %08x\n", ntohl(sp->creatorid)); 696 return (EINVAL); 697 } 698 699 if ((kif = pfi_kif_get(sp->ifname)) == NULL) { 700#ifdef __FreeBSD__ 701 if (V_pf_status.debug >= PF_DEBUG_MISC) 702#else 703 if (pf_status.debug >= PF_DEBUG_MISC) 704#endif 705 printf("pfsync_state_import: " 706 "unknown interface: %s\n", sp->ifname); 707 if (flags & PFSYNC_SI_IOCTL) 708 return (EINVAL); 709 return (0); /* skip this state */ 710 } 711 712 /* 713 * If the ruleset checksums match or the state is coming from the ioctl, 714 * it's safe to associate the state with the rule of that number. 715 */ 716 if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 717 (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 718 pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 719 r = pf_main_ruleset.rules[ 720 PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 721 else 722#ifdef __FreeBSD__ 723 r = &V_pf_default_rule; 724#else 725 r = &pf_default_rule; 726#endif 727 728 if ((r->max_states && r->states_cur >= r->max_states)) 729 goto cleanup; 730 731#ifdef __FreeBSD__ 732 if (flags & PFSYNC_SI_IOCTL) 733 pool_flags = PR_WAITOK | PR_ZERO; 734 else 735 pool_flags = PR_NOWAIT | PR_ZERO; 736 737 if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL) 738 goto cleanup; 739#else 740 if (flags & PFSYNC_SI_IOCTL) 741 pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; 742 else 743 pool_flags = PR_LIMITFAIL | PR_ZERO; 744 745 if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) 746 goto cleanup; 747#endif 748 749 if ((skw = pf_alloc_state_key(pool_flags)) == NULL) 750 goto cleanup; 751 752 if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 753 &sp->key[PF_SK_STACK].addr[0], sp->af) || 754 PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 755 &sp->key[PF_SK_STACK].addr[1], sp->af) || 756 sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 757 sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 758 if ((sks = pf_alloc_state_key(pool_flags)) == NULL) 759 goto cleanup; 760 } else 761 sks = skw; 762 763 /* allocate memory for scrub info */ 764 if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 765 pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 766 goto cleanup; 767 768 /* copy to state key(s) */ 769 skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 770 skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 771 skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 772 skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 773 skw->proto = sp->proto; 774 skw->af = sp->af; 775 if (sks != skw) { 776 sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 777 sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 778 sks->port[0] = sp->key[PF_SK_STACK].port[0]; 779 sks->port[1] = sp->key[PF_SK_STACK].port[1]; 780 sks->proto = sp->proto; 781 sks->af = sp->af; 782 } 783 784 /* copy to state */ 785 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 786 st->creation = time_uptime - ntohl(sp->creation); 787 st->expire = time_second; 788 if (sp->expire) { 789 /* XXX No adaptive scaling. */ 790 st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); 791 } 792 793 st->expire = ntohl(sp->expire) + time_second; 794 st->direction = sp->direction; 795 st->log = sp->log; 796 st->timeout = sp->timeout; 797 st->state_flags = sp->state_flags; 798 799 bcopy(sp->id, &st->id, sizeof(st->id)); 800 st->creatorid = sp->creatorid; 801 pf_state_peer_ntoh(&sp->src, &st->src); 802 pf_state_peer_ntoh(&sp->dst, &st->dst); 803 804 st->rule.ptr = r; 805 st->nat_rule.ptr = NULL; 806 st->anchor.ptr = NULL; 807 st->rt_kif = NULL; 808 809 st->pfsync_time = time_uptime; 810 st->sync_state = PFSYNC_S_NONE; 811 812 /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 813 r->states_cur++; 814 r->states_tot++; 815 816 if (!ISSET(flags, PFSYNC_SI_IOCTL)) 817 SET(st->state_flags, PFSTATE_NOSYNC); 818 819 if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 820 /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 821 r->states_cur--; 822 goto cleanup_state; 823 } 824 825 if (!ISSET(flags, PFSYNC_SI_IOCTL)) { 826 CLR(st->state_flags, PFSTATE_NOSYNC); 827 if (ISSET(st->state_flags, PFSTATE_ACK)) { 828 pfsync_q_ins(st, PFSYNC_S_IACK); 829#ifdef __FreeBSD__ 830 pfsync_sendout(); 831#else 832 schednetisr(NETISR_PFSYNC); 833#endif 834 } 835 } 836 CLR(st->state_flags, PFSTATE_ACK); 837 838 return (0); 839 840cleanup: 841 error = ENOMEM; 842 if (skw == sks) 843 sks = NULL; 844#ifdef __FreeBSD__ 845 if (skw != NULL) 846 pool_put(&V_pf_state_key_pl, skw); 847 if (sks != NULL) 848 pool_put(&V_pf_state_key_pl, sks); 849#else 850 if (skw != NULL) 851 pool_put(&pf_state_key_pl, skw); 852 if (sks != NULL) 853 pool_put(&pf_state_key_pl, sks); 854#endif 855 856cleanup_state: /* pf_state_insert frees the state keys */ 857 if (st) { 858#ifdef __FreeBSD__ 859 if (st->dst.scrub) 860 pool_put(&V_pf_state_scrub_pl, st->dst.scrub); 861 if (st->src.scrub) 862 pool_put(&V_pf_state_scrub_pl, st->src.scrub); 863 pool_put(&V_pf_state_pl, st); 864#else 865 if (st->dst.scrub) 866 pool_put(&pf_state_scrub_pl, st->dst.scrub); 867 if (st->src.scrub) 868 pool_put(&pf_state_scrub_pl, st->src.scrub); 869 pool_put(&pf_state_pl, st); 870#endif 871 } 872 return (error); 873} 874 875void 876#ifdef __FreeBSD__ 877pfsync_input(struct mbuf *m, __unused int off) 878#else 879pfsync_input(struct mbuf *m, ...) 880#endif 881{ 882#ifdef __FreeBSD__ 883 struct pfsync_softc *sc = V_pfsyncif; 884#else 885 struct pfsync_softc *sc = pfsyncif; 886#endif 887 struct pfsync_pkt pkt; 888 struct ip *ip = mtod(m, struct ip *); 889 struct pfsync_header *ph; 890 struct pfsync_subheader subh; 891 892 int offset; 893 int rv; 894 895 V_pfsyncstats.pfsyncs_ipackets++; 896 897 /* verify that we have a sync interface configured */ 898#ifdef __FreeBSD__ 899 if (!sc || !sc->sc_sync_if || !V_pf_status.running) 900#else 901 if (!sc || !sc->sc_sync_if || !pf_status.running) 902#endif 903 goto done; 904 905 /* verify that the packet came in on the right interface */ 906 if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 907 V_pfsyncstats.pfsyncs_badif++; 908 goto done; 909 } 910 911#ifdef __FreeBSD__ 912 sc->sc_ifp->if_ipackets++; 913 sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 914#else 915 sc->sc_if.if_ipackets++; 916 sc->sc_if.if_ibytes += m->m_pkthdr.len; 917#endif 918 /* verify that the IP TTL is 255. */ 919 if (ip->ip_ttl != PFSYNC_DFLTTL) { 920 V_pfsyncstats.pfsyncs_badttl++; 921 goto done; 922 } 923 924 offset = ip->ip_hl << 2; 925 if (m->m_pkthdr.len < offset + sizeof(*ph)) { 926 V_pfsyncstats.pfsyncs_hdrops++; 927 goto done; 928 } 929 930 if (offset + sizeof(*ph) > m->m_len) { 931 if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 932 V_pfsyncstats.pfsyncs_hdrops++; 933 return; 934 } 935 ip = mtod(m, struct ip *); 936 } 937 ph = (struct pfsync_header *)((char *)ip + offset); 938 939 /* verify the version */ 940 if (ph->version != PFSYNC_VERSION) { 941 V_pfsyncstats.pfsyncs_badver++; 942 goto done; 943 } 944 945#if 0 946 if (pfsync_input_hmac(m, offset) != 0) { 947 /* XXX stats */ 948 goto done; 949 } 950#endif 951 952 /* Cheaper to grab this now than having to mess with mbufs later */ 953 pkt.ip = ip; 954 pkt.src = ip->ip_src; 955 pkt.flags = 0; 956 957#ifdef __FreeBSD__ 958 if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 959#else 960 if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 961#endif 962 pkt.flags |= PFSYNC_SI_CKSUM; 963 964 offset += sizeof(*ph); 965 for (;;) { 966 m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 967 offset += sizeof(subh); 968 969 if (subh.action >= PFSYNC_ACT_MAX) { 970 V_pfsyncstats.pfsyncs_badact++; 971 goto done; 972 } 973 974 rv = (*pfsync_acts[subh.action])(&pkt, m, offset, 975 ntohs(subh.count)); 976 if (rv == -1) 977 return; 978 979 offset += rv; 980 } 981 982done: 983 m_freem(m); 984} 985 986int 987pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 988{ 989 struct pfsync_clr *clr; 990 struct mbuf *mp; 991 int len = sizeof(*clr) * count; 992 int i, offp; 993 994 struct pf_state *st, *nexts; 995 struct pf_state_key *sk, *nextsk; 996 struct pf_state_item *si; 997 u_int32_t creatorid; 998 int s; 999 1000 mp = m_pulldown(m, offset, len, &offp); 1001 if (mp == NULL) { 1002 V_pfsyncstats.pfsyncs_badlen++; 1003 return (-1); 1004 } 1005 clr = (struct pfsync_clr *)(mp->m_data + offp); 1006 1007 s = splsoftnet(); 1008#ifdef __FreeBSD__ 1009 PF_LOCK(); 1010#endif 1011 for (i = 0; i < count; i++) { 1012 creatorid = clr[i].creatorid; 1013 1014 if (clr[i].ifname[0] == '\0') { 1015#ifdef __FreeBSD__ 1016 for (st = RB_MIN(pf_state_tree_id, &V_tree_id); 1017 st; st = nexts) { 1018 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); 1019#else 1020 for (st = RB_MIN(pf_state_tree_id, &tree_id); 1021 st; st = nexts) { 1022 nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 1023#endif 1024 if (st->creatorid == creatorid) { 1025 SET(st->state_flags, PFSTATE_NOSYNC); 1026 pf_unlink_state(st); 1027 } 1028 } 1029 } else { 1030 if (pfi_kif_get(clr[i].ifname) == NULL) 1031 continue; 1032 1033 /* XXX correct? */ 1034#ifdef __FreeBSD__ 1035 for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); 1036#else 1037 for (sk = RB_MIN(pf_state_tree, &pf_statetbl); 1038#endif 1039 sk; sk = nextsk) { 1040 nextsk = RB_NEXT(pf_state_tree, 1041#ifdef __FreeBSD__ 1042 &V_pf_statetbl, sk); 1043#else 1044 &pf_statetbl, sk); 1045#endif 1046 TAILQ_FOREACH(si, &sk->states, entry) { 1047 if (si->s->creatorid == creatorid) { 1048 SET(si->s->state_flags, 1049 PFSTATE_NOSYNC); 1050 pf_unlink_state(si->s); 1051 } 1052 } 1053 } 1054 } 1055 } 1056#ifdef __FreeBSD__ 1057 PF_UNLOCK(); 1058#endif 1059 splx(s); 1060 1061 return (len); 1062} 1063 1064int 1065pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1066{ 1067 struct mbuf *mp; 1068 struct pfsync_state *sa, *sp; 1069 int len = sizeof(*sp) * count; 1070 int i, offp; 1071 1072 int s; 1073 1074 mp = m_pulldown(m, offset, len, &offp); 1075 if (mp == NULL) { 1076 V_pfsyncstats.pfsyncs_badlen++; 1077 return (-1); 1078 } 1079 sa = (struct pfsync_state *)(mp->m_data + offp); 1080 1081 s = splsoftnet(); 1082#ifdef __FreeBSD__ 1083 PF_LOCK(); 1084#endif 1085 for (i = 0; i < count; i++) { 1086 sp = &sa[i]; 1087 1088 /* check for invalid values */ 1089 if (sp->timeout >= PFTM_MAX || 1090 sp->src.state > PF_TCPS_PROXY_DST || 1091 sp->dst.state > PF_TCPS_PROXY_DST || 1092 sp->direction > PF_OUT || 1093 (sp->af != AF_INET && sp->af != AF_INET6)) { 1094#ifdef __FreeBSD__ 1095 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1096#else 1097 if (pf_status.debug >= PF_DEBUG_MISC) { 1098#endif 1099 printf("pfsync_input: PFSYNC5_ACT_INS: " 1100 "invalid value\n"); 1101 } 1102 V_pfsyncstats.pfsyncs_badval++; 1103 continue; 1104 } 1105 1106 if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { 1107 /* drop out, but process the rest of the actions */ 1108 break; 1109 } 1110 } 1111#ifdef __FreeBSD__ 1112 PF_UNLOCK(); 1113#endif 1114 splx(s); 1115 1116 return (len); 1117} 1118 1119int 1120pfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1121{ 1122 struct pfsync_ins_ack *ia, *iaa; 1123 struct pf_state_cmp id_key; 1124 struct pf_state *st; 1125 1126 struct mbuf *mp; 1127 int len = count * sizeof(*ia); 1128 int offp, i; 1129 int s; 1130 1131 mp = m_pulldown(m, offset, len, &offp); 1132 if (mp == NULL) { 1133 V_pfsyncstats.pfsyncs_badlen++; 1134 return (-1); 1135 } 1136 iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 1137 1138 s = splsoftnet(); 1139#ifdef __FreeBSD__ 1140 PF_LOCK(); 1141#endif 1142 for (i = 0; i < count; i++) { 1143 ia = &iaa[i]; 1144 1145 bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); 1146 id_key.creatorid = ia->creatorid; 1147 1148 st = pf_find_state_byid(&id_key); 1149 if (st == NULL) 1150 continue; 1151 1152 if (ISSET(st->state_flags, PFSTATE_ACK)) 1153 pfsync_deferred(st, 0); 1154 } 1155#ifdef __FreeBSD__ 1156 PF_UNLOCK(); 1157#endif 1158 splx(s); 1159 /* 1160 * XXX this is not yet implemented, but we know the size of the 1161 * message so we can skip it. 1162 */ 1163 1164 return (count * sizeof(struct pfsync_ins_ack)); 1165} 1166 1167int 1168pfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 1169 struct pfsync_state_peer *dst) 1170{ 1171 int sfail = 0; 1172 1173 /* 1174 * The state should never go backwards except 1175 * for syn-proxy states. Neither should the 1176 * sequence window slide backwards. 1177 */ 1178 if (st->src.state > src->state && 1179 (st->src.state < PF_TCPS_PROXY_SRC || 1180 src->state >= PF_TCPS_PROXY_SRC)) 1181 sfail = 1; 1182 else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) 1183 sfail = 3; 1184 else if (st->dst.state > dst->state) { 1185 /* There might still be useful 1186 * information about the src state here, 1187 * so import that part of the update, 1188 * then "fail" so we send the updated 1189 * state back to the peer who is missing 1190 * our what we know. */ 1191 pf_state_peer_ntoh(src, &st->src); 1192 /* XXX do anything with timeouts? */ 1193 sfail = 7; 1194 } else if (st->dst.state >= TCPS_SYN_SENT && 1195 SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) 1196 sfail = 4; 1197 1198 return (sfail); 1199} 1200 1201int 1202pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1203{ 1204 struct pfsync_state *sa, *sp; 1205 struct pf_state_cmp id_key; 1206 struct pf_state_key *sk; 1207 struct pf_state *st; 1208 int sfail; 1209 1210 struct mbuf *mp; 1211 int len = count * sizeof(*sp); 1212 int offp, i; 1213 int s; 1214 1215 mp = m_pulldown(m, offset, len, &offp); 1216 if (mp == NULL) { 1217 V_pfsyncstats.pfsyncs_badlen++; 1218 return (-1); 1219 } 1220 sa = (struct pfsync_state *)(mp->m_data + offp); 1221 1222 s = splsoftnet(); 1223#ifdef __FreeBSD__ 1224 PF_LOCK(); 1225#endif 1226 for (i = 0; i < count; i++) { 1227 sp = &sa[i]; 1228 1229 /* check for invalid values */ 1230 if (sp->timeout >= PFTM_MAX || 1231 sp->src.state > PF_TCPS_PROXY_DST || 1232 sp->dst.state > PF_TCPS_PROXY_DST) { 1233#ifdef __FreeBSD__ 1234 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1235#else 1236 if (pf_status.debug >= PF_DEBUG_MISC) { 1237#endif 1238 printf("pfsync_input: PFSYNC_ACT_UPD: " 1239 "invalid value\n"); 1240 } 1241 V_pfsyncstats.pfsyncs_badval++; 1242 continue; 1243 } 1244 1245 bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1246 id_key.creatorid = sp->creatorid; 1247 1248 st = pf_find_state_byid(&id_key); 1249 if (st == NULL) { 1250 /* insert the update */ 1251 if (pfsync_state_import(sp, 0)) 1252 V_pfsyncstats.pfsyncs_badstate++; 1253 continue; 1254 } 1255 1256 if (ISSET(st->state_flags, PFSTATE_ACK)) 1257 pfsync_deferred(st, 1); 1258 1259 sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1260 sfail = 0; 1261 if (sk->proto == IPPROTO_TCP) 1262 sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); 1263 else { 1264 /* 1265 * Non-TCP protocol state machine always go 1266 * forwards 1267 */ 1268 if (st->src.state > sp->src.state) 1269 sfail = 5; 1270 else if (st->dst.state > sp->dst.state) 1271 sfail = 6; 1272 } 1273 1274 if (sfail) { 1275#ifdef __FreeBSD__ 1276 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1277#else 1278 if (pf_status.debug >= PF_DEBUG_MISC) { 1279#endif 1280 printf("pfsync: %s stale update (%d)" 1281 " id: %016llx creatorid: %08x\n", 1282 (sfail < 7 ? "ignoring" : "partial"), 1283 sfail, betoh64(st->id), 1284 ntohl(st->creatorid)); 1285 } 1286 V_pfsyncstats.pfsyncs_stale++; 1287 1288 pfsync_update_state(st); 1289#ifdef __FreeBSD__ 1290 pfsync_sendout(); 1291#else 1292 schednetisr(NETISR_PFSYNC); 1293#endif 1294 continue; 1295 } 1296 pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 1297 pf_state_peer_ntoh(&sp->src, &st->src); 1298 pf_state_peer_ntoh(&sp->dst, &st->dst); 1299 st->expire = ntohl(sp->expire) + time_second; 1300 st->timeout = sp->timeout; 1301 st->pfsync_time = time_uptime; 1302 } 1303#ifdef __FreeBSD__ 1304 PF_UNLOCK(); 1305#endif 1306 splx(s); 1307 1308 return (len); 1309} 1310 1311int 1312pfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1313{ 1314 struct pfsync_upd_c *ua, *up; 1315 struct pf_state_key *sk; 1316 struct pf_state_cmp id_key; 1317 struct pf_state *st; 1318 1319 int len = count * sizeof(*up); 1320 int sfail; 1321 1322 struct mbuf *mp; 1323 int offp, i; 1324 int s; 1325 1326 mp = m_pulldown(m, offset, len, &offp); 1327 if (mp == NULL) { 1328 V_pfsyncstats.pfsyncs_badlen++; 1329 return (-1); 1330 } 1331 ua = (struct pfsync_upd_c *)(mp->m_data + offp); 1332 1333 s = splsoftnet(); 1334#ifdef __FreeBSD__ 1335 PF_LOCK(); 1336#endif 1337 for (i = 0; i < count; i++) { 1338 up = &ua[i]; 1339 1340 /* check for invalid values */ 1341 if (up->timeout >= PFTM_MAX || 1342 up->src.state > PF_TCPS_PROXY_DST || 1343 up->dst.state > PF_TCPS_PROXY_DST) { 1344#ifdef __FreeBSD__ 1345 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1346#else 1347 if (pf_status.debug >= PF_DEBUG_MISC) { 1348#endif 1349 printf("pfsync_input: " 1350 "PFSYNC_ACT_UPD_C: " 1351 "invalid value\n"); 1352 } 1353 V_pfsyncstats.pfsyncs_badval++; 1354 continue; 1355 } 1356 1357 bcopy(&up->id, &id_key.id, sizeof(id_key.id)); 1358 id_key.creatorid = up->creatorid; 1359 1360 st = pf_find_state_byid(&id_key); 1361 if (st == NULL) { 1362 /* We don't have this state. Ask for it. */ 1363 pfsync_request_update(id_key.creatorid, id_key.id); 1364 continue; 1365 } 1366 1367 if (ISSET(st->state_flags, PFSTATE_ACK)) 1368 pfsync_deferred(st, 1); 1369 1370 sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1371 sfail = 0; 1372 if (sk->proto == IPPROTO_TCP) 1373 sfail = pfsync_upd_tcp(st, &up->src, &up->dst); 1374 else { 1375 /* 1376 * Non-TCP protocol state machine always go forwards 1377 */ 1378 if (st->src.state > up->src.state) 1379 sfail = 5; 1380 else if (st->dst.state > up->dst.state) 1381 sfail = 6; 1382 } 1383 1384 if (sfail) { 1385#ifdef __FreeBSD__ 1386 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1387#else 1388 if (pf_status.debug >= PF_DEBUG_MISC) { 1389#endif 1390 printf("pfsync: ignoring stale update " 1391 "(%d) id: %016llx " 1392 "creatorid: %08x\n", sfail, 1393 betoh64(st->id), 1394 ntohl(st->creatorid)); 1395 } 1396 V_pfsyncstats.pfsyncs_stale++; 1397 1398 pfsync_update_state(st); 1399#ifdef __FreeBSD__ 1400 pfsync_sendout(); 1401#else 1402 schednetisr(NETISR_PFSYNC); 1403#endif 1404 continue; 1405 } 1406 pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1407 pf_state_peer_ntoh(&up->src, &st->src); 1408 pf_state_peer_ntoh(&up->dst, &st->dst); 1409 st->expire = ntohl(up->expire) + time_second; 1410 st->timeout = up->timeout; 1411 st->pfsync_time = time_uptime; 1412 } 1413#ifdef __FreeBSD__ 1414 PF_UNLOCK(); 1415#endif 1416 splx(s); 1417 1418 return (len); 1419} 1420 1421int 1422pfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1423{ 1424 struct pfsync_upd_req *ur, *ura; 1425 struct mbuf *mp; 1426 int len = count * sizeof(*ur); 1427 int i, offp; 1428 1429 struct pf_state_cmp id_key; 1430 struct pf_state *st; 1431 1432 mp = m_pulldown(m, offset, len, &offp); 1433 if (mp == NULL) { 1434 V_pfsyncstats.pfsyncs_badlen++; 1435 return (-1); 1436 } 1437 ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1438 1439 for (i = 0; i < count; i++) { 1440 ur = &ura[i]; 1441 1442 bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); 1443 id_key.creatorid = ur->creatorid; 1444 1445 if (id_key.id == 0 && id_key.creatorid == 0) 1446 pfsync_bulk_start(); 1447 else { 1448 st = pf_find_state_byid(&id_key); 1449 if (st == NULL) { 1450 V_pfsyncstats.pfsyncs_badstate++; 1451 continue; 1452 } 1453 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) 1454 continue; 1455 1456 PF_LOCK(); 1457 pfsync_update_state_req(st); 1458 PF_UNLOCK(); 1459 } 1460 } 1461 1462 return (len); 1463} 1464 1465int 1466pfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1467{ 1468 struct mbuf *mp; 1469 struct pfsync_state *sa, *sp; 1470 struct pf_state_cmp id_key; 1471 struct pf_state *st; 1472 int len = count * sizeof(*sp); 1473 int offp, i; 1474 int s; 1475 1476 mp = m_pulldown(m, offset, len, &offp); 1477 if (mp == NULL) { 1478 V_pfsyncstats.pfsyncs_badlen++; 1479 return (-1); 1480 } 1481 sa = (struct pfsync_state *)(mp->m_data + offp); 1482 1483 s = splsoftnet(); 1484#ifdef __FreeBSD__ 1485 PF_LOCK(); 1486#endif 1487 for (i = 0; i < count; i++) { 1488 sp = &sa[i]; 1489 1490 bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1491 id_key.creatorid = sp->creatorid; 1492 1493 st = pf_find_state_byid(&id_key); 1494 if (st == NULL) { 1495 V_pfsyncstats.pfsyncs_badstate++; 1496 continue; 1497 } 1498 SET(st->state_flags, PFSTATE_NOSYNC); 1499 pf_unlink_state(st); 1500 } 1501#ifdef __FreeBSD__ 1502 PF_UNLOCK(); 1503#endif 1504 splx(s); 1505 1506 return (len); 1507} 1508 1509int 1510pfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1511{ 1512 struct mbuf *mp; 1513 struct pfsync_del_c *sa, *sp; 1514 struct pf_state_cmp id_key; 1515 struct pf_state *st; 1516 int len = count * sizeof(*sp); 1517 int offp, i; 1518 int s; 1519 1520 mp = m_pulldown(m, offset, len, &offp); 1521 if (mp == NULL) { 1522 V_pfsyncstats.pfsyncs_badlen++; 1523 return (-1); 1524 } 1525 sa = (struct pfsync_del_c *)(mp->m_data + offp); 1526 1527 s = splsoftnet(); 1528#ifdef __FreeBSD__ 1529 PF_LOCK(); 1530#endif 1531 for (i = 0; i < count; i++) { 1532 sp = &sa[i]; 1533 1534 bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); 1535 id_key.creatorid = sp->creatorid; 1536 1537 st = pf_find_state_byid(&id_key); 1538 if (st == NULL) { 1539 V_pfsyncstats.pfsyncs_badstate++; 1540 continue; 1541 } 1542 1543 SET(st->state_flags, PFSTATE_NOSYNC); 1544 pf_unlink_state(st); 1545 } 1546#ifdef __FreeBSD__ 1547 PF_UNLOCK(); 1548#endif 1549 splx(s); 1550 1551 return (len); 1552} 1553 1554int 1555pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1556{ 1557#ifdef __FreeBSD__ 1558 struct pfsync_softc *sc = V_pfsyncif; 1559#else 1560 struct pfsync_softc *sc = pfsyncif; 1561#endif 1562 struct pfsync_bus *bus; 1563 struct mbuf *mp; 1564 int len = count * sizeof(*bus); 1565 int offp; 1566 1567 /* If we're not waiting for a bulk update, who cares. */ 1568 if (sc->sc_ureq_sent == 0) 1569 return (len); 1570 1571 mp = m_pulldown(m, offset, len, &offp); 1572 if (mp == NULL) { 1573 V_pfsyncstats.pfsyncs_badlen++; 1574 return (-1); 1575 } 1576 bus = (struct pfsync_bus *)(mp->m_data + offp); 1577 1578 switch (bus->status) { 1579 case PFSYNC_BUS_START: 1580#ifdef __FreeBSD__ 1581 callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 1582 V_pf_pool_limits[PF_LIMIT_STATES].limit / 1583 ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 1584 sizeof(struct pfsync_state)), 1585 pfsync_bulk_fail, V_pfsyncif); 1586#else 1587 timeout_add(&sc->sc_bulkfail_tmo, 4 * hz + 1588 pf_pool_limits[PF_LIMIT_STATES].limit / 1589 ((sc->sc_if.if_mtu - PFSYNC_MINPKT) / 1590 sizeof(struct pfsync_state))); 1591#endif 1592#ifdef __FreeBSD__ 1593 if (V_pf_status.debug >= PF_DEBUG_MISC) 1594#else 1595 if (pf_status.debug >= PF_DEBUG_MISC) 1596#endif 1597 printf("pfsync: received bulk update start\n"); 1598 break; 1599 1600 case PFSYNC_BUS_END: 1601 if (time_uptime - ntohl(bus->endtime) >= 1602 sc->sc_ureq_sent) { 1603 /* that's it, we're happy */ 1604 sc->sc_ureq_sent = 0; 1605 sc->sc_bulk_tries = 0; 1606 timeout_del(&sc->sc_bulkfail_tmo); 1607#ifdef __FreeBSD__ 1608 if (!sc->pfsync_sync_ok && carp_demote_adj_p) 1609 (*carp_demote_adj_p)(-V_pfsync_carp_adj, 1610 "pfsync bulk done"); 1611 sc->pfsync_sync_ok = 1; 1612#else 1613#if NCARP > 0 1614 if (!pfsync_sync_ok) 1615 carp_group_demote_adj(&sc->sc_if, -1); 1616#endif 1617 pfsync_sync_ok = 1; 1618#endif 1619#ifdef __FreeBSD__ 1620 if (V_pf_status.debug >= PF_DEBUG_MISC) 1621#else 1622 if (pf_status.debug >= PF_DEBUG_MISC) 1623#endif 1624 printf("pfsync: received valid " 1625 "bulk update end\n"); 1626 } else { 1627#ifdef __FreeBSD__ 1628 if (V_pf_status.debug >= PF_DEBUG_MISC) 1629#else 1630 if (pf_status.debug >= PF_DEBUG_MISC) 1631#endif 1632 printf("pfsync: received invalid " 1633 "bulk update end: bad timestamp\n"); 1634 } 1635 break; 1636 } 1637 1638 return (len); 1639} 1640 1641int 1642pfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1643{ 1644 int len = count * sizeof(struct pfsync_tdb); 1645 1646#if defined(IPSEC) 1647 struct pfsync_tdb *tp; 1648 struct mbuf *mp; 1649 int offp; 1650 int i; 1651 int s; 1652 1653 mp = m_pulldown(m, offset, len, &offp); 1654 if (mp == NULL) { 1655 V_pfsyncstats.pfsyncs_badlen++; 1656 return (-1); 1657 } 1658 tp = (struct pfsync_tdb *)(mp->m_data + offp); 1659 1660 s = splsoftnet(); 1661#ifdef __FreeBSD__ 1662 PF_LOCK(); 1663#endif 1664 for (i = 0; i < count; i++) 1665 pfsync_update_net_tdb(&tp[i]); 1666#ifdef __FreeBSD__ 1667 PF_UNLOCK(); 1668#endif 1669 splx(s); 1670#endif 1671 1672 return (len); 1673} 1674 1675#if defined(IPSEC) 1676/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1677void 1678pfsync_update_net_tdb(struct pfsync_tdb *pt) 1679{ 1680 struct tdb *tdb; 1681 int s; 1682 1683 /* check for invalid values */ 1684 if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1685 (pt->dst.sa.sa_family != AF_INET && 1686 pt->dst.sa.sa_family != AF_INET6)) 1687 goto bad; 1688 1689 s = spltdb(); 1690 tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1691 if (tdb) { 1692 pt->rpl = ntohl(pt->rpl); 1693 pt->cur_bytes = betoh64(pt->cur_bytes); 1694 1695 /* Neither replay nor byte counter should ever decrease. */ 1696 if (pt->rpl < tdb->tdb_rpl || 1697 pt->cur_bytes < tdb->tdb_cur_bytes) { 1698 splx(s); 1699 goto bad; 1700 } 1701 1702 tdb->tdb_rpl = pt->rpl; 1703 tdb->tdb_cur_bytes = pt->cur_bytes; 1704 } 1705 splx(s); 1706 return; 1707 1708bad: 1709#ifdef __FreeBSD__ 1710 if (V_pf_status.debug >= PF_DEBUG_MISC) 1711#else 1712 if (pf_status.debug >= PF_DEBUG_MISC) 1713#endif 1714 printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1715 "invalid value\n"); 1716 V_pfsyncstats.pfsyncs_badstate++; 1717 return; 1718} 1719#endif 1720 1721 1722int 1723pfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1724{ 1725 /* check if we are at the right place in the packet */ 1726 if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) 1727 V_pfsyncstats.pfsyncs_badact++; 1728 1729 /* we're done. free and let the caller return */ 1730 m_freem(m); 1731 return (-1); 1732} 1733 1734int 1735pfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1736{ 1737 V_pfsyncstats.pfsyncs_badact++; 1738 1739 m_freem(m); 1740 return (-1); 1741} 1742 1743int 1744pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1745#ifdef __FreeBSD__ 1746 struct route *rt) 1747#else 1748 struct rtentry *rt) 1749#endif 1750{ 1751 m_freem(m); 1752 return (0); 1753} 1754 1755/* ARGSUSED */ 1756int 1757pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1758{ 1759#ifndef __FreeBSD__ 1760 struct proc *p = curproc; 1761#endif 1762 struct pfsync_softc *sc = ifp->if_softc; 1763 struct ifreq *ifr = (struct ifreq *)data; 1764 struct ip_moptions *imo = &sc->sc_imo; 1765 struct pfsyncreq pfsyncr; 1766 struct ifnet *sifp; 1767 struct ip *ip; 1768 int s, error; 1769 1770 switch (cmd) { 1771#if 0 1772 case SIOCSIFADDR: 1773 case SIOCAIFADDR: 1774 case SIOCSIFDSTADDR: 1775#endif 1776 case SIOCSIFFLAGS: 1777#ifdef __FreeBSD__ 1778 if (ifp->if_flags & IFF_UP) 1779 ifp->if_drv_flags |= IFF_DRV_RUNNING; 1780 else 1781 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1782#else 1783 if (ifp->if_flags & IFF_UP) 1784 ifp->if_flags |= IFF_RUNNING; 1785 else 1786 ifp->if_flags &= ~IFF_RUNNING; 1787#endif 1788 break; 1789 case SIOCSIFMTU: 1790 if (!sc->sc_sync_if || 1791 ifr->ifr_mtu <= PFSYNC_MINPKT || 1792 ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 1793 return (EINVAL); 1794 if (ifr->ifr_mtu < ifp->if_mtu) { 1795 s = splnet(); 1796#ifdef __FreeBSD__ 1797 PF_LOCK(); 1798#endif 1799 pfsync_sendout(); 1800#ifdef __FreeBSD__ 1801 PF_UNLOCK(); 1802#endif 1803 splx(s); 1804 } 1805 ifp->if_mtu = ifr->ifr_mtu; 1806 break; 1807 case SIOCGETPFSYNC: 1808 bzero(&pfsyncr, sizeof(pfsyncr)); 1809 if (sc->sc_sync_if) { 1810 strlcpy(pfsyncr.pfsyncr_syncdev, 1811 sc->sc_sync_if->if_xname, IFNAMSIZ); 1812 } 1813 pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1814 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1815 return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1816 1817 case SIOCSETPFSYNC: 1818#ifdef __FreeBSD__ 1819 if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1820#else 1821 if ((error = suser(p, p->p_acflag)) != 0) 1822#endif 1823 return (error); 1824 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1825 return (error); 1826 1827#ifdef __FreeBSD__ 1828 PF_LOCK(); 1829#endif 1830 if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1831#ifdef __FreeBSD__ 1832 sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1833#else 1834 sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1835#endif 1836 else 1837 sc->sc_sync_peer.s_addr = 1838 pfsyncr.pfsyncr_syncpeer.s_addr; 1839 1840 if (pfsyncr.pfsyncr_maxupdates > 255) 1841#ifdef __FreeBSD__ 1842 { 1843 PF_UNLOCK(); 1844#endif 1845 return (EINVAL); 1846#ifdef __FreeBSD__ 1847 } 1848#endif 1849 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1850 1851 if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1852 sc->sc_sync_if = NULL; 1853#ifdef __FreeBSD__ 1854 PF_UNLOCK(); 1855 if (imo->imo_membership) 1856 pfsync_multicast_cleanup(sc); 1857#else 1858 if (imo->imo_num_memberships > 0) { 1859 in_delmulti(imo->imo_membership[ 1860 --imo->imo_num_memberships]); 1861 imo->imo_multicast_ifp = NULL; 1862 } 1863#endif 1864 break; 1865 } 1866 1867#ifdef __FreeBSD__ 1868 PF_UNLOCK(); 1869#endif 1870 if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1871 return (EINVAL); 1872 1873#ifdef __FreeBSD__ 1874 PF_LOCK(); 1875#endif 1876 s = splnet(); 1877#ifdef __FreeBSD__ 1878 if (sifp->if_mtu < sc->sc_ifp->if_mtu || 1879#else 1880 if (sifp->if_mtu < sc->sc_if.if_mtu || 1881#endif 1882 (sc->sc_sync_if != NULL && 1883 sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1884 sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1885 pfsync_sendout(); 1886 sc->sc_sync_if = sifp; 1887 1888#ifdef __FreeBSD__ 1889 if (imo->imo_membership) { 1890 PF_UNLOCK(); 1891 pfsync_multicast_cleanup(sc); 1892 PF_LOCK(); 1893 } 1894#else 1895 if (imo->imo_num_memberships > 0) { 1896 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1897 imo->imo_multicast_ifp = NULL; 1898 } 1899#endif 1900 1901#ifdef __FreeBSD__ 1902 if (sc->sc_sync_if && 1903 sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1904 PF_UNLOCK(); 1905 error = pfsync_multicast_setup(sc); 1906 if (error) 1907 return (error); 1908 PF_LOCK(); 1909 } 1910#else 1911 if (sc->sc_sync_if && 1912 sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1913 struct in_addr addr; 1914 1915 if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1916 sc->sc_sync_if = NULL; 1917 splx(s); 1918 return (EADDRNOTAVAIL); 1919 } 1920 1921 addr.s_addr = INADDR_PFSYNC_GROUP; 1922 1923 if ((imo->imo_membership[0] = 1924 in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1925 sc->sc_sync_if = NULL; 1926 splx(s); 1927 return (ENOBUFS); 1928 } 1929 imo->imo_num_memberships++; 1930 imo->imo_multicast_ifp = sc->sc_sync_if; 1931 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1932 imo->imo_multicast_loop = 0; 1933 } 1934#endif /* !__FreeBSD__ */ 1935 1936 ip = &sc->sc_template; 1937 bzero(ip, sizeof(*ip)); 1938 ip->ip_v = IPVERSION; 1939 ip->ip_hl = sizeof(sc->sc_template) >> 2; 1940 ip->ip_tos = IPTOS_LOWDELAY; 1941 /* len and id are set later */ 1942#ifdef __FreeBSD__ 1943 ip->ip_off = IP_DF; 1944#else 1945 ip->ip_off = htons(IP_DF); 1946#endif 1947 ip->ip_ttl = PFSYNC_DFLTTL; 1948 ip->ip_p = IPPROTO_PFSYNC; 1949 ip->ip_src.s_addr = INADDR_ANY; 1950 ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1951 1952 if (sc->sc_sync_if) { 1953 /* Request a full state table update. */ 1954 sc->sc_ureq_sent = time_uptime; 1955#ifdef __FreeBSD__ 1956 if (sc->pfsync_sync_ok && carp_demote_adj_p) 1957 (*carp_demote_adj_p)(V_pfsync_carp_adj, 1958 "pfsync bulk start"); 1959 sc->pfsync_sync_ok = 0; 1960#else 1961#if NCARP > 0 1962 if (pfsync_sync_ok) 1963 carp_group_demote_adj(&sc->sc_if, 1); 1964#endif 1965 pfsync_sync_ok = 0; 1966#endif 1967#ifdef __FreeBSD__ 1968 if (V_pf_status.debug >= PF_DEBUG_MISC) 1969#else 1970 if (pf_status.debug >= PF_DEBUG_MISC) 1971#endif 1972 printf("pfsync: requesting bulk update\n"); 1973#ifdef __FreeBSD__ 1974 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1975 pfsync_bulk_fail, V_pfsyncif); 1976#else 1977 timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 1978#endif 1979 pfsync_request_update(0, 0); 1980 } 1981#ifdef __FreeBSD__ 1982 PF_UNLOCK(); 1983#endif 1984 splx(s); 1985 1986 break; 1987 1988 default: 1989 return (ENOTTY); 1990 } 1991 1992 return (0); 1993} 1994 1995int 1996pfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) 1997{ 1998 struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); 1999 2000 pfsync_state_export(sp, st); 2001 2002 return (sizeof(*sp)); 2003} 2004 2005int 2006pfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) 2007{ 2008 struct pfsync_ins_ack *iack = 2009 (struct pfsync_ins_ack *)(m->m_data + offset); 2010 2011 iack->id = st->id; 2012 iack->creatorid = st->creatorid; 2013 2014 return (sizeof(*iack)); 2015} 2016 2017int 2018pfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) 2019{ 2020 struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); 2021 2022 up->id = st->id; 2023 pf_state_peer_hton(&st->src, &up->src); 2024 pf_state_peer_hton(&st->dst, &up->dst); 2025 up->creatorid = st->creatorid; 2026 2027 up->expire = pf_state_expires(st); 2028 if (up->expire <= time_second) 2029 up->expire = htonl(0); 2030 else 2031 up->expire = htonl(up->expire - time_second); 2032 up->timeout = st->timeout; 2033 2034 bzero(up->_pad, sizeof(up->_pad)); /* XXX */ 2035 2036 return (sizeof(*up)); 2037} 2038 2039int 2040pfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) 2041{ 2042 struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); 2043 2044 dp->id = st->id; 2045 dp->creatorid = st->creatorid; 2046 2047 SET(st->state_flags, PFSTATE_NOSYNC); 2048 2049 return (sizeof(*dp)); 2050} 2051 2052void 2053pfsync_drop(struct pfsync_softc *sc) 2054{ 2055 struct pf_state *st; 2056 struct pfsync_upd_req_item *ur; 2057#ifdef notyet 2058 struct tdb *t; 2059#endif 2060 int q; 2061 2062 for (q = 0; q < PFSYNC_S_COUNT; q++) { 2063 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2064 continue; 2065 2066 TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2067#ifdef PFSYNC_DEBUG 2068#ifdef __FreeBSD__ 2069 KASSERT(st->sync_state == q, 2070 ("%s: st->sync_state == q", 2071 __FUNCTION__)); 2072#else 2073 KASSERT(st->sync_state == q); 2074#endif 2075#endif 2076 st->sync_state = PFSYNC_S_NONE; 2077 } 2078 TAILQ_INIT(&sc->sc_qs[q]); 2079 } 2080 2081 while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2082 TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2083 pool_put(&sc->sc_pool, ur); 2084 } 2085 2086 sc->sc_plus = NULL; 2087 2088#ifdef notyet 2089 if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2090 TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) 2091 CLR(t->tdb_flags, TDBF_PFSYNC); 2092 2093 TAILQ_INIT(&sc->sc_tdb_q); 2094 } 2095#endif 2096 2097 sc->sc_len = PFSYNC_MINPKT; 2098} 2099 2100void 2101pfsync_sendout(void) 2102{ 2103#ifdef __FreeBSD__ 2104 struct pfsync_softc *sc = V_pfsyncif; 2105#else 2106 struct pfsync_softc *sc = pfsyncif; 2107#endif 2108#if NBPFILTER > 0 2109#ifdef __FreeBSD__ 2110 struct ifnet *ifp = sc->sc_ifp; 2111#else 2112 struct ifnet *ifp = &sc->sc_if; 2113#endif 2114#endif 2115 struct mbuf *m; 2116 struct ip *ip; 2117 struct pfsync_header *ph; 2118 struct pfsync_subheader *subh; 2119 struct pf_state *st; 2120 struct pfsync_upd_req_item *ur; 2121#ifdef notyet 2122 struct tdb *t; 2123#endif 2124#ifdef __FreeBSD__ 2125 size_t pktlen; 2126 int dummy_error; 2127#endif 2128 int offset; 2129 int q, count = 0; 2130 2131#ifdef __FreeBSD__ 2132 PF_LOCK_ASSERT(); 2133#else 2134 splassert(IPL_NET); 2135#endif 2136 2137 if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) 2138 return; 2139 2140#if NBPFILTER > 0 2141 if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 2142#else 2143 if (sc->sc_sync_if == NULL) { 2144#endif 2145 pfsync_drop(sc); 2146 return; 2147 } 2148 2149 MGETHDR(m, M_DONTWAIT, MT_DATA); 2150 if (m == NULL) { 2151#ifdef __FreeBSD__ 2152 sc->sc_ifp->if_oerrors++; 2153#else 2154 sc->sc_if.if_oerrors++; 2155#endif 2156 V_pfsyncstats.pfsyncs_onomem++; 2157 pfsync_drop(sc); 2158 return; 2159 } 2160 2161#ifdef __FreeBSD__ 2162 pktlen = max_linkhdr + sc->sc_len; 2163 if (pktlen > MHLEN) { 2164 /* Find the right pool to allocate from. */ 2165 /* XXX: This is ugly. */ 2166 m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE : 2167 pktlen <= MCLBYTES ? MCLBYTES : 2168#if MJUMPAGESIZE != MCLBYTES 2169 pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE : 2170#endif 2171 pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 2172#else 2173 if (max_linkhdr + sc->sc_len > MHLEN) { 2174 MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); 2175#endif 2176 if (!ISSET(m->m_flags, M_EXT)) { 2177 m_free(m); 2178#ifdef __FreeBSD__ 2179 sc->sc_ifp->if_oerrors++; 2180#else 2181 sc->sc_if.if_oerrors++; 2182#endif 2183 V_pfsyncstats.pfsyncs_onomem++; 2184 pfsync_drop(sc); 2185 return; 2186 } 2187 } 2188 m->m_data += max_linkhdr; 2189 m->m_len = m->m_pkthdr.len = sc->sc_len; 2190 2191 /* build the ip header */ 2192 ip = (struct ip *)m->m_data; 2193 bcopy(&sc->sc_template, ip, sizeof(*ip)); 2194 offset = sizeof(*ip); 2195 2196#ifdef __FreeBSD__ 2197 ip->ip_len = m->m_pkthdr.len; 2198#else 2199 ip->ip_len = htons(m->m_pkthdr.len); 2200#endif 2201 ip->ip_id = htons(ip_randomid()); 2202 2203 /* build the pfsync header */ 2204 ph = (struct pfsync_header *)(m->m_data + offset); 2205 bzero(ph, sizeof(*ph)); 2206 offset += sizeof(*ph); 2207 2208 ph->version = PFSYNC_VERSION; 2209 ph->len = htons(sc->sc_len - sizeof(*ip)); 2210#ifdef __FreeBSD__ 2211 bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2212#else 2213 bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2214#endif 2215 2216 /* walk the queues */ 2217 for (q = 0; q < PFSYNC_S_COUNT; q++) { 2218 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2219 continue; 2220 2221 subh = (struct pfsync_subheader *)(m->m_data + offset); 2222 offset += sizeof(*subh); 2223 2224 count = 0; 2225 TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2226#ifdef PFSYNC_DEBUG 2227#ifdef __FreeBSD__ 2228 KASSERT(st->sync_state == q, 2229 ("%s: st->sync_state == q", 2230 __FUNCTION__)); 2231#else 2232 KASSERT(st->sync_state == q); 2233#endif 2234#endif 2235 2236 offset += pfsync_qs[q].write(st, m, offset); 2237 st->sync_state = PFSYNC_S_NONE; 2238 count++; 2239 } 2240 TAILQ_INIT(&sc->sc_qs[q]); 2241 2242 bzero(subh, sizeof(*subh)); 2243 subh->action = pfsync_qs[q].action; 2244 subh->count = htons(count); 2245 } 2246 2247 if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 2248 subh = (struct pfsync_subheader *)(m->m_data + offset); 2249 offset += sizeof(*subh); 2250 2251 count = 0; 2252 while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2253 TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2254 2255 bcopy(&ur->ur_msg, m->m_data + offset, 2256 sizeof(ur->ur_msg)); 2257 offset += sizeof(ur->ur_msg); 2258 2259 pool_put(&sc->sc_pool, ur); 2260 2261 count++; 2262 } 2263 2264 bzero(subh, sizeof(*subh)); 2265 subh->action = PFSYNC_ACT_UPD_REQ; 2266 subh->count = htons(count); 2267 } 2268 2269 /* has someone built a custom region for us to add? */ 2270 if (sc->sc_plus != NULL) { 2271 bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 2272 offset += sc->sc_pluslen; 2273 2274 sc->sc_plus = NULL; 2275 } 2276 2277#ifdef notyet 2278 if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2279 subh = (struct pfsync_subheader *)(m->m_data + offset); 2280 offset += sizeof(*subh); 2281 2282 count = 0; 2283 TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { 2284 offset += pfsync_out_tdb(t, m, offset); 2285 CLR(t->tdb_flags, TDBF_PFSYNC); 2286 2287 count++; 2288 } 2289 TAILQ_INIT(&sc->sc_tdb_q); 2290 2291 bzero(subh, sizeof(*subh)); 2292 subh->action = PFSYNC_ACT_TDB; 2293 subh->count = htons(count); 2294 } 2295#endif 2296 2297 subh = (struct pfsync_subheader *)(m->m_data + offset); 2298 offset += sizeof(*subh); 2299 2300 bzero(subh, sizeof(*subh)); 2301 subh->action = PFSYNC_ACT_EOF; 2302 subh->count = htons(1); 2303 2304 /* XXX write checksum in EOF here */ 2305 2306 /* we're done, let's put it on the wire */ 2307#if NBPFILTER > 0 2308 if (ifp->if_bpf) { 2309 m->m_data += sizeof(*ip); 2310 m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 2311#ifdef __FreeBSD__ 2312 BPF_MTAP(ifp, m); 2313#else 2314 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 2315#endif 2316 m->m_data -= sizeof(*ip); 2317 m->m_len = m->m_pkthdr.len = sc->sc_len; 2318 } 2319 2320 if (sc->sc_sync_if == NULL) { 2321 sc->sc_len = PFSYNC_MINPKT; 2322 m_freem(m); 2323 return; 2324 } 2325#endif 2326 2327#ifdef __FreeBSD__ 2328 sc->sc_ifp->if_opackets++; 2329 sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2330 sc->sc_len = PFSYNC_MINPKT; 2331 2332 IFQ_ENQUEUE(&sc->sc_ifp->if_snd, m, dummy_error); 2333 swi_sched(V_pfsync_swi_cookie, 0); 2334#else 2335 sc->sc_if.if_opackets++; 2336 sc->sc_if.if_obytes += m->m_pkthdr.len; 2337 2338 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2339 pfsyncstats.pfsyncs_opackets++; 2340 else 2341 pfsyncstats.pfsyncs_oerrors++; 2342 2343 /* start again */ 2344 sc->sc_len = PFSYNC_MINPKT; 2345#endif 2346} 2347 2348void 2349pfsync_insert_state(struct pf_state *st) 2350{ 2351#ifdef __FreeBSD__ 2352 struct pfsync_softc *sc = V_pfsyncif; 2353#else 2354 struct pfsync_softc *sc = pfsyncif; 2355#endif 2356 2357#ifdef __FreeBSD__ 2358 PF_LOCK_ASSERT(); 2359#else 2360 splassert(IPL_SOFTNET); 2361#endif 2362 2363 if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || 2364 st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 2365 SET(st->state_flags, PFSTATE_NOSYNC); 2366 return; 2367 } 2368 2369 if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) 2370 return; 2371 2372#ifdef PFSYNC_DEBUG 2373#ifdef __FreeBSD__ 2374 KASSERT(st->sync_state == PFSYNC_S_NONE, 2375 ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2376#else 2377 KASSERT(st->sync_state == PFSYNC_S_NONE); 2378#endif 2379#endif 2380 2381 if (sc->sc_len == PFSYNC_MINPKT) 2382#ifdef __FreeBSD__ 2383 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2384 V_pfsyncif); 2385#else 2386 timeout_add_sec(&sc->sc_tmo, 1); 2387#endif 2388 2389 pfsync_q_ins(st, PFSYNC_S_INS); 2390 2391 if (ISSET(st->state_flags, PFSTATE_ACK)) 2392#ifdef __FreeBSD__ 2393 pfsync_sendout(); 2394#else 2395 schednetisr(NETISR_PFSYNC); 2396#endif 2397 else 2398 st->sync_updates = 0; 2399} 2400 2401int defer = 10; 2402 2403int 2404pfsync_defer(struct pf_state *st, struct mbuf *m) 2405{ 2406#ifdef __FreeBSD__ 2407 struct pfsync_softc *sc = V_pfsyncif; 2408#else 2409 struct pfsync_softc *sc = pfsyncif; 2410#endif 2411 struct pfsync_deferral *pd; 2412 2413#ifdef __FreeBSD__ 2414 PF_LOCK_ASSERT(); 2415#else 2416 splassert(IPL_SOFTNET); 2417#endif 2418 2419 if (sc->sc_deferred >= 128) 2420 pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 2421 2422 pd = pool_get(&sc->sc_pool, M_NOWAIT); 2423 if (pd == NULL) 2424 return (0); 2425 sc->sc_deferred++; 2426 2427#ifdef __FreeBSD__ 2428 m->m_flags |= M_SKIP_FIREWALL; 2429#else 2430 m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2431#endif 2432 SET(st->state_flags, PFSTATE_ACK); 2433 2434 pd->pd_st = st; 2435 pd->pd_m = m; 2436 2437 TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 2438#ifdef __FreeBSD__ 2439 callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); 2440 callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, 2441 pd); 2442#else 2443 timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); 2444 timeout_add(&pd->pd_tmo, defer); 2445#endif 2446 2447 return (1); 2448} 2449 2450void 2451pfsync_undefer(struct pfsync_deferral *pd, int drop) 2452{ 2453#ifdef __FreeBSD__ 2454 struct pfsync_softc *sc = V_pfsyncif; 2455#else 2456 struct pfsync_softc *sc = pfsyncif; 2457#endif 2458 int s; 2459 2460#ifdef __FreeBSD__ 2461 PF_LOCK_ASSERT(); 2462#else 2463 splassert(IPL_SOFTNET); 2464#endif 2465 2466 TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 2467 sc->sc_deferred--; 2468 2469 CLR(pd->pd_st->state_flags, PFSTATE_ACK); 2470 timeout_del(&pd->pd_tmo); /* bah */ 2471 if (drop) 2472 m_freem(pd->pd_m); 2473 else { 2474 s = splnet(); 2475#ifdef __FreeBSD__ 2476 /* XXX: use pf_defered?! */ 2477 PF_UNLOCK(); 2478#endif 2479 ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, 2480 (void *)NULL, (void *)NULL); 2481#ifdef __FreeBSD__ 2482 PF_LOCK(); 2483#endif 2484 splx(s); 2485 } 2486 2487 pool_put(&sc->sc_pool, pd); 2488} 2489 2490void 2491pfsync_defer_tmo(void *arg) 2492{ 2493#if defined(__FreeBSD__) && defined(VIMAGE) 2494 struct pfsync_deferral *pd = arg; 2495#endif 2496 int s; 2497 2498 s = splsoftnet(); 2499#ifdef __FreeBSD__ 2500 CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ 2501 PF_LOCK(); 2502#endif 2503 pfsync_undefer(arg, 0); 2504#ifdef __FreeBSD__ 2505 PF_UNLOCK(); 2506 CURVNET_RESTORE(); 2507#endif 2508 splx(s); 2509} 2510 2511void 2512pfsync_deferred(struct pf_state *st, int drop) 2513{ 2514#ifdef __FreeBSD__ 2515 struct pfsync_softc *sc = V_pfsyncif; 2516#else 2517 struct pfsync_softc *sc = pfsyncif; 2518#endif 2519 struct pfsync_deferral *pd; 2520 2521 TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 2522 if (pd->pd_st == st) { 2523 pfsync_undefer(pd, drop); 2524 return; 2525 } 2526 } 2527 2528 panic("pfsync_send_deferred: unable to find deferred state"); 2529} 2530 2531u_int pfsync_upds = 0; 2532 2533void 2534pfsync_update_state(struct pf_state *st) 2535{ 2536#ifdef __FreeBSD__ 2537 struct pfsync_softc *sc = V_pfsyncif; 2538#else 2539 struct pfsync_softc *sc = pfsyncif; 2540#endif 2541 int sync = 0; 2542 2543#ifdef __FreeBSD__ 2544 PF_LOCK_ASSERT(); 2545#else 2546 splassert(IPL_SOFTNET); 2547#endif 2548 2549 if (sc == NULL) 2550 return; 2551 2552 if (ISSET(st->state_flags, PFSTATE_ACK)) 2553 pfsync_deferred(st, 0); 2554 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2555 if (st->sync_state != PFSYNC_S_NONE) 2556 pfsync_q_del(st); 2557 return; 2558 } 2559 2560 if (sc->sc_len == PFSYNC_MINPKT) 2561#ifdef __FreeBSD__ 2562 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2563 V_pfsyncif); 2564#else 2565 timeout_add_sec(&sc->sc_tmo, 1); 2566#endif 2567 2568 switch (st->sync_state) { 2569 case PFSYNC_S_UPD_C: 2570 case PFSYNC_S_UPD: 2571 case PFSYNC_S_INS: 2572 /* we're already handling it */ 2573 2574 if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 2575 st->sync_updates++; 2576 if (st->sync_updates >= sc->sc_maxupdates) 2577 sync = 1; 2578 } 2579 break; 2580 2581 case PFSYNC_S_IACK: 2582 pfsync_q_del(st); 2583 case PFSYNC_S_NONE: 2584 pfsync_q_ins(st, PFSYNC_S_UPD_C); 2585 st->sync_updates = 0; 2586 break; 2587 2588 default: 2589 panic("pfsync_update_state: unexpected sync state %d", 2590 st->sync_state); 2591 } 2592 2593 if (sync || (time_uptime - st->pfsync_time) < 2) { 2594 pfsync_upds++; 2595#ifdef __FreeBSD__ 2596 pfsync_sendout(); 2597#else 2598 schednetisr(NETISR_PFSYNC); 2599#endif 2600 } 2601} 2602 2603void 2604pfsync_request_update(u_int32_t creatorid, u_int64_t id) 2605{ 2606#ifdef __FreeBSD__ 2607 struct pfsync_softc *sc = V_pfsyncif; 2608#else 2609 struct pfsync_softc *sc = pfsyncif; 2610#endif 2611 struct pfsync_upd_req_item *item; 2612 size_t nlen = sizeof(struct pfsync_upd_req); 2613 int s; 2614 2615 PF_LOCK_ASSERT(); 2616 2617 /* 2618 * this code does nothing to prevent multiple update requests for the 2619 * same state being generated. 2620 */ 2621 2622 item = pool_get(&sc->sc_pool, PR_NOWAIT); 2623 if (item == NULL) { 2624 /* XXX stats */ 2625 return; 2626 } 2627 2628 item->ur_msg.id = id; 2629 item->ur_msg.creatorid = creatorid; 2630 2631 if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 2632 nlen += sizeof(struct pfsync_subheader); 2633 2634#ifdef __FreeBSD__ 2635 if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2636#else 2637 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2638#endif 2639 s = splnet(); 2640 pfsync_sendout(); 2641 splx(s); 2642 2643 nlen = sizeof(struct pfsync_subheader) + 2644 sizeof(struct pfsync_upd_req); 2645 } 2646 2647 TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 2648 sc->sc_len += nlen; 2649 2650#ifdef __FreeBSD__ 2651 pfsync_sendout(); 2652#else 2653 schednetisr(NETISR_PFSYNC); 2654#endif 2655} 2656 2657void 2658pfsync_update_state_req(struct pf_state *st) 2659{ 2660#ifdef __FreeBSD__ 2661 struct pfsync_softc *sc = V_pfsyncif; 2662#else 2663 struct pfsync_softc *sc = pfsyncif; 2664#endif 2665 2666 PF_LOCK_ASSERT(); 2667 2668 if (sc == NULL) 2669 panic("pfsync_update_state_req: nonexistant instance"); 2670 2671 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2672 if (st->sync_state != PFSYNC_S_NONE) 2673 pfsync_q_del(st); 2674 return; 2675 } 2676 2677 switch (st->sync_state) { 2678 case PFSYNC_S_UPD_C: 2679 case PFSYNC_S_IACK: 2680 pfsync_q_del(st); 2681 case PFSYNC_S_NONE: 2682 pfsync_q_ins(st, PFSYNC_S_UPD); 2683#ifdef __FreeBSD__ 2684 pfsync_sendout(); 2685#else 2686 schednetisr(NETISR_PFSYNC); 2687#endif 2688 return; 2689 2690 case PFSYNC_S_INS: 2691 case PFSYNC_S_UPD: 2692 case PFSYNC_S_DEL: 2693 /* we're already handling it */ 2694 return; 2695 2696 default: 2697 panic("pfsync_update_state_req: unexpected sync state %d", 2698 st->sync_state); 2699 } 2700} 2701 2702void 2703pfsync_delete_state(struct pf_state *st) 2704{ 2705#ifdef __FreeBSD__ 2706 struct pfsync_softc *sc = V_pfsyncif; 2707#else 2708 struct pfsync_softc *sc = pfsyncif; 2709#endif 2710 2711#ifdef __FreeBSD__ 2712 PF_LOCK_ASSERT(); 2713#else 2714 splassert(IPL_SOFTNET); 2715#endif 2716 2717 if (sc == NULL) 2718 return; 2719 2720 if (ISSET(st->state_flags, PFSTATE_ACK)) 2721 pfsync_deferred(st, 1); 2722 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2723 if (st->sync_state != PFSYNC_S_NONE) 2724 pfsync_q_del(st); 2725 return; 2726 } 2727 2728 if (sc->sc_len == PFSYNC_MINPKT) 2729#ifdef __FreeBSD__ 2730 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2731 V_pfsyncif); 2732#else 2733 timeout_add_sec(&sc->sc_tmo, 1); 2734#endif 2735 2736 switch (st->sync_state) { 2737 case PFSYNC_S_INS: 2738 /* we never got to tell the world so just forget about it */ 2739 pfsync_q_del(st); 2740 return; 2741 2742 case PFSYNC_S_UPD_C: 2743 case PFSYNC_S_UPD: 2744 case PFSYNC_S_IACK: 2745 pfsync_q_del(st); 2746 /* FALLTHROUGH to putting it on the del list */ 2747 2748 case PFSYNC_S_NONE: 2749 pfsync_q_ins(st, PFSYNC_S_DEL); 2750 return; 2751 2752 default: 2753 panic("pfsync_delete_state: unexpected sync state %d", 2754 st->sync_state); 2755 } 2756} 2757 2758void 2759pfsync_clear_states(u_int32_t creatorid, const char *ifname) 2760{ 2761 struct { 2762 struct pfsync_subheader subh; 2763 struct pfsync_clr clr; 2764 } __packed r; 2765 2766#ifdef __FreeBSD__ 2767 struct pfsync_softc *sc = V_pfsyncif; 2768#else 2769 struct pfsync_softc *sc = pfsyncif; 2770#endif 2771 2772#ifdef __FreeBSD__ 2773 PF_LOCK_ASSERT(); 2774#else 2775 splassert(IPL_SOFTNET); 2776#endif 2777 2778 if (sc == NULL) 2779 return; 2780 2781 bzero(&r, sizeof(r)); 2782 2783 r.subh.action = PFSYNC_ACT_CLR; 2784 r.subh.count = htons(1); 2785 2786 strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 2787 r.clr.creatorid = creatorid; 2788 2789 pfsync_send_plus(&r, sizeof(r)); 2790} 2791 2792void 2793pfsync_q_ins(struct pf_state *st, int q) 2794{ 2795#ifdef __FreeBSD__ 2796 struct pfsync_softc *sc = V_pfsyncif; 2797#else 2798 struct pfsync_softc *sc = pfsyncif; 2799#endif 2800 size_t nlen = pfsync_qs[q].len; 2801 int s; 2802 2803 PF_LOCK_ASSERT(); 2804 2805#ifdef __FreeBSD__ 2806 KASSERT(st->sync_state == PFSYNC_S_NONE, 2807 ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2808#else 2809 KASSERT(st->sync_state == PFSYNC_S_NONE); 2810#endif 2811 2812#if 1 || defined(PFSYNC_DEBUG) 2813 if (sc->sc_len < PFSYNC_MINPKT) 2814#ifdef __FreeBSD__ 2815 panic("pfsync pkt len is too low %zu", sc->sc_len); 2816#else 2817 panic("pfsync pkt len is too low %d", sc->sc_len); 2818#endif 2819#endif 2820 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2821 nlen += sizeof(struct pfsync_subheader); 2822 2823#ifdef __FreeBSD__ 2824 if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2825#else 2826 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2827#endif 2828 s = splnet(); 2829 pfsync_sendout(); 2830 splx(s); 2831 2832 nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 2833 } 2834 2835 sc->sc_len += nlen; 2836 TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 2837 st->sync_state = q; 2838} 2839 2840void 2841pfsync_q_del(struct pf_state *st) 2842{ 2843#ifdef __FreeBSD__ 2844 struct pfsync_softc *sc = V_pfsyncif; 2845#else 2846 struct pfsync_softc *sc = pfsyncif; 2847#endif 2848 int q = st->sync_state; 2849 2850#ifdef __FreeBSD__ 2851 KASSERT(st->sync_state != PFSYNC_S_NONE, 2852 ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); 2853#else 2854 KASSERT(st->sync_state != PFSYNC_S_NONE); 2855#endif 2856 2857 sc->sc_len -= pfsync_qs[q].len; 2858 TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2859 st->sync_state = PFSYNC_S_NONE; 2860 2861 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2862 sc->sc_len -= sizeof(struct pfsync_subheader); 2863} 2864 2865#ifdef notyet 2866void 2867pfsync_update_tdb(struct tdb *t, int output) 2868{ 2869#ifdef __FreeBSD__ 2870 struct pfsync_softc *sc = V_pfsyncif; 2871#else 2872 struct pfsync_softc *sc = pfsyncif; 2873#endif 2874 size_t nlen = sizeof(struct pfsync_tdb); 2875 int s; 2876 2877 if (sc == NULL) 2878 return; 2879 2880 if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { 2881 if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2882 nlen += sizeof(struct pfsync_subheader); 2883 2884 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2885 s = splnet(); 2886 PF_LOCK(); 2887 pfsync_sendout(); 2888 PF_UNLOCK(); 2889 splx(s); 2890 2891 nlen = sizeof(struct pfsync_subheader) + 2892 sizeof(struct pfsync_tdb); 2893 } 2894 2895 sc->sc_len += nlen; 2896 TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); 2897 SET(t->tdb_flags, TDBF_PFSYNC); 2898 t->tdb_updates = 0; 2899 } else { 2900 if (++t->tdb_updates >= sc->sc_maxupdates) 2901 schednetisr(NETISR_PFSYNC); 2902 } 2903 2904 if (output) 2905 SET(t->tdb_flags, TDBF_PFSYNC_RPL); 2906 else 2907 CLR(t->tdb_flags, TDBF_PFSYNC_RPL); 2908} 2909 2910void 2911pfsync_delete_tdb(struct tdb *t) 2912{ 2913#ifdef __FreeBSD__ 2914 struct pfsync_softc *sc = V_pfsyncif; 2915#else 2916 struct pfsync_softc *sc = pfsyncif; 2917#endif 2918 2919 if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) 2920 return; 2921 2922 sc->sc_len -= sizeof(struct pfsync_tdb); 2923 TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); 2924 CLR(t->tdb_flags, TDBF_PFSYNC); 2925 2926 if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2927 sc->sc_len -= sizeof(struct pfsync_subheader); 2928} 2929 2930int 2931pfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) 2932{ 2933 struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); 2934 2935 bzero(ut, sizeof(*ut)); 2936 ut->spi = t->tdb_spi; 2937 bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); 2938 /* 2939 * When a failover happens, the master's rpl is probably above 2940 * what we see here (we may be up to a second late), so 2941 * increase it a bit for outbound tdbs to manage most such 2942 * situations. 2943 * 2944 * For now, just add an offset that is likely to be larger 2945 * than the number of packets we can see in one second. The RFC 2946 * just says the next packet must have a higher seq value. 2947 * 2948 * XXX What is a good algorithm for this? We could use 2949 * a rate-determined increase, but to know it, we would have 2950 * to extend struct tdb. 2951 * XXX pt->rpl can wrap over MAXINT, but if so the real tdb 2952 * will soon be replaced anyway. For now, just don't handle 2953 * this edge case. 2954 */ 2955#define RPL_INCR 16384 2956 ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? 2957 RPL_INCR : 0)); 2958 ut->cur_bytes = htobe64(t->tdb_cur_bytes); 2959 ut->sproto = t->tdb_sproto; 2960 2961 return (sizeof(*ut)); 2962} 2963#endif 2964 2965void 2966pfsync_bulk_start(void) 2967{ 2968#ifdef __FreeBSD__ 2969 struct pfsync_softc *sc = V_pfsyncif; 2970#else 2971 struct pfsync_softc *sc = pfsyncif; 2972#endif 2973 2974#ifdef __FreeBSD__ 2975 if (V_pf_status.debug >= PF_DEBUG_MISC) 2976#else 2977 if (pf_status.debug >= PF_DEBUG_MISC) 2978#endif 2979 printf("pfsync: received bulk update request\n"); 2980 2981#ifdef __FreeBSD__ 2982 PF_LOCK(); 2983 if (TAILQ_EMPTY(&V_state_list)) 2984#else 2985 if (TAILQ_EMPTY(&state_list)) 2986#endif 2987 pfsync_bulk_status(PFSYNC_BUS_END); 2988 else { 2989 sc->sc_ureq_received = time_uptime; 2990 if (sc->sc_bulk_next == NULL) 2991#ifdef __FreeBSD__ 2992 sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); 2993#else 2994 sc->sc_bulk_next = TAILQ_FIRST(&state_list); 2995#endif 2996 sc->sc_bulk_last = sc->sc_bulk_next; 2997 2998 pfsync_bulk_status(PFSYNC_BUS_START); 2999 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 3000 } 3001#ifdef __FreeBSD__ 3002 PF_UNLOCK(); 3003#endif 3004} 3005 3006void 3007pfsync_bulk_update(void *arg) 3008{ 3009 struct pfsync_softc *sc = arg; 3010 struct pf_state *st = sc->sc_bulk_next; 3011 int i = 0; 3012 int s; 3013 3014 PF_LOCK_ASSERT(); 3015 3016 s = splsoftnet(); 3017#ifdef __FreeBSD__ 3018 CURVNET_SET(sc->sc_ifp->if_vnet); 3019#endif 3020 for (;;) { 3021 if (st->sync_state == PFSYNC_S_NONE && 3022 st->timeout < PFTM_MAX && 3023 st->pfsync_time <= sc->sc_ureq_received) { 3024 pfsync_update_state_req(st); 3025 i++; 3026 } 3027 3028 st = TAILQ_NEXT(st, entry_list); 3029 if (st == NULL) 3030#ifdef __FreeBSD__ 3031 st = TAILQ_FIRST(&V_state_list); 3032#else 3033 st = TAILQ_FIRST(&state_list); 3034#endif 3035 3036 if (st == sc->sc_bulk_last) { 3037 /* we're done */ 3038 sc->sc_bulk_next = NULL; 3039 sc->sc_bulk_last = NULL; 3040 pfsync_bulk_status(PFSYNC_BUS_END); 3041 break; 3042 } 3043 3044#ifdef __FreeBSD__ 3045 if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 3046#else 3047 if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) < 3048#endif 3049 sizeof(struct pfsync_state)) { 3050 /* we've filled a packet */ 3051 sc->sc_bulk_next = st; 3052#ifdef __FreeBSD__ 3053 callout_reset(&sc->sc_bulk_tmo, 1, 3054 pfsync_bulk_update, sc); 3055#else 3056 timeout_add(&sc->sc_bulk_tmo, 1); 3057#endif 3058 break; 3059 } 3060 } 3061 3062#ifdef __FreeBSD__ 3063 CURVNET_RESTORE(); 3064#endif 3065 splx(s); 3066} 3067 3068void 3069pfsync_bulk_status(u_int8_t status) 3070{ 3071 struct { 3072 struct pfsync_subheader subh; 3073 struct pfsync_bus bus; 3074 } __packed r; 3075 3076#ifdef __FreeBSD__ 3077 struct pfsync_softc *sc = V_pfsyncif; 3078#else 3079 struct pfsync_softc *sc = pfsyncif; 3080#endif 3081 3082 PF_LOCK_ASSERT(); 3083 3084 bzero(&r, sizeof(r)); 3085 3086 r.subh.action = PFSYNC_ACT_BUS; 3087 r.subh.count = htons(1); 3088 3089#ifdef __FreeBSD__ 3090 r.bus.creatorid = V_pf_status.hostid; 3091#else 3092 r.bus.creatorid = pf_status.hostid; 3093#endif 3094 r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 3095 r.bus.status = status; 3096 3097 pfsync_send_plus(&r, sizeof(r)); 3098} 3099 3100void 3101pfsync_bulk_fail(void *arg) 3102{ 3103 struct pfsync_softc *sc = arg; 3104 3105#ifdef __FreeBSD__ 3106 CURVNET_SET(sc->sc_ifp->if_vnet); 3107#endif 3108 3109 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 3110 /* Try again */ 3111#ifdef __FreeBSD__ 3112 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 3113 pfsync_bulk_fail, V_pfsyncif); 3114#else 3115 timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 3116#endif 3117 PF_LOCK(); 3118 pfsync_request_update(0, 0); 3119 PF_UNLOCK(); 3120 } else { 3121 /* Pretend like the transfer was ok */ 3122 sc->sc_ureq_sent = 0; 3123 sc->sc_bulk_tries = 0; 3124#ifdef __FreeBSD__ 3125 if (!sc->pfsync_sync_ok && carp_demote_adj_p) 3126 (*carp_demote_adj_p)(-V_pfsync_carp_adj, 3127 "pfsync bulk fail"); 3128 sc->pfsync_sync_ok = 1; 3129#else 3130#if NCARP > 0 3131 if (!pfsync_sync_ok) 3132 carp_group_demote_adj(&sc->sc_if, -1); 3133#endif 3134 pfsync_sync_ok = 1; 3135#endif 3136#ifdef __FreeBSD__ 3137 if (V_pf_status.debug >= PF_DEBUG_MISC) 3138#else 3139 if (pf_status.debug >= PF_DEBUG_MISC) 3140#endif 3141 printf("pfsync: failed to receive bulk update\n"); 3142 } 3143 3144#ifdef __FreeBSD__ 3145 CURVNET_RESTORE(); 3146#endif 3147} 3148 3149void 3150pfsync_send_plus(void *plus, size_t pluslen) 3151{ 3152#ifdef __FreeBSD__ 3153 struct pfsync_softc *sc = V_pfsyncif; 3154#else 3155 struct pfsync_softc *sc = pfsyncif; 3156#endif 3157 int s; 3158 3159 PF_LOCK_ASSERT(); 3160 3161#ifdef __FreeBSD__ 3162 if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { 3163#else 3164 if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { 3165#endif 3166 s = splnet(); 3167 pfsync_sendout(); 3168 splx(s); 3169 } 3170 3171 sc->sc_plus = plus; 3172 sc->sc_len += (sc->sc_pluslen = pluslen); 3173 3174 s = splnet(); 3175 pfsync_sendout(); 3176 splx(s); 3177} 3178 3179int 3180pfsync_up(void) 3181{ 3182#ifdef __FreeBSD__ 3183 struct pfsync_softc *sc = V_pfsyncif; 3184#else 3185 struct pfsync_softc *sc = pfsyncif; 3186#endif 3187 3188#ifdef __FreeBSD__ 3189 if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) 3190#else 3191 if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) 3192#endif 3193 return (0); 3194 3195 return (1); 3196} 3197 3198int 3199pfsync_state_in_use(struct pf_state *st) 3200{ 3201#ifdef __FreeBSD__ 3202 struct pfsync_softc *sc = V_pfsyncif; 3203#else 3204 struct pfsync_softc *sc = pfsyncif; 3205#endif 3206 3207 if (sc == NULL) 3208 return (0); 3209 3210 if (st->sync_state != PFSYNC_S_NONE || 3211 st == sc->sc_bulk_next || 3212 st == sc->sc_bulk_last) 3213 return (1); 3214 3215 return (0); 3216} 3217 3218u_int pfsync_ints; 3219u_int pfsync_tmos; 3220 3221void 3222pfsync_timeout(void *arg) 3223{ 3224#if defined(__FreeBSD__) && defined(VIMAGE) 3225 struct pfsync_softc *sc = arg; 3226#endif 3227 int s; 3228 3229#ifdef __FreeBSD__ 3230 CURVNET_SET(sc->sc_ifp->if_vnet); 3231#endif 3232 3233 pfsync_tmos++; 3234 3235 s = splnet(); 3236#ifdef __FreeBSD__ 3237 PF_LOCK(); 3238#endif 3239 pfsync_sendout(); 3240#ifdef __FreeBSD__ 3241 PF_UNLOCK(); 3242#endif 3243 splx(s); 3244 3245#ifdef __FreeBSD__ 3246 CURVNET_RESTORE(); 3247#endif 3248} 3249 3250/* this is a softnet/netisr handler */ 3251void 3252#ifdef __FreeBSD__ 3253pfsyncintr(void *arg) 3254{ 3255 struct pfsync_softc *sc = arg; 3256 struct mbuf *m, *n; 3257 3258 CURVNET_SET(sc->sc_ifp->if_vnet); 3259 pfsync_ints++; 3260 3261 IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m); 3262 3263 for (; m != NULL; m = n) { 3264 3265 n = m->m_nextpkt; 3266 m->m_nextpkt = NULL; 3267 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) 3268 == 0) 3269 V_pfsyncstats.pfsyncs_opackets++; 3270 else 3271 V_pfsyncstats.pfsyncs_oerrors++; 3272 } 3273 CURVNET_RESTORE(); 3274} 3275#else 3276pfsyncintr(void) 3277{ 3278 int s; 3279 3280 pfsync_ints++; 3281 3282 s = splnet(); 3283 pfsync_sendout(); 3284 splx(s); 3285} 3286#endif 3287 3288int 3289pfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 3290 size_t newlen) 3291{ 3292 3293#ifdef notyet 3294 /* All sysctl names at this level are terminal. */ 3295 if (namelen != 1) 3296 return (ENOTDIR); 3297 3298 switch (name[0]) { 3299 case PFSYNCCTL_STATS: 3300 if (newp != NULL) 3301 return (EPERM); 3302 return (sysctl_struct(oldp, oldlenp, newp, newlen, 3303 &V_pfsyncstats, sizeof(V_pfsyncstats))); 3304 } 3305#endif 3306 return (ENOPROTOOPT); 3307} 3308 3309#ifdef __FreeBSD__ 3310static int 3311pfsync_multicast_setup(struct pfsync_softc *sc) 3312{ 3313 struct ip_moptions *imo = &sc->sc_imo; 3314 int error; 3315 3316 if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 3317 sc->sc_sync_if = NULL; 3318 return (EADDRNOTAVAIL); 3319 } 3320 3321 imo->imo_membership = (struct in_multi **)malloc( 3322 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 3323 M_WAITOK | M_ZERO); 3324 imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 3325 imo->imo_multicast_vif = -1; 3326 3327 if ((error = in_joingroup(sc->sc_sync_if, &sc->sc_sync_peer, NULL, 3328 &imo->imo_membership[0])) != 0) { 3329 free(imo->imo_membership, M_PFSYNC); 3330 return (error); 3331 } 3332 imo->imo_num_memberships++; 3333 imo->imo_multicast_ifp = sc->sc_sync_if; 3334 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 3335 imo->imo_multicast_loop = 0; 3336 3337 return (0); 3338} 3339 3340static void 3341pfsync_multicast_cleanup(struct pfsync_softc *sc) 3342{ 3343 struct ip_moptions *imo = &sc->sc_imo; 3344 3345 in_leavegroup(imo->imo_membership[0], NULL); 3346 free(imo->imo_membership, M_PFSYNC); 3347 imo->imo_membership = NULL; 3348 imo->imo_multicast_ifp = NULL; 3349} 3350 3351#ifdef INET 3352extern struct domain inetdomain; 3353static struct protosw in_pfsync_protosw = { 3354 .pr_type = SOCK_RAW, 3355 .pr_domain = &inetdomain, 3356 .pr_protocol = IPPROTO_PFSYNC, 3357 .pr_flags = PR_ATOMIC|PR_ADDR, 3358 .pr_input = pfsync_input, 3359 .pr_output = (pr_output_t *)rip_output, 3360 .pr_ctloutput = rip_ctloutput, 3361 .pr_usrreqs = &rip_usrreqs 3362}; 3363#endif 3364 3365static int 3366pfsync_init() 3367{ 3368 VNET_ITERATOR_DECL(vnet_iter); 3369 int error = 0; 3370 3371 VNET_LIST_RLOCK(); 3372 VNET_FOREACH(vnet_iter) { 3373 CURVNET_SET(vnet_iter); 3374 V_pfsync_cloner = pfsync_cloner; 3375 V_pfsync_cloner_data = pfsync_cloner_data; 3376 V_pfsync_cloner.ifc_data = &V_pfsync_cloner_data; 3377 if_clone_attach(&V_pfsync_cloner); 3378 error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3379 SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 3380 CURVNET_RESTORE(); 3381 if (error) 3382 goto fail_locked; 3383 } 3384 VNET_LIST_RUNLOCK(); 3385#ifdef INET 3386 error = pf_proto_register(PF_INET, &in_pfsync_protosw); 3387 if (error) 3388 goto fail; 3389 error = ipproto_register(IPPROTO_PFSYNC); 3390 if (error) { 3391 pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3392 goto fail; 3393 } 3394#endif 3395 PF_LOCK(); 3396 pfsync_state_import_ptr = pfsync_state_import; 3397 pfsync_up_ptr = pfsync_up; 3398 pfsync_insert_state_ptr = pfsync_insert_state; 3399 pfsync_update_state_ptr = pfsync_update_state; 3400 pfsync_delete_state_ptr = pfsync_delete_state; 3401 pfsync_clear_states_ptr = pfsync_clear_states; 3402 pfsync_state_in_use_ptr = pfsync_state_in_use; 3403 pfsync_defer_ptr = pfsync_defer; 3404 PF_UNLOCK(); 3405 3406 return (0); 3407 3408fail: 3409 VNET_LIST_RLOCK(); 3410fail_locked: 3411 VNET_FOREACH(vnet_iter) { 3412 CURVNET_SET(vnet_iter); 3413 if (V_pfsync_swi_cookie) { 3414 swi_remove(V_pfsync_swi_cookie); 3415 if_clone_detach(&V_pfsync_cloner); 3416 } 3417 CURVNET_RESTORE(); 3418 } 3419 VNET_LIST_RUNLOCK(); 3420 3421 return (error); 3422} 3423 3424static void 3425pfsync_uninit() 3426{ 3427 VNET_ITERATOR_DECL(vnet_iter); 3428 3429 PF_LOCK(); 3430 pfsync_state_import_ptr = NULL; 3431 pfsync_up_ptr = NULL; 3432 pfsync_insert_state_ptr = NULL; 3433 pfsync_update_state_ptr = NULL; 3434 pfsync_delete_state_ptr = NULL; 3435 pfsync_clear_states_ptr = NULL; 3436 pfsync_state_in_use_ptr = NULL; 3437 pfsync_defer_ptr = NULL; 3438 PF_UNLOCK(); 3439 3440 ipproto_unregister(IPPROTO_PFSYNC); 3441 pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 3442 VNET_LIST_RLOCK(); 3443 VNET_FOREACH(vnet_iter) { 3444 CURVNET_SET(vnet_iter); 3445 swi_remove(V_pfsync_swi_cookie); 3446 if_clone_detach(&V_pfsync_cloner); 3447 CURVNET_RESTORE(); 3448 } 3449 VNET_LIST_RUNLOCK(); 3450} 3451 3452static int 3453pfsync_modevent(module_t mod, int type, void *data) 3454{ 3455 int error = 0; 3456 3457 switch (type) { 3458 case MOD_LOAD: 3459 error = pfsync_init(); 3460 break; 3461 case MOD_QUIESCE: 3462 /* 3463 * Module should not be unloaded due to race conditions. 3464 */ 3465 error = EPERM; 3466 break; 3467 case MOD_UNLOAD: 3468 pfsync_uninit(); 3469 break; 3470 default: 3471 error = EINVAL; 3472 break; 3473 } 3474 3475 return (error); 3476} 3477 3478static moduledata_t pfsync_mod = { 3479 "pfsync", 3480 pfsync_modevent, 3481 0 3482}; 3483 3484#define PFSYNC_MODVER 1 3485 3486DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 3487MODULE_VERSION(pfsync, PFSYNC_MODVER); 3488MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3489#endif /* __FreeBSD__ */ 3490