if_pfsync.c revision 133720
1/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 133720 2004-08-14 15:32:40Z dwmalone $ */ 2/* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */ 3 4/* 5 * Copyright (c) 2002 Michael Shalayeff 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 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#ifdef __FreeBSD__ 31#include "opt_inet.h" 32#include "opt_inet6.h" 33#endif 34 35#ifndef __FreeBSD__ 36#include "bpfilter.h" 37#include "pfsync.h" 38#elif __FreeBSD__ >= 5 39#include "opt_bpf.h" 40#include "opt_pf.h" 41#define NBPFILTER DEV_BPF 42#define NPFSYNC DEV_PFSYNC 43#endif 44 45#include <sys/param.h> 46#include <sys/proc.h> 47#include <sys/systm.h> 48#include <sys/time.h> 49#include <sys/mbuf.h> 50#include <sys/socket.h> 51#ifdef __FreeBSD__ 52#include <sys/kernel.h> 53#include <sys/malloc.h> 54#include <sys/module.h> 55#include <sys/sockio.h> 56#include <sys/lock.h> 57#include <sys/mutex.h> 58#else 59#include <sys/ioctl.h> 60#include <sys/timeout.h> 61#endif 62 63#include <net/if.h> 64#if defined(__FreeBSD__) 65#include <net/if_clone.h> 66#endif 67#include <net/if_types.h> 68#include <net/route.h> 69#include <net/bpf.h> 70 71#ifdef INET 72#include <netinet/in.h> 73#include <netinet/in_systm.h> 74#include <netinet/in_var.h> 75#include <netinet/ip.h> 76#include <netinet/ip_var.h> 77#endif 78 79#ifdef INET6 80#ifndef INET 81#include <netinet/in.h> 82#endif 83#include <netinet6/nd6.h> 84#endif /* INET6 */ 85 86#include <net/pfvar.h> 87#include <net/if_pfsync.h> 88 89#ifdef __FreeBSD__ 90#define PFSYNCNAME "pfsync" 91#endif 92 93#define PFSYNC_MINMTU \ 94 (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 95 96#ifdef PFSYNCDEBUG 97#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 98int pfsyncdebug; 99#else 100#define DPRINTF(x) 101#endif 102 103#ifndef __FreeBSD__ 104struct pfsync_softc pfsyncif; 105#endif 106int pfsync_sync_ok; 107struct pfsyncstats pfsyncstats; 108 109#ifdef __FreeBSD__ 110 111/* 112 * Locking notes: 113 * Whenever we really touch/look at the state table we have to hold the 114 * PF_LOCK. Functions that do just the interface handling, grab the per 115 * softc lock instead. 116 * 117 */ 118 119static void pfsync_clone_destroy(struct ifnet *); 120static int pfsync_clone_create(struct if_clone *, int); 121#else 122void pfsyncattach(int); 123#endif 124void pfsync_setmtu(struct pfsync_softc *, int); 125int pfsync_insert_net_state(struct pfsync_state *); 126int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 127 struct rtentry *); 128int pfsyncioctl(struct ifnet *, u_long, caddr_t); 129void pfsyncstart(struct ifnet *); 130 131struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 132int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 133int pfsync_sendout(struct pfsync_softc *); 134void pfsync_timeout(void *); 135void pfsync_send_bus(struct pfsync_softc *, u_int8_t); 136void pfsync_bulk_update(void *); 137void pfsync_bulkfail(void *); 138 139#ifndef __FreeBSD__ 140extern int ifqmaxlen; 141extern struct timeval time; 142extern struct timeval mono_time; 143extern int hz; 144#endif 145 146#ifdef __FreeBSD__ 147static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 148static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 149IFC_SIMPLE_DECLARE(pfsync, 1); 150 151static void 152pfsync_clone_destroy(struct ifnet *ifp) 153{ 154 struct pfsync_softc *sc; 155 156 sc = ifp->if_softc; 157 callout_stop(&sc->sc_tmo); 158 callout_stop(&sc->sc_bulk_tmo); 159 callout_stop(&sc->sc_bulkfail_tmo); 160 161#if NBPFILTER > 0 162 bpfdetach(ifp); 163#endif 164 if_detach(ifp); 165 LIST_REMOVE(sc, sc_next); 166 free(sc, M_PFSYNC); 167} 168 169static int 170pfsync_clone_create(struct if_clone *ifc, int unit) 171{ 172 struct pfsync_softc *sc; 173 struct ifnet *ifp; 174 175 MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 176 M_WAITOK|M_ZERO); 177 178 pfsync_sync_ok = 1; 179 sc->sc_mbuf = NULL; 180 sc->sc_mbuf_net = NULL; 181 sc->sc_statep.s = NULL; 182 sc->sc_statep_net.s = NULL; 183 sc->sc_maxupdates = 128; 184 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 185 sc->sc_ureq_received = 0; 186 sc->sc_ureq_sent = 0; 187 188 ifp = &sc->sc_if; 189 if_initname(ifp, ifc->ifc_name, unit); 190 ifp->if_ioctl = pfsyncioctl; 191 ifp->if_output = pfsyncoutput; 192 ifp->if_start = pfsyncstart; 193 ifp->if_type = IFT_PFSYNC; 194 ifp->if_snd.ifq_maxlen = ifqmaxlen; 195 ifp->if_hdrlen = PFSYNC_HDRLEN; 196 ifp->if_baudrate = IF_Mbps(100); 197 ifp->if_softc = sc; 198 pfsync_setmtu(sc, MCLBYTES); 199 /* 200 * XXX 201 * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE 202 * if Gaint lock is removed from the network stack. 203 */ 204 callout_init(&sc->sc_tmo, 0); 205 callout_init(&sc->sc_bulk_tmo, 0); 206 callout_init(&sc->sc_bulkfail_tmo, 0); 207 if_attach(&sc->sc_if); 208 209 LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 210#if NBPFILTER > 0 211 bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN); 212#endif 213 214 return (0); 215} 216#else /* !__FreeBSD__ */ 217void 218pfsyncattach(int npfsync) 219{ 220 struct ifnet *ifp; 221 222 pfsync_sync_ok = 1; 223 bzero(&pfsyncif, sizeof(pfsyncif)); 224 pfsyncif.sc_mbuf = NULL; 225 pfsyncif.sc_mbuf_net = NULL; 226 pfsyncif.sc_statep.s = NULL; 227 pfsyncif.sc_statep_net.s = NULL; 228 pfsyncif.sc_maxupdates = 128; 229 pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 230 pfsyncif.sc_ureq_received = 0; 231 pfsyncif.sc_ureq_sent = 0; 232 ifp = &pfsyncif.sc_if; 233 strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); 234 ifp->if_softc = &pfsyncif; 235 ifp->if_ioctl = pfsyncioctl; 236 ifp->if_output = pfsyncoutput; 237 ifp->if_start = pfsyncstart; 238 ifp->if_type = IFT_PFSYNC; 239 ifp->if_snd.ifq_maxlen = ifqmaxlen; 240 ifp->if_hdrlen = PFSYNC_HDRLEN; 241 pfsync_setmtu(&pfsyncif, MCLBYTES); 242 timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); 243 timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); 244 timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); 245 if_attach(ifp); 246 if_alloc_sadl(ifp); 247 248#if NBPFILTER > 0 249 bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 250#endif 251} 252#endif 253 254/* 255 * Start output on the pfsync interface. 256 */ 257void 258pfsyncstart(struct ifnet *ifp) 259{ 260#ifdef __FreeBSD__ 261 IF_LOCK(&ifp->if_snd); 262 _IF_DROP(&ifp->if_snd); 263 _IF_DRAIN(&ifp->if_snd); 264 IF_UNLOCK(&ifp->if_snd); 265#else 266 struct mbuf *m; 267 int s; 268 269 for (;;) { 270 s = splimp(); 271 IF_DROP(&ifp->if_snd); 272 IF_DEQUEUE(&ifp->if_snd, m); 273 splx(s); 274 275 if (m == NULL) 276 return; 277 else 278 m_freem(m); 279 } 280#endif 281} 282 283int 284pfsync_insert_net_state(struct pfsync_state *sp) 285{ 286 struct pf_state *st = NULL; 287 struct pf_rule *r = NULL; 288 struct pfi_kif *kif; 289 290#ifdef __FreeBSD__ 291 PF_ASSERT(MA_OWNED); 292#endif 293 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 294 printf("pfsync_insert_net_state: invalid creator id:" 295 " %08x\n", ntohl(sp->creatorid)); 296 return (EINVAL); 297 } 298 299 kif = pfi_lookup_create(sp->ifname); 300 if (kif == NULL) { 301 if (pf_status.debug >= PF_DEBUG_MISC) 302 printf("pfsync_insert_net_state: " 303 "unknown interface: %s\n", sp->ifname); 304 /* skip this state */ 305 return (0); 306 } 307 308 /* 309 * Just use the default rule until we have infrastructure to find the 310 * best matching rule. 311 */ 312 r = &pf_default_rule; 313 314 if (!r->max_states || r->states < r->max_states) 315 st = pool_get(&pf_state_pl, PR_NOWAIT); 316 if (st == NULL) { 317 pfi_maybe_destroy(kif); 318 return (ENOMEM); 319 } 320 bzero(st, sizeof(*st)); 321 322 st->rule.ptr = r; 323 /* XXX get pointers to nat_rule and anchor */ 324 325 /* fill in the rest of the state entry */ 326 pf_state_host_ntoh(&sp->lan, &st->lan); 327 pf_state_host_ntoh(&sp->gwy, &st->gwy); 328 pf_state_host_ntoh(&sp->ext, &st->ext); 329 330 pf_state_peer_ntoh(&sp->src, &st->src); 331 pf_state_peer_ntoh(&sp->dst, &st->dst); 332 333 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 334#ifdef __FreeBSD__ 335 st->creation = ntohl(sp->creation) + time_second; 336 st->expire = ntohl(sp->expire) + time_second; 337#else 338 st->creation = ntohl(sp->creation) + time.tv_sec; 339 st->expire = ntohl(sp->expire) + time.tv_sec; 340#endif 341 342 st->af = sp->af; 343 st->proto = sp->proto; 344 st->direction = sp->direction; 345 st->log = sp->log; 346 st->timeout = sp->timeout; 347 st->allow_opts = sp->allow_opts; 348 349 bcopy(sp->id, &st->id, sizeof(st->id)); 350 st->creatorid = sp->creatorid; 351 st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC; 352 353 354 if (pf_insert_state(kif, st)) { 355 pfi_maybe_destroy(kif); 356 pool_put(&pf_state_pl, st); 357 return (EINVAL); 358 } 359 360 return (0); 361} 362 363void 364#ifdef __FreeBSD__ 365pfsync_input(struct mbuf *m, __unused int off) 366#else 367pfsync_input(struct mbuf *m, ...) 368#endif 369{ 370 struct ip *ip = mtod(m, struct ip *); 371 struct pfsync_header *ph; 372#ifdef __FreeBSD__ 373 struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 374#else 375 struct pfsync_softc *sc = &pfsyncif; 376#endif 377 struct pf_state *st, key; 378 struct pfsync_state *sp; 379 struct pfsync_state_upd *up; 380 struct pfsync_state_del *dp; 381 struct pfsync_state_clr *cp; 382 struct pfsync_state_upd_req *rup; 383 struct pfsync_state_bus *bus; 384 struct in_addr src; 385 struct mbuf *mp; 386 int iplen, action, error, i, s, count, offp; 387 388 pfsyncstats.pfsyncs_ipackets++; 389 390 /* verify that we have a sync interface configured */ 391 if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ 392 goto done; 393 394 /* verify that the packet came in on the right interface */ 395 if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 396 pfsyncstats.pfsyncs_badif++; 397 goto done; 398 } 399 400 /* verify that the IP TTL is 255. */ 401 if (ip->ip_ttl != PFSYNC_DFLTTL) { 402 pfsyncstats.pfsyncs_badttl++; 403 goto done; 404 } 405 406 iplen = ip->ip_hl << 2; 407 408 if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 409 pfsyncstats.pfsyncs_hdrops++; 410 goto done; 411 } 412 413 if (iplen + sizeof(*ph) > m->m_len) { 414 if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 415 pfsyncstats.pfsyncs_hdrops++; 416 goto done; 417 } 418 ip = mtod(m, struct ip *); 419 } 420 ph = (struct pfsync_header *)((char *)ip + iplen); 421 422 /* verify the version */ 423 if (ph->version != PFSYNC_VERSION) { 424 pfsyncstats.pfsyncs_badver++; 425 goto done; 426 } 427 428 action = ph->action; 429 count = ph->count; 430 431 /* make sure it's a valid action code */ 432 if (action >= PFSYNC_ACT_MAX) { 433 pfsyncstats.pfsyncs_badact++; 434 goto done; 435 } 436 437 /* Cheaper to grab this now than having to mess with mbufs later */ 438 src = ip->ip_src; 439 440 switch (action) { 441 case PFSYNC_ACT_CLR: { 442 struct pfi_kif *kif; 443 u_int32_t creatorid; 444 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 445 sizeof(*cp), &offp)) == NULL) { 446 pfsyncstats.pfsyncs_badlen++; 447 return; 448 } 449 cp = (struct pfsync_state_clr *)(mp->m_data + offp); 450 creatorid = cp->creatorid; 451 452 s = splsoftnet(); 453#ifdef __FreeBSD__ 454 PF_LOCK(); 455#endif 456 if (cp->ifname[0] == '\0') { 457 RB_FOREACH(st, pf_state_tree_id, &tree_id) { 458 if (st->creatorid == creatorid) 459 st->timeout = PFTM_PURGE; 460 } 461 } else { 462 kif = pfi_lookup_if(cp->ifname); 463 if (kif == NULL) { 464 if (pf_status.debug >= PF_DEBUG_MISC) 465 printf("pfsync_input: PFSYNC_ACT_CLR " 466 "bad interface: %s\n", cp->ifname); 467 splx(s); 468#ifdef __FreeBSD__ 469 PF_UNLOCK(); 470#endif 471 goto done; 472 } 473 RB_FOREACH(st, pf_state_tree_lan_ext, 474 &kif->pfik_lan_ext) { 475 if (st->creatorid == creatorid) 476 st->timeout = PFTM_PURGE; 477 } 478 } 479 pf_purge_expired_states(); 480#ifdef __FreeBSD__ 481 PF_UNLOCK(); 482#endif 483 splx(s); 484 485 break; 486 } 487 case PFSYNC_ACT_INS: 488 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 489 count * sizeof(*sp), &offp)) == NULL) { 490 pfsyncstats.pfsyncs_badlen++; 491 return; 492 } 493 494 s = splsoftnet(); 495#ifdef __FreeBSD__ 496 PF_LOCK(); 497#endif 498 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 499 i < count; i++, sp++) { 500 /* check for invalid values */ 501 if (sp->timeout >= PFTM_MAX || 502 sp->src.state > PF_TCPS_PROXY_DST || 503 sp->dst.state > PF_TCPS_PROXY_DST || 504 sp->direction > PF_OUT || 505 (sp->af != AF_INET && sp->af != AF_INET6)) { 506 if (pf_status.debug >= PF_DEBUG_MISC) 507 printf("pfsync_insert: PFSYNC_ACT_INS: " 508 "invalid value\n"); 509 pfsyncstats.pfsyncs_badstate++; 510 continue; 511 } 512 513 if ((error = pfsync_insert_net_state(sp))) { 514 if (error == ENOMEM) { 515 splx(s); 516#ifdef __FreeBSD__ 517 PF_UNLOCK(); 518#endif 519 goto done; 520 } 521 continue; 522 } 523 } 524#ifdef __FreeBSD__ 525 PF_UNLOCK(); 526#endif 527 splx(s); 528 break; 529 case PFSYNC_ACT_UPD: 530 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 531 count * sizeof(*sp), &offp)) == NULL) { 532 pfsyncstats.pfsyncs_badlen++; 533 return; 534 } 535 536 s = splsoftnet(); 537#ifdef __FreeBSD__ 538 PF_LOCK(); 539#endif 540 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 541 i < count; i++, sp++) { 542 /* check for invalid values */ 543 if (sp->timeout >= PFTM_MAX || 544 sp->src.state > PF_TCPS_PROXY_DST || 545 sp->dst.state > PF_TCPS_PROXY_DST) { 546 if (pf_status.debug >= PF_DEBUG_MISC) 547 printf("pfsync_insert: PFSYNC_ACT_UPD: " 548 "invalid value\n"); 549 pfsyncstats.pfsyncs_badstate++; 550 continue; 551 } 552 553 bcopy(sp->id, &key.id, sizeof(key.id)); 554 key.creatorid = sp->creatorid; 555 556 st = pf_find_state_byid(&key); 557 if (st == NULL) { 558 /* insert the update */ 559 if (pfsync_insert_net_state(sp)) 560 pfsyncstats.pfsyncs_badstate++; 561 continue; 562 } 563 pf_state_peer_ntoh(&sp->src, &st->src); 564 pf_state_peer_ntoh(&sp->dst, &st->dst); 565#ifdef __FreeBSD__ 566 st->expire = ntohl(sp->expire) + time_second; 567#else 568 st->expire = ntohl(sp->expire) + time.tv_sec; 569#endif 570 st->timeout = sp->timeout; 571 572 } 573#ifdef __FreeBSD__ 574 PF_UNLOCK(); 575#endif 576 splx(s); 577 break; 578 /* 579 * It's not strictly necessary for us to support the "uncompressed" 580 * delete action, but it's relatively simple and maintains consistency. 581 */ 582 case PFSYNC_ACT_DEL: 583 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 584 count * sizeof(*sp), &offp)) == NULL) { 585 pfsyncstats.pfsyncs_badlen++; 586 return; 587 } 588 589 s = splsoftnet(); 590#ifdef __FreeBSD__ 591 PF_LOCK(); 592#endif 593 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 594 i < count; i++, sp++) { 595 bcopy(sp->id, &key.id, sizeof(key.id)); 596 key.creatorid = sp->creatorid; 597 598 st = pf_find_state_byid(&key); 599 if (st == NULL) { 600 pfsyncstats.pfsyncs_badstate++; 601 continue; 602 } 603 /* 604 * XXX 605 * pf_purge_expired_states() is expensive, 606 * we really want to purge the state directly. 607 */ 608 st->timeout = PFTM_PURGE; 609 st->sync_flags |= PFSTATE_FROMSYNC; 610 } 611 pf_purge_expired_states(); 612#ifdef __FreeBSD__ 613 PF_UNLOCK(); 614#endif 615 splx(s); 616 break; 617 case PFSYNC_ACT_UPD_C: { 618 int update_requested = 0; 619 620 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 621 count * sizeof(*up), &offp)) == NULL) { 622 pfsyncstats.pfsyncs_badlen++; 623 return; 624 } 625 626 s = splsoftnet(); 627#ifdef __FreeBSD__ 628 PF_LOCK(); 629#endif 630 for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 631 i < count; i++, up++) { 632 /* check for invalid values */ 633 if (up->timeout >= PFTM_MAX || 634 up->src.state > PF_TCPS_PROXY_DST || 635 up->dst.state > PF_TCPS_PROXY_DST) { 636 if (pf_status.debug >= PF_DEBUG_MISC) 637 printf("pfsync_insert: " 638 "PFSYNC_ACT_UPD_C: " 639 "invalid value\n"); 640 pfsyncstats.pfsyncs_badstate++; 641 continue; 642 } 643 644 bcopy(up->id, &key.id, sizeof(key.id)); 645 key.creatorid = up->creatorid; 646 647 st = pf_find_state_byid(&key); 648 if (st == NULL) { 649 /* We don't have this state. Ask for it. */ 650 pfsync_request_update(up, &src); 651 update_requested = 1; 652 pfsyncstats.pfsyncs_badstate++; 653 continue; 654 } 655 pf_state_peer_ntoh(&up->src, &st->src); 656 pf_state_peer_ntoh(&up->dst, &st->dst); 657#ifdef __FreeBSD__ 658 st->expire = ntohl(up->expire) + time_second; 659#else 660 st->expire = ntohl(up->expire) + time.tv_sec; 661#endif 662 st->timeout = up->timeout; 663 } 664 if (update_requested) 665 pfsync_sendout(sc); 666#ifdef __FreeBSD__ 667 PF_UNLOCK(); 668#endif 669 splx(s); 670 break; 671 } 672 case PFSYNC_ACT_DEL_C: 673 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 674 count * sizeof(*dp), &offp)) == NULL) { 675 pfsyncstats.pfsyncs_badlen++; 676 return; 677 } 678 679 s = splsoftnet(); 680#ifdef __FreeBSD__ 681 PF_LOCK(); 682#endif 683 for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 684 i < count; i++, dp++) { 685 bcopy(dp->id, &key.id, sizeof(key.id)); 686 key.creatorid = dp->creatorid; 687 688 st = pf_find_state_byid(&key); 689 if (st == NULL) { 690 pfsyncstats.pfsyncs_badstate++; 691 continue; 692 } 693 /* 694 * XXX 695 * pf_purge_expired_states() is expensive, 696 * we really want to purge the state directly. 697 */ 698 st->timeout = PFTM_PURGE; 699 st->sync_flags |= PFSTATE_FROMSYNC; 700 } 701 pf_purge_expired_states(); 702#ifdef __FreeBSD__ 703 PF_UNLOCK(); 704#endif 705 splx(s); 706 break; 707 case PFSYNC_ACT_INS_F: 708 case PFSYNC_ACT_DEL_F: 709 /* not implemented */ 710 break; 711 case PFSYNC_ACT_UREQ: 712 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 713 count * sizeof(*rup), &offp)) == NULL) { 714 pfsyncstats.pfsyncs_badlen++; 715 return; 716 } 717 718 s = splsoftnet(); 719 /* XXX send existing. pfsync_pack_state should handle this. */ 720#ifdef __FreeBSD__ 721 PF_LOCK(); 722#endif 723 if (sc->sc_mbuf != NULL) 724 pfsync_sendout(sc); 725 for (i = 0, 726 rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 727 i < count; i++, rup++) { 728 bcopy(rup->id, &key.id, sizeof(key.id)); 729 key.creatorid = rup->creatorid; 730 731 if (key.id == 0 && key.creatorid == 0) { 732#ifdef __FreeBSD__ 733 sc->sc_ureq_received = time_uptime; 734#else 735 sc->sc_ureq_received = mono_time.tv_sec; 736#endif 737 if (pf_status.debug >= PF_DEBUG_MISC) 738 printf("pfsync: received " 739 "bulk update request\n"); 740 pfsync_send_bus(sc, PFSYNC_BUS_START); 741#ifdef __FreeBSD__ 742 callout_reset(&sc->sc_bulk_tmo, 1 * hz, 743 pfsync_bulk_update, 744 LIST_FIRST(&pfsync_list)); 745#else 746 timeout_add(&sc->sc_bulk_tmo, 1 * hz); 747#endif 748 } else { 749 st = pf_find_state_byid(&key); 750 if (st == NULL) { 751 pfsyncstats.pfsyncs_badstate++; 752 continue; 753 } 754 pfsync_pack_state(PFSYNC_ACT_UPD, st, 0); 755 } 756 } 757 if (sc->sc_mbuf != NULL) 758 pfsync_sendout(sc); 759#ifdef __FreeBSD__ 760 PF_UNLOCK(); 761#endif 762 splx(s); 763 break; 764 case PFSYNC_ACT_BUS: 765 /* If we're not waiting for a bulk update, who cares. */ 766 if (sc->sc_ureq_sent == 0) 767 break; 768 769 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 770 sizeof(*bus), &offp)) == NULL) { 771 pfsyncstats.pfsyncs_badlen++; 772 return; 773 } 774 bus = (struct pfsync_state_bus *)(mp->m_data + offp); 775 switch (bus->status) { 776 case PFSYNC_BUS_START: 777#ifdef __FreeBSD__ 778 callout_reset(&sc->sc_bulkfail_tmo, 779 pf_pool_limits[PF_LIMIT_STATES].limit / 780 (PFSYNC_BULKPACKETS * sc->sc_maxcount), 781 pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 782#else 783 timeout_add(&sc->sc_bulkfail_tmo, 784 pf_pool_limits[PF_LIMIT_STATES].limit / 785 (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 786#endif 787 if (pf_status.debug >= PF_DEBUG_MISC) 788 printf("pfsync: received bulk " 789 "update start\n"); 790 break; 791 case PFSYNC_BUS_END: 792#ifdef __FreeBSD__ 793 if (time_uptime - ntohl(bus->endtime) >= 794#else 795 if (mono_time.tv_sec - ntohl(bus->endtime) >= 796#endif 797 sc->sc_ureq_sent) { 798 /* that's it, we're happy */ 799 sc->sc_ureq_sent = 0; 800 sc->sc_bulk_tries = 0; 801#ifdef __FreeBSD__ 802 callout_stop(&sc->sc_bulkfail_tmo); 803#else 804 timeout_del(&sc->sc_bulkfail_tmo); 805#endif 806 pfsync_sync_ok = 1; 807 if (pf_status.debug >= PF_DEBUG_MISC) 808 printf("pfsync: received valid " 809 "bulk update end\n"); 810 } else { 811 if (pf_status.debug >= PF_DEBUG_MISC) 812 printf("pfsync: received invalid " 813 "bulk update end: bad timestamp\n"); 814 } 815 break; 816 } 817 break; 818 } 819 820done: 821 if (m) 822 m_freem(m); 823} 824 825int 826pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 827 struct rtentry *rt) 828{ 829 m_freem(m); 830 return (0); 831} 832 833/* ARGSUSED */ 834int 835pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 836{ 837#ifndef __FreeBSD__ 838 struct proc *p = curproc; 839#endif 840 struct pfsync_softc *sc = ifp->if_softc; 841 struct ifreq *ifr = (struct ifreq *)data; 842 struct ip_moptions *imo = &sc->sc_imo; 843 struct pfsyncreq pfsyncr; 844 struct ifnet *sifp; 845 int s, error; 846 847 switch (cmd) { 848 case SIOCSIFADDR: 849 case SIOCAIFADDR: 850 case SIOCSIFDSTADDR: 851 case SIOCSIFFLAGS: 852 if (ifp->if_flags & IFF_UP) 853 ifp->if_flags |= IFF_RUNNING; 854 else 855 ifp->if_flags &= ~IFF_RUNNING; 856 break; 857 case SIOCSIFMTU: 858 if (ifr->ifr_mtu < PFSYNC_MINMTU) 859 return (EINVAL); 860 if (ifr->ifr_mtu > MCLBYTES) 861 ifr->ifr_mtu = MCLBYTES; 862 s = splnet(); 863#ifdef __FreeBSD__ 864 PF_LOCK(); 865#endif 866 if (ifr->ifr_mtu < ifp->if_mtu) { 867 pfsync_sendout(sc); 868 } 869 pfsync_setmtu(sc, ifr->ifr_mtu); 870#ifdef __FreeBSD__ 871 PF_UNLOCK(); 872#endif 873 splx(s); 874 break; 875 case SIOCGETPFSYNC: 876#ifdef __FreeBSD__ 877 /* XXX: read unlocked */ 878#endif 879 bzero(&pfsyncr, sizeof(pfsyncr)); 880 if (sc->sc_sync_ifp) 881 strlcpy(pfsyncr.pfsyncr_syncif, 882 sc->sc_sync_ifp->if_xname, IFNAMSIZ); 883 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 884 if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 885 return (error); 886 break; 887 case SIOCSETPFSYNC: 888#ifdef __FreeBSD__ 889 if ((error = suser(curthread)) != 0) 890#else 891 if ((error = suser(p, p->p_acflag)) != 0) 892#endif 893 return (error); 894 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 895 return (error); 896 897 if (pfsyncr.pfsyncr_maxupdates > 255) 898 return (EINVAL); 899#ifdef __FreeBSD__ 900 PF_LOCK(); 901#endif 902 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 903 904 if (pfsyncr.pfsyncr_syncif[0] == 0) { 905 sc->sc_sync_ifp = NULL; 906 if (sc->sc_mbuf_net != NULL) { 907 /* Don't keep stale pfsync packets around. */ 908 s = splnet(); 909 m_freem(sc->sc_mbuf_net); 910 sc->sc_mbuf_net = NULL; 911 sc->sc_statep_net.s = NULL; 912 splx(s); 913 } 914#ifdef __FreeBSD__ 915 PF_UNLOCK(); 916#endif 917 break; 918 } 919 if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) { 920#ifdef __FreeBSD__ 921 PF_UNLOCK(); 922#endif 923 return (EINVAL); 924 } 925 else if (sifp == sc->sc_sync_ifp) { 926#ifdef __FreeBSD__ 927 PF_UNLOCK(); 928#endif 929 break; 930 } 931 932 s = splnet(); 933 if (sifp->if_mtu < sc->sc_if.if_mtu || 934 (sc->sc_sync_ifp != NULL && 935 sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 936 sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 937 pfsync_sendout(sc); 938 sc->sc_sync_ifp = sifp; 939 940 pfsync_setmtu(sc, sc->sc_if.if_mtu); 941 942 if (imo->imo_num_memberships > 0) { 943 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 944 imo->imo_multicast_ifp = NULL; 945 } 946 947 if (sc->sc_sync_ifp) { 948 struct in_addr addr; 949 950#ifdef __FreeBSD__ 951 PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ 952 addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 953#else 954 addr.s_addr = INADDR_PFSYNC_GROUP; 955#endif 956 if ((imo->imo_membership[0] = 957 in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 958 splx(s); 959 return (ENOBUFS); 960 } 961 imo->imo_num_memberships++; 962 imo->imo_multicast_ifp = sc->sc_sync_ifp; 963 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 964 imo->imo_multicast_loop = 0; 965 966 /* Request a full state table update. */ 967#ifdef __FreeBSD__ 968 PF_LOCK(); 969 sc->sc_ureq_sent = time_uptime; 970#else 971 sc->sc_ureq_sent = mono_time.tv_sec; 972#endif 973 pfsync_sync_ok = 0; 974 if (pf_status.debug >= PF_DEBUG_MISC) 975 printf("pfsync: requesting bulk update\n"); 976#ifdef __FreeBSD__ 977 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 978 pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 979#else 980 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 981#endif 982 pfsync_request_update(NULL, NULL); 983 pfsync_sendout(sc); 984 } 985#ifdef __FreeBSD__ 986 PF_UNLOCK(); 987#endif 988 splx(s); 989 990 break; 991 992 default: 993 return (ENOTTY); 994 } 995 996 return (0); 997} 998 999void 1000pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 1001{ 1002 int mtu; 1003 1004 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 1005 mtu = sc->sc_sync_ifp->if_mtu; 1006 else 1007 mtu = mtu_req; 1008 1009 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 1010 sizeof(struct pfsync_state); 1011 if (sc->sc_maxcount > 254) 1012 sc->sc_maxcount = 254; 1013 sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 1014 sc->sc_maxcount * sizeof(struct pfsync_state); 1015} 1016 1017struct mbuf * 1018pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 1019{ 1020 struct pfsync_header *h; 1021 struct mbuf *m; 1022 int len; 1023 1024#ifdef __FreeBSD__ 1025 PF_ASSERT(MA_OWNED); 1026#endif 1027 MGETHDR(m, M_DONTWAIT, MT_DATA); 1028 if (m == NULL) { 1029 sc->sc_if.if_oerrors++; 1030 return (NULL); 1031 } 1032 1033 switch (action) { 1034 case PFSYNC_ACT_CLR: 1035 len = sizeof(struct pfsync_header) + 1036 sizeof(struct pfsync_state_clr); 1037 break; 1038 case PFSYNC_ACT_UPD_C: 1039 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 1040 sizeof(struct pfsync_header); 1041 break; 1042 case PFSYNC_ACT_DEL_C: 1043 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 1044 sizeof(struct pfsync_header); 1045 break; 1046 case PFSYNC_ACT_UREQ: 1047 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 1048 sizeof(struct pfsync_header); 1049 break; 1050 case PFSYNC_ACT_BUS: 1051 len = sizeof(struct pfsync_header) + 1052 sizeof(struct pfsync_state_bus); 1053 break; 1054 default: 1055 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 1056 sizeof(struct pfsync_header); 1057 break; 1058 } 1059 1060 if (len > MHLEN) { 1061 MCLGET(m, M_DONTWAIT); 1062 if ((m->m_flags & M_EXT) == 0) { 1063 m_free(m); 1064 sc->sc_if.if_oerrors++; 1065 return (NULL); 1066 } 1067 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 1068 } else 1069 MH_ALIGN(m, len); 1070 1071 m->m_pkthdr.rcvif = NULL; 1072 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 1073 h = mtod(m, struct pfsync_header *); 1074 h->version = PFSYNC_VERSION; 1075 h->af = 0; 1076 h->count = 0; 1077 h->action = action; 1078 1079 *sp = (void *)((char *)h + PFSYNC_HDRLEN); 1080#ifdef __FreeBSD__ 1081 callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 1082 LIST_FIRST(&pfsync_list)); 1083#else 1084 timeout_add(&sc->sc_tmo, hz); 1085#endif 1086 return (m); 1087} 1088 1089int 1090pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress) 1091{ 1092#ifdef __FreeBSD__ 1093 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 1094#else 1095 struct ifnet *ifp = &pfsyncif.sc_if; 1096#endif 1097 struct pfsync_softc *sc = ifp->if_softc; 1098 struct pfsync_header *h, *h_net; 1099 struct pfsync_state *sp = NULL; 1100 struct pfsync_state_upd *up = NULL; 1101 struct pfsync_state_del *dp = NULL; 1102 struct pf_rule *r; 1103 u_long secs; 1104 int s, ret = 0; 1105 u_int8_t i = 255, newaction = 0; 1106 1107#ifdef __FreeBSD__ 1108 PF_ASSERT(MA_OWNED); 1109#endif 1110 /* 1111 * If a packet falls in the forest and there's nobody around to 1112 * hear, does it make a sound? 1113 */ 1114 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) { 1115 /* Don't leave any stale pfsync packets hanging around. */ 1116 if (sc->sc_mbuf != NULL) { 1117 m_freem(sc->sc_mbuf); 1118 sc->sc_mbuf = NULL; 1119 sc->sc_statep.s = NULL; 1120 } 1121 return (0); 1122 } 1123 1124 if (action >= PFSYNC_ACT_MAX) 1125 return (EINVAL); 1126 1127 s = splnet(); 1128 if (sc->sc_mbuf == NULL) { 1129 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1130 (void *)&sc->sc_statep.s)) == NULL) { 1131 splx(s); 1132 return (ENOMEM); 1133 } 1134 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1135 } else { 1136 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1137 if (h->action != action) { 1138 pfsync_sendout(sc); 1139 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1140 (void *)&sc->sc_statep.s)) == NULL) { 1141 splx(s); 1142 return (ENOMEM); 1143 } 1144 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1145 } else { 1146 /* 1147 * If it's an update, look in the packet to see if 1148 * we already have an update for the state. 1149 */ 1150 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 1151 struct pfsync_state *usp = 1152 (void *)((char *)h + PFSYNC_HDRLEN); 1153 1154 for (i = 0; i < h->count; i++) { 1155 if (!memcmp(usp->id, &st->id, 1156 PFSYNC_ID_LEN) && 1157 usp->creatorid == st->creatorid) { 1158 sp = usp; 1159 sp->updates++; 1160 break; 1161 } 1162 usp++; 1163 } 1164 } 1165 } 1166 } 1167 1168#ifdef __FreeBSD__ 1169 secs = time_second; 1170 1171 st->pfsync_time = time_uptime; 1172#else 1173 secs = time.tv_sec; 1174 1175 st->pfsync_time = mono_time.tv_sec; 1176#endif 1177 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 1178 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 1179 1180 if (sp == NULL) { 1181 /* not a "duplicate" update */ 1182 i = 255; 1183 sp = sc->sc_statep.s++; 1184 sc->sc_mbuf->m_pkthdr.len = 1185 sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 1186 h->count++; 1187 bzero(sp, sizeof(*sp)); 1188 1189 bcopy(&st->id, sp->id, sizeof(sp->id)); 1190 sp->creatorid = st->creatorid; 1191 1192 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 1193 pf_state_host_hton(&st->lan, &sp->lan); 1194 pf_state_host_hton(&st->gwy, &sp->gwy); 1195 pf_state_host_hton(&st->ext, &sp->ext); 1196 1197 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 1198 1199 sp->creation = htonl(secs - st->creation); 1200 sp->packets[0] = htonl(st->packets[0]); 1201 sp->packets[1] = htonl(st->packets[1]); 1202 sp->bytes[0] = htonl(st->bytes[0]); 1203 sp->bytes[1] = htonl(st->bytes[1]); 1204 if ((r = st->rule.ptr) == NULL) 1205 sp->rule = htonl(-1); 1206 else 1207 sp->rule = htonl(r->nr); 1208 if ((r = st->anchor.ptr) == NULL) 1209 sp->anchor = htonl(-1); 1210 else 1211 sp->anchor = htonl(r->nr); 1212 sp->af = st->af; 1213 sp->proto = st->proto; 1214 sp->direction = st->direction; 1215 sp->log = st->log; 1216 sp->allow_opts = st->allow_opts; 1217 sp->timeout = st->timeout; 1218 1219 sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC; 1220 } 1221 1222 pf_state_peer_hton(&st->src, &sp->src); 1223 pf_state_peer_hton(&st->dst, &sp->dst); 1224 1225 if (st->expire <= secs) 1226 sp->expire = htonl(0); 1227 else 1228 sp->expire = htonl(st->expire - secs); 1229 1230 /* do we need to build "compressed" actions for network transfer? */ 1231 if (sc->sc_sync_ifp && compress) { 1232 switch (action) { 1233 case PFSYNC_ACT_UPD: 1234 newaction = PFSYNC_ACT_UPD_C; 1235 break; 1236 case PFSYNC_ACT_DEL: 1237 newaction = PFSYNC_ACT_DEL_C; 1238 break; 1239 default: 1240 /* by default we just send the uncompressed states */ 1241 break; 1242 } 1243 } 1244 1245 if (newaction) { 1246 if (sc->sc_mbuf_net == NULL) { 1247 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 1248 (void *)&sc->sc_statep_net.s)) == NULL) { 1249 splx(s); 1250 return (ENOMEM); 1251 } 1252 } 1253 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 1254 1255 switch (newaction) { 1256 case PFSYNC_ACT_UPD_C: 1257 if (i != 255) { 1258 up = (void *)((char *)h_net + 1259 PFSYNC_HDRLEN + (i * sizeof(*up))); 1260 up->updates++; 1261 } else { 1262 h_net->count++; 1263 sc->sc_mbuf_net->m_pkthdr.len = 1264 sc->sc_mbuf_net->m_len += sizeof(*up); 1265 up = sc->sc_statep_net.u++; 1266 1267 bzero(up, sizeof(*up)); 1268 bcopy(&st->id, up->id, sizeof(up->id)); 1269 up->creatorid = st->creatorid; 1270 } 1271 up->timeout = st->timeout; 1272 up->expire = sp->expire; 1273 up->src = sp->src; 1274 up->dst = sp->dst; 1275 break; 1276 case PFSYNC_ACT_DEL_C: 1277 sc->sc_mbuf_net->m_pkthdr.len = 1278 sc->sc_mbuf_net->m_len += sizeof(*dp); 1279 dp = sc->sc_statep_net.d++; 1280 h_net->count++; 1281 1282 bzero(dp, sizeof(*dp)); 1283 bcopy(&st->id, dp->id, sizeof(dp->id)); 1284 dp->creatorid = st->creatorid; 1285 break; 1286 } 1287 } 1288 1289 if (h->count == sc->sc_maxcount || 1290 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 1291 ret = pfsync_sendout(sc); 1292 1293 splx(s); 1294 return (ret); 1295} 1296 1297/* This must be called in splnet() */ 1298int 1299pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 1300{ 1301#ifdef __FreeBSD__ 1302 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 1303#else 1304 struct ifnet *ifp = &pfsyncif.sc_if; 1305#endif 1306 struct pfsync_header *h; 1307 struct pfsync_softc *sc = ifp->if_softc; 1308 struct pfsync_state_upd_req *rup; 1309 int s = 0, ret = 0; /* make the compiler happy */ 1310 1311#ifdef __FreeBSD__ 1312 PF_ASSERT(MA_OWNED); 1313#endif 1314 if (sc->sc_mbuf == NULL) { 1315 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1316 (void *)&sc->sc_statep.s)) == NULL) { 1317 splx(s); 1318 return (ENOMEM); 1319 } 1320 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1321 } else { 1322 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1323 if (h->action != PFSYNC_ACT_UREQ) { 1324 pfsync_sendout(sc); 1325 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1326 (void *)&sc->sc_statep.s)) == NULL) { 1327 splx(s); 1328 return (ENOMEM); 1329 } 1330 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1331 } 1332 } 1333 1334 if (src != NULL) 1335 sc->sc_sendaddr = *src; 1336 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 1337 h->count++; 1338 rup = sc->sc_statep.r++; 1339 bzero(rup, sizeof(*rup)); 1340 if (up != NULL) { 1341 bcopy(up->id, rup->id, sizeof(rup->id)); 1342 rup->creatorid = up->creatorid; 1343 } 1344 1345 if (h->count == sc->sc_maxcount) 1346 ret = pfsync_sendout(sc); 1347 1348 return (ret); 1349} 1350 1351int 1352pfsync_clear_states(u_int32_t creatorid, char *ifname) 1353{ 1354#ifdef __FreeBSD__ 1355 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 1356#else 1357 struct ifnet *ifp = &pfsyncif.sc_if; 1358#endif 1359 struct pfsync_softc *sc = ifp->if_softc; 1360 struct pfsync_state_clr *cp; 1361 int s, ret; 1362 1363 s = splnet(); 1364#ifdef __FreeBSD__ 1365 PF_ASSERT(MA_OWNED); 1366#endif 1367 if (sc->sc_mbuf != NULL) 1368 pfsync_sendout(sc); 1369 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 1370 (void *)&sc->sc_statep.c)) == NULL) { 1371 splx(s); 1372 return (ENOMEM); 1373 } 1374 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 1375 cp = sc->sc_statep.c; 1376 cp->creatorid = creatorid; 1377 if (ifname != NULL) 1378 strlcpy(cp->ifname, ifname, IFNAMSIZ); 1379 1380 ret = (pfsync_sendout(sc)); 1381 splx(s); 1382 return (ret); 1383} 1384 1385void 1386pfsync_timeout(void *v) 1387{ 1388 struct pfsync_softc *sc = v; 1389 int s; 1390 1391 s = splnet(); 1392#ifdef __FreeBSD__ 1393 PF_LOCK(); 1394#endif 1395 pfsync_sendout(sc); 1396#ifdef __FreeBSD__ 1397 PF_UNLOCK(); 1398#endif 1399 splx(s); 1400} 1401 1402void 1403pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 1404{ 1405 struct pfsync_state_bus *bus; 1406 1407#ifdef __FreeBSD__ 1408 PF_ASSERT(MA_OWNED); 1409#endif 1410 if (sc->sc_mbuf != NULL) 1411 pfsync_sendout(sc); 1412 1413 if (pfsync_sync_ok && 1414 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 1415 (void *)&sc->sc_statep.b)) != NULL) { 1416 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 1417 bus = sc->sc_statep.b; 1418 bus->creatorid = pf_status.hostid; 1419 bus->status = status; 1420#ifdef __FreeBSD__ 1421 bus->endtime = htonl(time_uptime - sc->sc_ureq_received); 1422#else 1423 bus->endtime = htonl(mono_time.tv_sec - sc->sc_ureq_received); 1424#endif 1425 pfsync_sendout(sc); 1426 } 1427} 1428 1429void 1430pfsync_bulk_update(void *v) 1431{ 1432 struct pfsync_softc *sc = v; 1433 int s, i = 0; 1434 struct pf_state *state; 1435 1436#ifdef __FreeBSD__ 1437 PF_LOCK(); 1438#endif 1439 s = splnet(); 1440 if (sc->sc_mbuf != NULL) 1441 pfsync_sendout(sc); 1442 1443 /* 1444 * Grab at most PFSYNC_BULKPACKETS worth of states which have not 1445 * been sent since the latest request was made. 1446 */ 1447 while ((state = TAILQ_FIRST(&state_updates)) != NULL && 1448 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 1449 if (state->pfsync_time > sc->sc_ureq_received) { 1450 /* we're done */ 1451 pfsync_send_bus(sc, PFSYNC_BUS_END); 1452 sc->sc_ureq_received = 0; 1453#ifdef __FreeBSD__ 1454 callout_stop(&sc->sc_bulk_tmo); 1455#else 1456 timeout_del(&sc->sc_bulk_tmo); 1457#endif 1458 if (pf_status.debug >= PF_DEBUG_MISC) 1459 printf("pfsync: bulk update complete\n"); 1460 break; 1461 } else { 1462 /* send an update and move to end of list */ 1463 if (!state->sync_flags) 1464 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 1465#ifdef __FreeBSD__ 1466 state->pfsync_time = time_uptime; 1467#else 1468 state->pfsync_time = mono_time.tv_sec; 1469#endif 1470 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 1471 TAILQ_INSERT_TAIL(&state_updates, state, 1472 u.s.entry_updates); 1473 1474 /* look again for more in a bit */ 1475#ifdef __FreeBSD__ 1476 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 1477 LIST_FIRST(&pfsync_list)); 1478#else 1479 timeout_add(&sc->sc_bulk_tmo, 1); 1480#endif 1481 } 1482 } 1483 if (sc->sc_mbuf != NULL) 1484 pfsync_sendout(sc); 1485 splx(s); 1486#ifdef __FreeBSD__ 1487 PF_UNLOCK(); 1488#endif 1489} 1490 1491void 1492pfsync_bulkfail(void *v) 1493{ 1494 struct pfsync_softc *sc = v; 1495 1496#ifdef __FreeBSD__ 1497 PF_LOCK(); 1498#endif 1499 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1500 /* Try again in a bit */ 1501#ifdef __FreeBSD__ 1502 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1503 LIST_FIRST(&pfsync_list)); 1504#else 1505 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1506#endif 1507 pfsync_request_update(NULL, NULL); 1508 pfsync_sendout(sc); 1509 } else { 1510 /* Pretend like the transfer was ok */ 1511 sc->sc_ureq_sent = 0; 1512 sc->sc_bulk_tries = 0; 1513 pfsync_sync_ok = 1; 1514 if (pf_status.debug >= PF_DEBUG_MISC) 1515 printf("pfsync: failed to receive " 1516 "bulk update status\n"); 1517#ifdef __FreeBSD__ 1518 callout_stop(&sc->sc_bulkfail_tmo); 1519#else 1520 timeout_del(&sc->sc_bulkfail_tmo); 1521#endif 1522 } 1523#ifdef __FreeBSD__ 1524 PF_UNLOCK(); 1525#endif 1526} 1527 1528int 1529pfsync_sendout(sc) 1530 struct pfsync_softc *sc; 1531{ 1532 struct ifnet *ifp = &sc->sc_if; 1533 struct mbuf *m; 1534 1535#ifdef __FreeBSD__ 1536 PF_ASSERT(MA_OWNED); 1537 callout_stop(&sc->sc_tmo); 1538#else 1539 timeout_del(&sc->sc_tmo); 1540#endif 1541 1542 if (sc->sc_mbuf == NULL) 1543 return (0); 1544 m = sc->sc_mbuf; 1545 sc->sc_mbuf = NULL; 1546 sc->sc_statep.s = NULL; 1547 1548#ifdef __FreeBSD__ 1549 KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1550#endif 1551#if NBPFILTER > 0 1552 if (ifp->if_bpf) 1553 bpf_mtap(ifp->if_bpf, m); 1554#endif 1555 1556 if (sc->sc_mbuf_net) { 1557 m_freem(m); 1558 m = sc->sc_mbuf_net; 1559 sc->sc_mbuf_net = NULL; 1560 sc->sc_statep_net.s = NULL; 1561 } 1562 1563 if (sc->sc_sync_ifp) { 1564 struct ip *ip; 1565 struct ifaddr *ifa; 1566 struct sockaddr sa; 1567 1568 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 1569 if (m == NULL) { 1570 pfsyncstats.pfsyncs_onomem++; 1571 return (0); 1572 } 1573 ip = mtod(m, struct ip *); 1574 ip->ip_v = IPVERSION; 1575 ip->ip_hl = sizeof(*ip) >> 2; 1576 ip->ip_tos = IPTOS_LOWDELAY; 1577#ifdef __FreeBSD__ 1578 ip->ip_len = m->m_pkthdr.len; 1579#else 1580 ip->ip_len = htons(m->m_pkthdr.len); 1581#endif 1582 ip->ip_id = htons(ip_randomid()); 1583#ifdef __FreeBSD__ 1584 ip->ip_off = IP_DF; 1585#else 1586 ip->ip_off = htons(IP_DF); 1587#endif 1588 ip->ip_ttl = PFSYNC_DFLTTL; 1589 ip->ip_p = IPPROTO_PFSYNC; 1590 ip->ip_sum = 0; 1591 1592 bzero(&sa, sizeof(sa)); 1593 sa.sa_family = AF_INET; 1594 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp); 1595 if (ifa == NULL) 1596 return (0); 1597 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 1598 1599#ifdef __FreeBSD__ 1600 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1601#else 1602 if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) 1603#endif 1604 m->m_flags |= M_MCAST; 1605 ip->ip_dst = sc->sc_sendaddr; 1606#ifdef __FreeBSD__ 1607 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1608#else 1609 sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 1610#endif 1611 1612 pfsyncstats.pfsyncs_opackets++; 1613 1614#ifdef __FreeBSD__ 1615 PF_UNLOCK(); 1616#endif 1617 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1618 pfsyncstats.pfsyncs_oerrors++; 1619 1620#ifdef __FreeBSD__ 1621 PF_LOCK(); 1622#endif 1623 } else 1624 m_freem(m); 1625 1626 return (0); 1627} 1628 1629 1630#ifdef __FreeBSD__ 1631static int 1632pfsync_modevent(module_t mod, int type, void *data) 1633{ 1634 int error = 0; 1635 1636 switch (type) { 1637 case MOD_LOAD: 1638 LIST_INIT(&pfsync_list); 1639 if_clone_attach(&pfsync_cloner); 1640 break; 1641 1642 case MOD_UNLOAD: 1643 if_clone_detach(&pfsync_cloner); 1644 while (!LIST_EMPTY(&pfsync_list)) 1645 pfsync_clone_destroy( 1646 &LIST_FIRST(&pfsync_list)->sc_if); 1647 break; 1648 1649 default: 1650 error = EINVAL; 1651 break; 1652 } 1653 1654 return error; 1655} 1656 1657static moduledata_t pfsync_mod = { 1658 "pfsync", 1659 pfsync_modevent, 1660 0 1661}; 1662 1663#define PFSYNC_MODVER 1 1664 1665DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1666MODULE_VERSION(pfsync, PFSYNC_MODVER); 1667#endif /* __FreeBSD__ */ 1668