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