if_pfsync.c revision 165632
1126261Smlaier/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 165632 2006-12-29 13:59:50Z jhb $ */ 2145836Smlaier/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */ 3126258Smlaier 4126258Smlaier/* 5126258Smlaier * Copyright (c) 2002 Michael Shalayeff 6126258Smlaier * All rights reserved. 7126258Smlaier * 8126258Smlaier * Redistribution and use in source and binary forms, with or without 9126258Smlaier * modification, are permitted provided that the following conditions 10126258Smlaier * are met: 11126258Smlaier * 1. Redistributions of source code must retain the above copyright 12126258Smlaier * notice, this list of conditions and the following disclaimer. 13126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14126258Smlaier * notice, this list of conditions and the following disclaimer in the 15126258Smlaier * documentation and/or other materials provided with the distribution. 16126258Smlaier * 17126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE. 28126258Smlaier */ 29126258Smlaier 30127145Smlaier#ifdef __FreeBSD__ 31126261Smlaier#include "opt_inet.h" 32126261Smlaier#include "opt_inet6.h" 33126261Smlaier#endif 34126261Smlaier 35127145Smlaier#ifndef __FreeBSD__ 36126258Smlaier#include "bpfilter.h" 37126258Smlaier#include "pfsync.h" 38126261Smlaier#elif __FreeBSD__ >= 5 39126261Smlaier#include "opt_bpf.h" 40126261Smlaier#include "opt_pf.h" 41153110Sru 42153110Sru#ifdef DEV_BPF 43127145Smlaier#define NBPFILTER DEV_BPF 44153110Sru#else 45153110Sru#define NBPFILTER 0 46153110Sru#endif 47153110Sru 48153110Sru#ifdef DEV_PFSYNC 49127145Smlaier#define NPFSYNC DEV_PFSYNC 50153110Sru#else 51153110Sru#define NPFSYNC 0 52126261Smlaier#endif 53126258Smlaier 54153110Sru#endif 55153110Sru 56126258Smlaier#include <sys/param.h> 57164033Srwatson#ifdef __FreeBSD__ 58164033Srwatson#include <sys/priv.h> 59164033Srwatson#endif 60130613Smlaier#include <sys/proc.h> 61126258Smlaier#include <sys/systm.h> 62126258Smlaier#include <sys/time.h> 63126258Smlaier#include <sys/mbuf.h> 64126258Smlaier#include <sys/socket.h> 65145836Smlaier#include <sys/kernel.h> 66127145Smlaier#ifdef __FreeBSD__ 67145836Smlaier#include <sys/endian.h> 68126261Smlaier#include <sys/malloc.h> 69129907Smlaier#include <sys/module.h> 70126261Smlaier#include <sys/sockio.h> 71130613Smlaier#include <sys/lock.h> 72130613Smlaier#include <sys/mutex.h> 73148015Smlaier#include <sys/sysctl.h> 74126261Smlaier#else 75126258Smlaier#include <sys/ioctl.h> 76126258Smlaier#include <sys/timeout.h> 77126261Smlaier#endif 78126258Smlaier 79126258Smlaier#include <net/if.h> 80130933Sbrooks#if defined(__FreeBSD__) 81130933Sbrooks#include <net/if_clone.h> 82130933Sbrooks#endif 83126258Smlaier#include <net/if_types.h> 84126258Smlaier#include <net/route.h> 85126258Smlaier#include <net/bpf.h> 86145836Smlaier#include <netinet/tcp.h> 87145836Smlaier#include <netinet/tcp_seq.h> 88126258Smlaier 89126258Smlaier#ifdef INET 90126258Smlaier#include <netinet/in.h> 91130613Smlaier#include <netinet/in_systm.h> 92126258Smlaier#include <netinet/in_var.h> 93130613Smlaier#include <netinet/ip.h> 94130613Smlaier#include <netinet/ip_var.h> 95126258Smlaier#endif 96126258Smlaier 97126258Smlaier#ifdef INET6 98126258Smlaier#ifndef INET 99126258Smlaier#include <netinet/in.h> 100126258Smlaier#endif 101126258Smlaier#include <netinet6/nd6.h> 102126258Smlaier#endif /* INET6 */ 103126258Smlaier 104145836Smlaier#ifdef __FreeBSD__ 105145836Smlaier#include "opt_carp.h" 106145836Smlaier#ifdef DEV_CARP 107145836Smlaier#define NCARP 1 108159656Smlaier#else 109159656Smlaier#define NCARP 0 110145836Smlaier#endif 111145836Smlaier#else 112145836Smlaier#include "carp.h" 113145836Smlaier#endif 114145836Smlaier#if NCARP > 0 115145836Smlaierextern int carp_suppress_preempt; 116145836Smlaier#endif 117145836Smlaier 118126258Smlaier#include <net/pfvar.h> 119126258Smlaier#include <net/if_pfsync.h> 120126258Smlaier 121127145Smlaier#ifdef __FreeBSD__ 122127145Smlaier#define PFSYNCNAME "pfsync" 123126261Smlaier#endif 124126261Smlaier 125126258Smlaier#define PFSYNC_MINMTU \ 126126258Smlaier (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 127126258Smlaier 128126258Smlaier#ifdef PFSYNCDEBUG 129126258Smlaier#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 130126258Smlaierint pfsyncdebug; 131126258Smlaier#else 132126258Smlaier#define DPRINTF(x) 133126258Smlaier#endif 134126258Smlaier 135127145Smlaier#ifndef __FreeBSD__ 136130613Smlaierstruct pfsync_softc pfsyncif; 137126261Smlaier#endif 138130613Smlaierstruct pfsyncstats pfsyncstats; 139127145Smlaier#ifdef __FreeBSD__ 140148015SmlaierSYSCTL_DECL(_net_inet_pfsync); 141148015SmlaierSYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW, 142148015Smlaier &pfsyncstats, pfsyncstats, 143148015Smlaier "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 144130613Smlaier 145130613Smlaier/* 146130613Smlaier * Locking notes: 147130613Smlaier * Whenever we really touch/look at the state table we have to hold the 148130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per 149130613Smlaier * softc lock instead. 150130613Smlaier * 151130613Smlaier */ 152130613Smlaier 153128209Sbrooksstatic void pfsync_clone_destroy(struct ifnet *); 154160195Ssamstatic int pfsync_clone_create(struct if_clone *, int, caddr_t params); 155147261Smlaierstatic void pfsync_senddef(void *); 156126261Smlaier#else 157126258Smlaiervoid pfsyncattach(int); 158126261Smlaier#endif 159130613Smlaiervoid pfsync_setmtu(struct pfsync_softc *, int); 160130613Smlaierint pfsync_insert_net_state(struct pfsync_state *); 161126258Smlaierint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 162130613Smlaier struct rtentry *); 163126258Smlaierint pfsyncioctl(struct ifnet *, u_long, caddr_t); 164126258Smlaiervoid pfsyncstart(struct ifnet *); 165126258Smlaier 166130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 167130613Smlaierint pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 168130613Smlaierint pfsync_sendout(struct pfsync_softc *); 169130613Smlaiervoid pfsync_timeout(void *); 170130613Smlaiervoid pfsync_send_bus(struct pfsync_softc *, u_int8_t); 171130613Smlaiervoid pfsync_bulk_update(void *); 172130613Smlaiervoid pfsync_bulkfail(void *); 173126258Smlaier 174145836Smlaierint pfsync_sync_ok; 175127145Smlaier#ifndef __FreeBSD__ 176126258Smlaierextern int ifqmaxlen; 177130613Smlaierextern struct timeval time; 178130613Smlaierextern struct timeval mono_time; 179130613Smlaierextern int hz; 180126261Smlaier#endif 181126258Smlaier 182127145Smlaier#ifdef __FreeBSD__ 183126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 184126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 185147256Sbrooks#define SCP2IFP(sc) ((sc)->sc_ifp) 186130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1); 187126261Smlaier 188128209Sbrooksstatic void 189126261Smlaierpfsync_clone_destroy(struct ifnet *ifp) 190126261Smlaier{ 191126261Smlaier struct pfsync_softc *sc; 192126261Smlaier 193130613Smlaier sc = ifp->if_softc; 194126261Smlaier callout_stop(&sc->sc_tmo); 195130613Smlaier callout_stop(&sc->sc_bulk_tmo); 196130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 197126261Smlaier 198147261Smlaier callout_stop(&sc->sc_send_tmo); 199147261Smlaier 200126261Smlaier#if NBPFILTER > 0 201126261Smlaier bpfdetach(ifp); 202126261Smlaier#endif 203126261Smlaier if_detach(ifp); 204147256Sbrooks if_free(ifp); 205126261Smlaier LIST_REMOVE(sc, sc_next); 206160164Smlaier free(sc->sc_imo.imo_membership, M_PFSYNC); 207126261Smlaier free(sc, M_PFSYNC); 208126261Smlaier} 209126261Smlaier 210128209Sbrooksstatic int 211160195Ssam#ifdef __FreeBSD__ 212160195Ssampfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params) 213160195Ssam#else 214126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit) 215160195Ssam#endif 216126261Smlaier{ 217126261Smlaier struct pfsync_softc *sc; 218130613Smlaier struct ifnet *ifp; 219126261Smlaier 220126261Smlaier MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 221130613Smlaier M_WAITOK|M_ZERO); 222147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 223147256Sbrooks if (ifp == NULL) { 224147256Sbrooks free(sc, M_PFSYNC); 225147256Sbrooks return (ENOSPC); 226147256Sbrooks } 227126261Smlaier 228130613Smlaier pfsync_sync_ok = 1; 229130613Smlaier sc->sc_mbuf = NULL; 230130613Smlaier sc->sc_mbuf_net = NULL; 231130613Smlaier sc->sc_statep.s = NULL; 232130613Smlaier sc->sc_statep_net.s = NULL; 233130613Smlaier sc->sc_maxupdates = 128; 234159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 235130613Smlaier sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 236130613Smlaier sc->sc_ureq_received = 0; 237130613Smlaier sc->sc_ureq_sent = 0; 238160164Smlaier sc->sc_imo.imo_membership = (struct in_multi **)malloc( 239160164Smlaier (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 240160164Smlaier M_WAITOK); 241160164Smlaier sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 242130613Smlaier 243141584Smlaier ifp = SCP2IFP(sc); 244130613Smlaier if_initname(ifp, ifc->ifc_name, unit); 245130613Smlaier ifp->if_ioctl = pfsyncioctl; 246130613Smlaier ifp->if_output = pfsyncoutput; 247130613Smlaier ifp->if_start = pfsyncstart; 248130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 249130613Smlaier ifp->if_hdrlen = PFSYNC_HDRLEN; 250130613Smlaier ifp->if_baudrate = IF_Mbps(100); 251130613Smlaier ifp->if_softc = sc; 252126261Smlaier pfsync_setmtu(sc, MCLBYTES); 253147321Smlaier callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE); 254147321Smlaier callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE); 255147321Smlaier callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE); 256147321Smlaier callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE); 257147614Smlaier sc->sc_ifq.ifq_maxlen = ifqmaxlen; 258147261Smlaier mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue", 259147261Smlaier MTX_DEF); 260141584Smlaier if_attach(ifp); 261126261Smlaier 262126261Smlaier LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 263126261Smlaier#if NBPFILTER > 0 264141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 265126261Smlaier#endif 266126261Smlaier 267126261Smlaier return (0); 268126261Smlaier} 269126261Smlaier#else /* !__FreeBSD__ */ 270126261Smlaiervoid 271126258Smlaierpfsyncattach(int npfsync) 272126258Smlaier{ 273126258Smlaier struct ifnet *ifp; 274126258Smlaier 275130613Smlaier pfsync_sync_ok = 1; 276130613Smlaier bzero(&pfsyncif, sizeof(pfsyncif)); 277126258Smlaier pfsyncif.sc_mbuf = NULL; 278130613Smlaier pfsyncif.sc_mbuf_net = NULL; 279130613Smlaier pfsyncif.sc_statep.s = NULL; 280130613Smlaier pfsyncif.sc_statep_net.s = NULL; 281130613Smlaier pfsyncif.sc_maxupdates = 128; 282145836Smlaier pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 283130613Smlaier pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 284130613Smlaier pfsyncif.sc_ureq_received = 0; 285130613Smlaier pfsyncif.sc_ureq_sent = 0; 286126258Smlaier ifp = &pfsyncif.sc_if; 287126258Smlaier strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); 288126258Smlaier ifp->if_softc = &pfsyncif; 289126258Smlaier ifp->if_ioctl = pfsyncioctl; 290126258Smlaier ifp->if_output = pfsyncoutput; 291126258Smlaier ifp->if_start = pfsyncstart; 292126258Smlaier ifp->if_type = IFT_PFSYNC; 293126258Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 294126258Smlaier ifp->if_hdrlen = PFSYNC_HDRLEN; 295126258Smlaier pfsync_setmtu(&pfsyncif, MCLBYTES); 296126258Smlaier timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); 297130613Smlaier timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); 298130613Smlaier timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); 299126258Smlaier if_attach(ifp); 300126258Smlaier if_alloc_sadl(ifp); 301126258Smlaier 302126258Smlaier#if NBPFILTER > 0 303126258Smlaier bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 304126258Smlaier#endif 305126258Smlaier} 306126261Smlaier#endif 307126258Smlaier 308126258Smlaier/* 309126258Smlaier * Start output on the pfsync interface. 310126258Smlaier */ 311126258Smlaiervoid 312126258Smlaierpfsyncstart(struct ifnet *ifp) 313126258Smlaier{ 314130613Smlaier#ifdef __FreeBSD__ 315130613Smlaier IF_LOCK(&ifp->if_snd); 316130613Smlaier _IF_DROP(&ifp->if_snd); 317130613Smlaier _IF_DRAIN(&ifp->if_snd); 318130613Smlaier IF_UNLOCK(&ifp->if_snd); 319130613Smlaier#else 320126258Smlaier struct mbuf *m; 321126258Smlaier int s; 322126258Smlaier 323126258Smlaier for (;;) { 324126258Smlaier s = splimp(); 325126258Smlaier IF_DROP(&ifp->if_snd); 326126258Smlaier IF_DEQUEUE(&ifp->if_snd, m); 327126258Smlaier splx(s); 328126258Smlaier 329126258Smlaier if (m == NULL) 330126258Smlaier return; 331126258Smlaier else 332126258Smlaier m_freem(m); 333126258Smlaier } 334130613Smlaier#endif 335126258Smlaier} 336126258Smlaier 337126258Smlaierint 338130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp) 339130613Smlaier{ 340130613Smlaier struct pf_state *st = NULL; 341130613Smlaier struct pf_rule *r = NULL; 342130613Smlaier struct pfi_kif *kif; 343130613Smlaier 344130613Smlaier#ifdef __FreeBSD__ 345130613Smlaier PF_ASSERT(MA_OWNED); 346130613Smlaier#endif 347130613Smlaier if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 348130613Smlaier printf("pfsync_insert_net_state: invalid creator id:" 349130613Smlaier " %08x\n", ntohl(sp->creatorid)); 350130613Smlaier return (EINVAL); 351130613Smlaier } 352130613Smlaier 353130613Smlaier kif = pfi_lookup_create(sp->ifname); 354130613Smlaier if (kif == NULL) { 355130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 356130613Smlaier printf("pfsync_insert_net_state: " 357130613Smlaier "unknown interface: %s\n", sp->ifname); 358130613Smlaier /* skip this state */ 359130613Smlaier return (0); 360130613Smlaier } 361130613Smlaier 362130613Smlaier /* 363130613Smlaier * Just use the default rule until we have infrastructure to find the 364130613Smlaier * best matching rule. 365130613Smlaier */ 366130613Smlaier r = &pf_default_rule; 367130613Smlaier 368130613Smlaier if (!r->max_states || r->states < r->max_states) 369130613Smlaier st = pool_get(&pf_state_pl, PR_NOWAIT); 370130613Smlaier if (st == NULL) { 371130613Smlaier pfi_maybe_destroy(kif); 372130613Smlaier return (ENOMEM); 373130613Smlaier } 374130613Smlaier bzero(st, sizeof(*st)); 375130613Smlaier 376130613Smlaier st->rule.ptr = r; 377130613Smlaier /* XXX get pointers to nat_rule and anchor */ 378130613Smlaier 379145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 380145836Smlaier r->states++; 381145836Smlaier 382130613Smlaier /* fill in the rest of the state entry */ 383130613Smlaier pf_state_host_ntoh(&sp->lan, &st->lan); 384130613Smlaier pf_state_host_ntoh(&sp->gwy, &st->gwy); 385130613Smlaier pf_state_host_ntoh(&sp->ext, &st->ext); 386130613Smlaier 387130613Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 388130613Smlaier pf_state_peer_ntoh(&sp->dst, &st->dst); 389130613Smlaier 390130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 391145836Smlaier st->creation = time_second - ntohl(sp->creation); 392130613Smlaier st->expire = ntohl(sp->expire) + time_second; 393130613Smlaier 394130613Smlaier st->af = sp->af; 395130613Smlaier st->proto = sp->proto; 396130613Smlaier st->direction = sp->direction; 397130613Smlaier st->log = sp->log; 398130613Smlaier st->timeout = sp->timeout; 399130613Smlaier st->allow_opts = sp->allow_opts; 400130613Smlaier 401130613Smlaier bcopy(sp->id, &st->id, sizeof(st->id)); 402130613Smlaier st->creatorid = sp->creatorid; 403145836Smlaier st->sync_flags = PFSTATE_FROMSYNC; 404130613Smlaier 405130613Smlaier 406130613Smlaier if (pf_insert_state(kif, st)) { 407130613Smlaier pfi_maybe_destroy(kif); 408145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 409145836Smlaier r->states--; 410130613Smlaier pool_put(&pf_state_pl, st); 411130613Smlaier return (EINVAL); 412130613Smlaier } 413130613Smlaier 414130613Smlaier return (0); 415130613Smlaier} 416130613Smlaier 417130613Smlaiervoid 418130613Smlaier#ifdef __FreeBSD__ 419130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 420130613Smlaier#else 421130613Smlaierpfsync_input(struct mbuf *m, ...) 422130613Smlaier#endif 423130613Smlaier{ 424130613Smlaier struct ip *ip = mtod(m, struct ip *); 425130613Smlaier struct pfsync_header *ph; 426130613Smlaier#ifdef __FreeBSD__ 427130613Smlaier struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 428130613Smlaier#else 429130613Smlaier struct pfsync_softc *sc = &pfsyncif; 430130613Smlaier#endif 431130613Smlaier struct pf_state *st, key; 432130613Smlaier struct pfsync_state *sp; 433130613Smlaier struct pfsync_state_upd *up; 434130613Smlaier struct pfsync_state_del *dp; 435130613Smlaier struct pfsync_state_clr *cp; 436130613Smlaier struct pfsync_state_upd_req *rup; 437130613Smlaier struct pfsync_state_bus *bus; 438130613Smlaier struct in_addr src; 439130613Smlaier struct mbuf *mp; 440145836Smlaier int iplen, action, error, i, s, count, offp, sfail, stale = 0; 441130613Smlaier 442130613Smlaier pfsyncstats.pfsyncs_ipackets++; 443130613Smlaier 444130613Smlaier /* verify that we have a sync interface configured */ 445130613Smlaier if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ 446130613Smlaier goto done; 447130613Smlaier 448130613Smlaier /* verify that the packet came in on the right interface */ 449130613Smlaier if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 450130613Smlaier pfsyncstats.pfsyncs_badif++; 451130613Smlaier goto done; 452130613Smlaier } 453130613Smlaier 454130613Smlaier /* verify that the IP TTL is 255. */ 455130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 456130613Smlaier pfsyncstats.pfsyncs_badttl++; 457130613Smlaier goto done; 458130613Smlaier } 459130613Smlaier 460130613Smlaier iplen = ip->ip_hl << 2; 461130613Smlaier 462130613Smlaier if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 463130613Smlaier pfsyncstats.pfsyncs_hdrops++; 464130613Smlaier goto done; 465130613Smlaier } 466130613Smlaier 467130613Smlaier if (iplen + sizeof(*ph) > m->m_len) { 468130613Smlaier if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 469130613Smlaier pfsyncstats.pfsyncs_hdrops++; 470130613Smlaier goto done; 471130613Smlaier } 472130613Smlaier ip = mtod(m, struct ip *); 473130613Smlaier } 474130613Smlaier ph = (struct pfsync_header *)((char *)ip + iplen); 475130613Smlaier 476130613Smlaier /* verify the version */ 477130613Smlaier if (ph->version != PFSYNC_VERSION) { 478130613Smlaier pfsyncstats.pfsyncs_badver++; 479130613Smlaier goto done; 480130613Smlaier } 481130613Smlaier 482130613Smlaier action = ph->action; 483130613Smlaier count = ph->count; 484130613Smlaier 485130613Smlaier /* make sure it's a valid action code */ 486130613Smlaier if (action >= PFSYNC_ACT_MAX) { 487130613Smlaier pfsyncstats.pfsyncs_badact++; 488130613Smlaier goto done; 489130613Smlaier } 490130613Smlaier 491130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 492130613Smlaier src = ip->ip_src; 493130613Smlaier 494130613Smlaier switch (action) { 495130613Smlaier case PFSYNC_ACT_CLR: { 496145836Smlaier struct pf_state *nexts; 497130613Smlaier struct pfi_kif *kif; 498130613Smlaier u_int32_t creatorid; 499130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 500130613Smlaier sizeof(*cp), &offp)) == NULL) { 501130613Smlaier pfsyncstats.pfsyncs_badlen++; 502130613Smlaier return; 503130613Smlaier } 504130613Smlaier cp = (struct pfsync_state_clr *)(mp->m_data + offp); 505130613Smlaier creatorid = cp->creatorid; 506130613Smlaier 507130613Smlaier s = splsoftnet(); 508130613Smlaier#ifdef __FreeBSD__ 509130613Smlaier PF_LOCK(); 510130613Smlaier#endif 511130613Smlaier if (cp->ifname[0] == '\0') { 512145836Smlaier for (st = RB_MIN(pf_state_tree_id, &tree_id); 513145836Smlaier st; st = nexts) { 514145836Smlaier nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 515145836Smlaier if (st->creatorid == creatorid) { 516130613Smlaier st->timeout = PFTM_PURGE; 517145836Smlaier pf_purge_expired_state(st); 518145836Smlaier } 519130613Smlaier } 520130613Smlaier } else { 521130613Smlaier kif = pfi_lookup_if(cp->ifname); 522130613Smlaier if (kif == NULL) { 523130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 524130613Smlaier printf("pfsync_input: PFSYNC_ACT_CLR " 525130613Smlaier "bad interface: %s\n", cp->ifname); 526130613Smlaier splx(s); 527130613Smlaier#ifdef __FreeBSD__ 528130613Smlaier PF_UNLOCK(); 529130613Smlaier#endif 530130613Smlaier goto done; 531130613Smlaier } 532145836Smlaier for (st = RB_MIN(pf_state_tree_lan_ext, 533145836Smlaier &kif->pfik_lan_ext); st; st = nexts) { 534145836Smlaier nexts = RB_NEXT(pf_state_tree_lan_ext, 535145836Smlaier &kif->pfik_lan_ext, st); 536145836Smlaier if (st->creatorid == creatorid) { 537130613Smlaier st->timeout = PFTM_PURGE; 538145836Smlaier pf_purge_expired_state(st); 539145836Smlaier } 540130613Smlaier } 541130613Smlaier } 542130613Smlaier#ifdef __FreeBSD__ 543130613Smlaier PF_UNLOCK(); 544130613Smlaier#endif 545130613Smlaier splx(s); 546130613Smlaier 547130613Smlaier break; 548130613Smlaier } 549130613Smlaier case PFSYNC_ACT_INS: 550130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 551130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 552130613Smlaier pfsyncstats.pfsyncs_badlen++; 553130613Smlaier return; 554130613Smlaier } 555130613Smlaier 556130613Smlaier s = splsoftnet(); 557130613Smlaier#ifdef __FreeBSD__ 558130613Smlaier PF_LOCK(); 559130613Smlaier#endif 560130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 561130613Smlaier i < count; i++, sp++) { 562130613Smlaier /* check for invalid values */ 563130613Smlaier if (sp->timeout >= PFTM_MAX || 564130613Smlaier sp->src.state > PF_TCPS_PROXY_DST || 565130613Smlaier sp->dst.state > PF_TCPS_PROXY_DST || 566130613Smlaier sp->direction > PF_OUT || 567130613Smlaier (sp->af != AF_INET && sp->af != AF_INET6)) { 568130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 569130613Smlaier printf("pfsync_insert: PFSYNC_ACT_INS: " 570130613Smlaier "invalid value\n"); 571130613Smlaier pfsyncstats.pfsyncs_badstate++; 572130613Smlaier continue; 573130613Smlaier } 574130613Smlaier 575130613Smlaier if ((error = pfsync_insert_net_state(sp))) { 576130613Smlaier if (error == ENOMEM) { 577130613Smlaier splx(s); 578130613Smlaier#ifdef __FreeBSD__ 579130613Smlaier PF_UNLOCK(); 580130613Smlaier#endif 581130613Smlaier goto done; 582130613Smlaier } 583130613Smlaier continue; 584130613Smlaier } 585130613Smlaier } 586130613Smlaier#ifdef __FreeBSD__ 587130613Smlaier PF_UNLOCK(); 588130613Smlaier#endif 589130613Smlaier splx(s); 590130613Smlaier break; 591130613Smlaier case PFSYNC_ACT_UPD: 592130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 593130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 594130613Smlaier pfsyncstats.pfsyncs_badlen++; 595130613Smlaier return; 596130613Smlaier } 597130613Smlaier 598130613Smlaier s = splsoftnet(); 599130613Smlaier#ifdef __FreeBSD__ 600130613Smlaier PF_LOCK(); 601130613Smlaier#endif 602130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 603130613Smlaier i < count; i++, sp++) { 604145836Smlaier int flags = PFSYNC_FLAG_STALE; 605145836Smlaier 606130613Smlaier /* check for invalid values */ 607130613Smlaier if (sp->timeout >= PFTM_MAX || 608130613Smlaier sp->src.state > PF_TCPS_PROXY_DST || 609130613Smlaier sp->dst.state > PF_TCPS_PROXY_DST) { 610130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 611130613Smlaier printf("pfsync_insert: PFSYNC_ACT_UPD: " 612130613Smlaier "invalid value\n"); 613130613Smlaier pfsyncstats.pfsyncs_badstate++; 614130613Smlaier continue; 615130613Smlaier } 616130613Smlaier 617130613Smlaier bcopy(sp->id, &key.id, sizeof(key.id)); 618130613Smlaier key.creatorid = sp->creatorid; 619130613Smlaier 620130613Smlaier st = pf_find_state_byid(&key); 621130613Smlaier if (st == NULL) { 622130613Smlaier /* insert the update */ 623130613Smlaier if (pfsync_insert_net_state(sp)) 624130613Smlaier pfsyncstats.pfsyncs_badstate++; 625130613Smlaier continue; 626130613Smlaier } 627145836Smlaier sfail = 0; 628145836Smlaier if (st->proto == IPPROTO_TCP) { 629145836Smlaier /* 630145836Smlaier * The state should never go backwards except 631145836Smlaier * for syn-proxy states. Neither should the 632145836Smlaier * sequence window slide backwards. 633145836Smlaier */ 634145836Smlaier if (st->src.state > sp->src.state && 635145836Smlaier (st->src.state < PF_TCPS_PROXY_SRC || 636145836Smlaier sp->src.state >= PF_TCPS_PROXY_SRC)) 637145836Smlaier sfail = 1; 638145836Smlaier else if (SEQ_GT(st->src.seqlo, 639145836Smlaier ntohl(sp->src.seqlo))) 640145836Smlaier sfail = 3; 641145836Smlaier else if (st->dst.state > sp->dst.state) { 642145836Smlaier /* There might still be useful 643145836Smlaier * information about the src state here, 644145836Smlaier * so import that part of the update, 645145836Smlaier * then "fail" so we send the updated 646145836Smlaier * state back to the peer who is missing 647145836Smlaier * our what we know. */ 648145836Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 649145836Smlaier /* XXX do anything with timeouts? */ 650145836Smlaier sfail = 7; 651145836Smlaier flags = 0; 652145836Smlaier } else if (st->dst.state >= TCPS_SYN_SENT && 653145836Smlaier SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo))) 654145836Smlaier sfail = 4; 655145836Smlaier } else { 656145836Smlaier /* 657145836Smlaier * Non-TCP protocol state machine always go 658145836Smlaier * forwards 659145836Smlaier */ 660145836Smlaier if (st->src.state > sp->src.state) 661145836Smlaier sfail = 5; 662145836Smlaier else if ( st->dst.state > sp->dst.state) 663145836Smlaier sfail = 6; 664145836Smlaier } 665145836Smlaier if (sfail) { 666145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 667145836Smlaier printf("pfsync: %s stale update " 668145836Smlaier "(%d) id: %016llx " 669145836Smlaier "creatorid: %08x\n", 670145836Smlaier (sfail < 7 ? "ignoring" 671145836Smlaier : "partial"), sfail, 672145836Smlaier#ifdef __FreeBSD__ 673145836Smlaier (unsigned long long)be64toh(st->id), 674145836Smlaier#else 675145836Smlaier betoh64(st->id), 676145836Smlaier#endif 677145836Smlaier ntohl(st->creatorid)); 678145836Smlaier pfsyncstats.pfsyncs_badstate++; 679145836Smlaier 680145836Smlaier if (!(sp->sync_flags & PFSTATE_STALE)) { 681145836Smlaier /* we have a better state, send it */ 682145836Smlaier if (sc->sc_mbuf != NULL && !stale) 683145836Smlaier pfsync_sendout(sc); 684145836Smlaier stale++; 685145836Smlaier if (!st->sync_flags) 686145836Smlaier pfsync_pack_state( 687145836Smlaier PFSYNC_ACT_UPD, st, flags); 688145836Smlaier } 689145836Smlaier continue; 690145836Smlaier } 691130613Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 692130613Smlaier pf_state_peer_ntoh(&sp->dst, &st->dst); 693130613Smlaier st->expire = ntohl(sp->expire) + time_second; 694130613Smlaier st->timeout = sp->timeout; 695130613Smlaier } 696145836Smlaier if (stale && sc->sc_mbuf != NULL) 697145836Smlaier pfsync_sendout(sc); 698130613Smlaier#ifdef __FreeBSD__ 699130613Smlaier PF_UNLOCK(); 700130613Smlaier#endif 701130613Smlaier splx(s); 702130613Smlaier break; 703130613Smlaier /* 704130613Smlaier * It's not strictly necessary for us to support the "uncompressed" 705130613Smlaier * delete action, but it's relatively simple and maintains consistency. 706130613Smlaier */ 707130613Smlaier case PFSYNC_ACT_DEL: 708130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 709130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 710130613Smlaier pfsyncstats.pfsyncs_badlen++; 711130613Smlaier return; 712130613Smlaier } 713130613Smlaier 714130613Smlaier s = splsoftnet(); 715130613Smlaier#ifdef __FreeBSD__ 716130613Smlaier PF_LOCK(); 717130613Smlaier#endif 718130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 719130613Smlaier i < count; i++, sp++) { 720130613Smlaier bcopy(sp->id, &key.id, sizeof(key.id)); 721130613Smlaier key.creatorid = sp->creatorid; 722130613Smlaier 723130613Smlaier st = pf_find_state_byid(&key); 724130613Smlaier if (st == NULL) { 725130613Smlaier pfsyncstats.pfsyncs_badstate++; 726130613Smlaier continue; 727130613Smlaier } 728130613Smlaier st->timeout = PFTM_PURGE; 729130613Smlaier st->sync_flags |= PFSTATE_FROMSYNC; 730145836Smlaier pf_purge_expired_state(st); 731130613Smlaier } 732130613Smlaier#ifdef __FreeBSD__ 733130613Smlaier PF_UNLOCK(); 734130613Smlaier#endif 735130613Smlaier splx(s); 736130613Smlaier break; 737130613Smlaier case PFSYNC_ACT_UPD_C: { 738130613Smlaier int update_requested = 0; 739130613Smlaier 740130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 741130613Smlaier count * sizeof(*up), &offp)) == NULL) { 742130613Smlaier pfsyncstats.pfsyncs_badlen++; 743130613Smlaier return; 744130613Smlaier } 745130613Smlaier 746130613Smlaier s = splsoftnet(); 747130613Smlaier#ifdef __FreeBSD__ 748130613Smlaier PF_LOCK(); 749130613Smlaier#endif 750130613Smlaier for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 751130613Smlaier i < count; i++, up++) { 752130613Smlaier /* check for invalid values */ 753130613Smlaier if (up->timeout >= PFTM_MAX || 754130613Smlaier up->src.state > PF_TCPS_PROXY_DST || 755130613Smlaier up->dst.state > PF_TCPS_PROXY_DST) { 756130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 757130613Smlaier printf("pfsync_insert: " 758130613Smlaier "PFSYNC_ACT_UPD_C: " 759130613Smlaier "invalid value\n"); 760130613Smlaier pfsyncstats.pfsyncs_badstate++; 761130613Smlaier continue; 762130613Smlaier } 763130613Smlaier 764130613Smlaier bcopy(up->id, &key.id, sizeof(key.id)); 765130613Smlaier key.creatorid = up->creatorid; 766130613Smlaier 767130613Smlaier st = pf_find_state_byid(&key); 768130613Smlaier if (st == NULL) { 769130613Smlaier /* We don't have this state. Ask for it. */ 770145836Smlaier error = pfsync_request_update(up, &src); 771145836Smlaier if (error == ENOMEM) { 772145836Smlaier splx(s); 773145836Smlaier goto done; 774145836Smlaier } 775130613Smlaier update_requested = 1; 776130613Smlaier pfsyncstats.pfsyncs_badstate++; 777130613Smlaier continue; 778130613Smlaier } 779145836Smlaier sfail = 0; 780145836Smlaier if (st->proto == IPPROTO_TCP) { 781145836Smlaier /* 782145836Smlaier * The state should never go backwards except 783145836Smlaier * for syn-proxy states. Neither should the 784145836Smlaier * sequence window slide backwards. 785145836Smlaier */ 786145836Smlaier if (st->src.state > up->src.state && 787145836Smlaier (st->src.state < PF_TCPS_PROXY_SRC || 788145836Smlaier up->src.state >= PF_TCPS_PROXY_SRC)) 789145836Smlaier sfail = 1; 790145836Smlaier else if (st->dst.state > up->dst.state) 791145836Smlaier sfail = 2; 792145836Smlaier else if (SEQ_GT(st->src.seqlo, 793145836Smlaier ntohl(up->src.seqlo))) 794145836Smlaier sfail = 3; 795145836Smlaier else if (st->dst.state >= TCPS_SYN_SENT && 796145836Smlaier SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo))) 797145836Smlaier sfail = 4; 798145836Smlaier } else { 799145836Smlaier /* 800145836Smlaier * Non-TCP protocol state machine always go 801145836Smlaier * forwards 802145836Smlaier */ 803145836Smlaier if (st->src.state > up->src.state) 804145836Smlaier sfail = 5; 805145836Smlaier else if (st->dst.state > up->dst.state) 806145836Smlaier sfail = 6; 807145836Smlaier } 808145836Smlaier if (sfail) { 809145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 810145836Smlaier printf("pfsync: ignoring stale update " 811145836Smlaier "(%d) id: %016llx " 812145836Smlaier "creatorid: %08x\n", sfail, 813145836Smlaier#ifdef __FreeBSD__ 814145836Smlaier (unsigned long long)be64toh(st->id), 815145836Smlaier#else 816145836Smlaier betoh64(st->id), 817145836Smlaier#endif 818145836Smlaier ntohl(st->creatorid)); 819145836Smlaier pfsyncstats.pfsyncs_badstate++; 820145836Smlaier 821145836Smlaier /* we have a better state, send it out */ 822145836Smlaier if ((!stale || update_requested) && 823145836Smlaier sc->sc_mbuf != NULL) { 824145836Smlaier pfsync_sendout(sc); 825145836Smlaier update_requested = 0; 826145836Smlaier } 827145836Smlaier stale++; 828145836Smlaier if (!st->sync_flags) 829145836Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, st, 830145836Smlaier PFSYNC_FLAG_STALE); 831145836Smlaier continue; 832145836Smlaier } 833130613Smlaier pf_state_peer_ntoh(&up->src, &st->src); 834130613Smlaier pf_state_peer_ntoh(&up->dst, &st->dst); 835130613Smlaier st->expire = ntohl(up->expire) + time_second; 836130613Smlaier st->timeout = up->timeout; 837130613Smlaier } 838145836Smlaier if ((update_requested || stale) && sc->sc_mbuf) 839130613Smlaier pfsync_sendout(sc); 840130613Smlaier#ifdef __FreeBSD__ 841130613Smlaier PF_UNLOCK(); 842130613Smlaier#endif 843130613Smlaier splx(s); 844130613Smlaier break; 845130613Smlaier } 846130613Smlaier case PFSYNC_ACT_DEL_C: 847130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 848130613Smlaier count * sizeof(*dp), &offp)) == NULL) { 849130613Smlaier pfsyncstats.pfsyncs_badlen++; 850130613Smlaier return; 851130613Smlaier } 852130613Smlaier 853130613Smlaier s = splsoftnet(); 854130613Smlaier#ifdef __FreeBSD__ 855130613Smlaier PF_LOCK(); 856130613Smlaier#endif 857130613Smlaier for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 858130613Smlaier i < count; i++, dp++) { 859130613Smlaier bcopy(dp->id, &key.id, sizeof(key.id)); 860130613Smlaier key.creatorid = dp->creatorid; 861130613Smlaier 862130613Smlaier st = pf_find_state_byid(&key); 863130613Smlaier if (st == NULL) { 864130613Smlaier pfsyncstats.pfsyncs_badstate++; 865130613Smlaier continue; 866130613Smlaier } 867130613Smlaier st->timeout = PFTM_PURGE; 868130613Smlaier st->sync_flags |= PFSTATE_FROMSYNC; 869145836Smlaier pf_purge_expired_state(st); 870130613Smlaier } 871130613Smlaier#ifdef __FreeBSD__ 872130613Smlaier PF_UNLOCK(); 873130613Smlaier#endif 874130613Smlaier splx(s); 875130613Smlaier break; 876130613Smlaier case PFSYNC_ACT_INS_F: 877130613Smlaier case PFSYNC_ACT_DEL_F: 878130613Smlaier /* not implemented */ 879130613Smlaier break; 880130613Smlaier case PFSYNC_ACT_UREQ: 881130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 882130613Smlaier count * sizeof(*rup), &offp)) == NULL) { 883130613Smlaier pfsyncstats.pfsyncs_badlen++; 884130613Smlaier return; 885130613Smlaier } 886130613Smlaier 887130613Smlaier s = splsoftnet(); 888130613Smlaier#ifdef __FreeBSD__ 889130613Smlaier PF_LOCK(); 890130613Smlaier#endif 891130613Smlaier if (sc->sc_mbuf != NULL) 892130613Smlaier pfsync_sendout(sc); 893130613Smlaier for (i = 0, 894130613Smlaier rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 895130613Smlaier i < count; i++, rup++) { 896130613Smlaier bcopy(rup->id, &key.id, sizeof(key.id)); 897130613Smlaier key.creatorid = rup->creatorid; 898130613Smlaier 899130613Smlaier if (key.id == 0 && key.creatorid == 0) { 900130613Smlaier sc->sc_ureq_received = time_uptime; 901130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 902130613Smlaier printf("pfsync: received " 903130613Smlaier "bulk update request\n"); 904130613Smlaier pfsync_send_bus(sc, PFSYNC_BUS_START); 905130613Smlaier#ifdef __FreeBSD__ 906130613Smlaier callout_reset(&sc->sc_bulk_tmo, 1 * hz, 907130613Smlaier pfsync_bulk_update, 908130613Smlaier LIST_FIRST(&pfsync_list)); 909130613Smlaier#else 910130613Smlaier timeout_add(&sc->sc_bulk_tmo, 1 * hz); 911130613Smlaier#endif 912130613Smlaier } else { 913130613Smlaier st = pf_find_state_byid(&key); 914130613Smlaier if (st == NULL) { 915130613Smlaier pfsyncstats.pfsyncs_badstate++; 916130613Smlaier continue; 917130613Smlaier } 918145836Smlaier if (!st->sync_flags) 919145836Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, 920145836Smlaier st, 0); 921130613Smlaier } 922130613Smlaier } 923130613Smlaier if (sc->sc_mbuf != NULL) 924130613Smlaier pfsync_sendout(sc); 925130613Smlaier#ifdef __FreeBSD__ 926130613Smlaier PF_UNLOCK(); 927130613Smlaier#endif 928130613Smlaier splx(s); 929130613Smlaier break; 930130613Smlaier case PFSYNC_ACT_BUS: 931130613Smlaier /* If we're not waiting for a bulk update, who cares. */ 932130613Smlaier if (sc->sc_ureq_sent == 0) 933130613Smlaier break; 934130613Smlaier 935130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 936130613Smlaier sizeof(*bus), &offp)) == NULL) { 937130613Smlaier pfsyncstats.pfsyncs_badlen++; 938130613Smlaier return; 939130613Smlaier } 940130613Smlaier bus = (struct pfsync_state_bus *)(mp->m_data + offp); 941130613Smlaier switch (bus->status) { 942130613Smlaier case PFSYNC_BUS_START: 943130613Smlaier#ifdef __FreeBSD__ 944130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 945130613Smlaier pf_pool_limits[PF_LIMIT_STATES].limit / 946130613Smlaier (PFSYNC_BULKPACKETS * sc->sc_maxcount), 947130613Smlaier pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 948130613Smlaier#else 949130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 950130613Smlaier pf_pool_limits[PF_LIMIT_STATES].limit / 951130613Smlaier (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 952130613Smlaier#endif 953130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 954130613Smlaier printf("pfsync: received bulk " 955130613Smlaier "update start\n"); 956130613Smlaier break; 957130613Smlaier case PFSYNC_BUS_END: 958130613Smlaier if (time_uptime - ntohl(bus->endtime) >= 959130613Smlaier sc->sc_ureq_sent) { 960130613Smlaier /* that's it, we're happy */ 961130613Smlaier sc->sc_ureq_sent = 0; 962130613Smlaier sc->sc_bulk_tries = 0; 963130613Smlaier#ifdef __FreeBSD__ 964130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 965130613Smlaier#else 966130613Smlaier timeout_del(&sc->sc_bulkfail_tmo); 967130613Smlaier#endif 968145836Smlaier#if NCARP > 0 /* XXX_IMPORT */ 969145836Smlaier if (!pfsync_sync_ok) 970145836Smlaier carp_suppress_preempt--; 971145836Smlaier#endif 972130613Smlaier pfsync_sync_ok = 1; 973130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 974130613Smlaier printf("pfsync: received valid " 975130613Smlaier "bulk update end\n"); 976130613Smlaier } else { 977130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 978130613Smlaier printf("pfsync: received invalid " 979130613Smlaier "bulk update end: bad timestamp\n"); 980130613Smlaier } 981130613Smlaier break; 982130613Smlaier } 983130613Smlaier break; 984130613Smlaier } 985130613Smlaier 986130613Smlaierdone: 987130613Smlaier if (m) 988130613Smlaier m_freem(m); 989130613Smlaier} 990130613Smlaier 991130613Smlaierint 992126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 993126258Smlaier struct rtentry *rt) 994126258Smlaier{ 995126258Smlaier m_freem(m); 996126258Smlaier return (0); 997126258Smlaier} 998126258Smlaier 999126258Smlaier/* ARGSUSED */ 1000126258Smlaierint 1001126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1002126258Smlaier{ 1003130613Smlaier#ifndef __FreeBSD__ 1004130613Smlaier struct proc *p = curproc; 1005130613Smlaier#endif 1006126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1007126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1008130613Smlaier struct ip_moptions *imo = &sc->sc_imo; 1009130613Smlaier struct pfsyncreq pfsyncr; 1010130613Smlaier struct ifnet *sifp; 1011130613Smlaier int s, error; 1012126258Smlaier 1013126258Smlaier switch (cmd) { 1014126258Smlaier case SIOCSIFADDR: 1015126258Smlaier case SIOCAIFADDR: 1016126258Smlaier case SIOCSIFDSTADDR: 1017126258Smlaier case SIOCSIFFLAGS: 1018148891Smlaier#ifdef __FreeBSD__ 1019126258Smlaier if (ifp->if_flags & IFF_UP) 1020148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1021126258Smlaier else 1022148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1023148891Smlaier#else 1024148891Smlaier if (ifp->if_flags & IFF_UP) 1025148891Smlaier ifp->if_flags |= IFF_RUNNING; 1026148891Smlaier else 1027148891Smlaier ifp->if_flags &= ~IFF_RUNNING; 1028148891Smlaier#endif 1029126258Smlaier break; 1030126258Smlaier case SIOCSIFMTU: 1031126258Smlaier if (ifr->ifr_mtu < PFSYNC_MINMTU) 1032126258Smlaier return (EINVAL); 1033126258Smlaier if (ifr->ifr_mtu > MCLBYTES) 1034126258Smlaier ifr->ifr_mtu = MCLBYTES; 1035126258Smlaier s = splnet(); 1036130613Smlaier#ifdef __FreeBSD__ 1037130613Smlaier PF_LOCK(); 1038130613Smlaier#endif 1039130613Smlaier if (ifr->ifr_mtu < ifp->if_mtu) { 1040126258Smlaier pfsync_sendout(sc); 1041130613Smlaier } 1042126258Smlaier pfsync_setmtu(sc, ifr->ifr_mtu); 1043130613Smlaier#ifdef __FreeBSD__ 1044130613Smlaier PF_UNLOCK(); 1045130613Smlaier#endif 1046126258Smlaier splx(s); 1047126258Smlaier break; 1048130613Smlaier case SIOCGETPFSYNC: 1049130613Smlaier#ifdef __FreeBSD__ 1050130613Smlaier /* XXX: read unlocked */ 1051130613Smlaier#endif 1052130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1053130613Smlaier if (sc->sc_sync_ifp) 1054145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1055130613Smlaier sc->sc_sync_ifp->if_xname, IFNAMSIZ); 1056145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1057130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1058130613Smlaier if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 1059130613Smlaier return (error); 1060130613Smlaier break; 1061130613Smlaier case SIOCSETPFSYNC: 1062130613Smlaier#ifdef __FreeBSD__ 1063164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1064130613Smlaier#else 1065130613Smlaier if ((error = suser(p, p->p_acflag)) != 0) 1066130613Smlaier#endif 1067130613Smlaier return (error); 1068130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1069130613Smlaier return (error); 1070130613Smlaier 1071145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1072159603Smlaier#ifdef __FreeBSD__ 1073159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1074159603Smlaier#else 1075145836Smlaier sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1076159603Smlaier#endif 1077145836Smlaier else 1078145836Smlaier sc->sc_sync_peer.s_addr = 1079145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1080145836Smlaier 1081130613Smlaier if (pfsyncr.pfsyncr_maxupdates > 255) 1082130613Smlaier return (EINVAL); 1083130613Smlaier#ifdef __FreeBSD__ 1084147261Smlaier callout_drain(&sc->sc_send_tmo); 1085130613Smlaier PF_LOCK(); 1086130613Smlaier#endif 1087130613Smlaier sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1088130613Smlaier 1089145836Smlaier if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1090130613Smlaier sc->sc_sync_ifp = NULL; 1091130613Smlaier if (sc->sc_mbuf_net != NULL) { 1092130613Smlaier /* Don't keep stale pfsync packets around. */ 1093130613Smlaier s = splnet(); 1094130613Smlaier m_freem(sc->sc_mbuf_net); 1095130613Smlaier sc->sc_mbuf_net = NULL; 1096130613Smlaier sc->sc_statep_net.s = NULL; 1097130613Smlaier splx(s); 1098130613Smlaier } 1099145836Smlaier if (imo->imo_num_memberships > 0) { 1100145836Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1101145836Smlaier imo->imo_multicast_ifp = NULL; 1102145836Smlaier } 1103130613Smlaier#ifdef __FreeBSD__ 1104130613Smlaier PF_UNLOCK(); 1105130613Smlaier#endif 1106130613Smlaier break; 1107130613Smlaier } 1108145836Smlaier 1109145836Smlaier if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) { 1110130613Smlaier#ifdef __FreeBSD__ 1111130613Smlaier PF_UNLOCK(); 1112130613Smlaier#endif 1113130613Smlaier return (EINVAL); 1114130613Smlaier } 1115130613Smlaier 1116130613Smlaier s = splnet(); 1117141584Smlaier#ifdef __FreeBSD__ 1118141584Smlaier if (sifp->if_mtu < SCP2IFP(sc)->if_mtu || 1119141584Smlaier#else 1120130613Smlaier if (sifp->if_mtu < sc->sc_if.if_mtu || 1121141584Smlaier#endif 1122130613Smlaier (sc->sc_sync_ifp != NULL && 1123130613Smlaier sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 1124130613Smlaier sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1125130613Smlaier pfsync_sendout(sc); 1126130613Smlaier sc->sc_sync_ifp = sifp; 1127130613Smlaier 1128141584Smlaier#ifdef __FreeBSD__ 1129141584Smlaier pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu); 1130141584Smlaier#else 1131130613Smlaier pfsync_setmtu(sc, sc->sc_if.if_mtu); 1132141584Smlaier#endif 1133130613Smlaier 1134130613Smlaier if (imo->imo_num_memberships > 0) { 1135130613Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1136130613Smlaier imo->imo_multicast_ifp = NULL; 1137130613Smlaier } 1138130613Smlaier 1139145836Smlaier if (sc->sc_sync_ifp && 1140159603Smlaier#ifdef __FreeBSD__ 1141159603Smlaier sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1142159603Smlaier#else 1143145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1144159603Smlaier#endif 1145130613Smlaier struct in_addr addr; 1146130613Smlaier 1147145836Smlaier if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) { 1148145836Smlaier sc->sc_sync_ifp = NULL; 1149130613Smlaier#ifdef __FreeBSD__ 1150145836Smlaier PF_UNLOCK(); 1151145836Smlaier#endif 1152145836Smlaier splx(s); 1153145836Smlaier return (EADDRNOTAVAIL); 1154145836Smlaier } 1155145836Smlaier#ifdef __FreeBSD__ 1156130613Smlaier PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ 1157130613Smlaier addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1158130613Smlaier#else 1159130613Smlaier addr.s_addr = INADDR_PFSYNC_GROUP; 1160130613Smlaier#endif 1161145836Smlaier 1162130613Smlaier if ((imo->imo_membership[0] = 1163130613Smlaier in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 1164145836Smlaier sc->sc_sync_ifp = NULL; 1165130613Smlaier splx(s); 1166130613Smlaier return (ENOBUFS); 1167130613Smlaier } 1168130613Smlaier imo->imo_num_memberships++; 1169130613Smlaier imo->imo_multicast_ifp = sc->sc_sync_ifp; 1170130613Smlaier imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1171130613Smlaier imo->imo_multicast_loop = 0; 1172149982Smlaier#ifdef __FreeBSD__ 1173149982Smlaier PF_LOCK(); 1174149982Smlaier#endif 1175145836Smlaier } 1176130613Smlaier 1177145836Smlaier if (sc->sc_sync_ifp || 1178159603Smlaier#ifdef __FreeBSD__ 1179159603Smlaier sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) { 1180159603Smlaier#else 1181145836Smlaier sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) { 1182159603Smlaier#endif 1183130613Smlaier /* Request a full state table update. */ 1184130613Smlaier sc->sc_ureq_sent = time_uptime; 1185145836Smlaier#if NCARP > 0 1186145836Smlaier if (pfsync_sync_ok) 1187145836Smlaier carp_suppress_preempt++; 1188130613Smlaier#endif 1189130613Smlaier pfsync_sync_ok = 0; 1190130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1191130613Smlaier printf("pfsync: requesting bulk update\n"); 1192130613Smlaier#ifdef __FreeBSD__ 1193130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1194130613Smlaier pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 1195130613Smlaier#else 1196130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1197130613Smlaier#endif 1198145836Smlaier error = pfsync_request_update(NULL, NULL); 1199145836Smlaier if (error == ENOMEM) { 1200145836Smlaier#ifdef __FreeBSD__ 1201145836Smlaier PF_UNLOCK(); 1202145836Smlaier#endif 1203145836Smlaier splx(s); 1204145836Smlaier return (ENOMEM); 1205145836Smlaier } 1206130613Smlaier pfsync_sendout(sc); 1207130613Smlaier } 1208130613Smlaier#ifdef __FreeBSD__ 1209130613Smlaier PF_UNLOCK(); 1210130613Smlaier#endif 1211130613Smlaier splx(s); 1212130613Smlaier 1213130613Smlaier break; 1214130613Smlaier 1215126258Smlaier default: 1216126258Smlaier return (ENOTTY); 1217126258Smlaier } 1218126258Smlaier 1219126258Smlaier return (0); 1220126258Smlaier} 1221126258Smlaier 1222126258Smlaiervoid 1223130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 1224130613Smlaier{ 1225126258Smlaier int mtu; 1226130613Smlaier 1227130613Smlaier if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 1228130613Smlaier mtu = sc->sc_sync_ifp->if_mtu; 1229130613Smlaier else 1230130613Smlaier mtu = mtu_req; 1231130613Smlaier 1232130613Smlaier sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 1233130613Smlaier sizeof(struct pfsync_state); 1234130613Smlaier if (sc->sc_maxcount > 254) 1235130613Smlaier sc->sc_maxcount = 254; 1236141584Smlaier#ifdef __FreeBSD__ 1237141584Smlaier SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) + 1238141584Smlaier sc->sc_maxcount * sizeof(struct pfsync_state); 1239141584Smlaier#else 1240126258Smlaier sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 1241130613Smlaier sc->sc_maxcount * sizeof(struct pfsync_state); 1242141584Smlaier#endif 1243126258Smlaier} 1244126258Smlaier 1245126258Smlaierstruct mbuf * 1246130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 1247126258Smlaier{ 1248126258Smlaier struct pfsync_header *h; 1249126258Smlaier struct mbuf *m; 1250126258Smlaier int len; 1251126258Smlaier 1252130613Smlaier#ifdef __FreeBSD__ 1253130613Smlaier PF_ASSERT(MA_OWNED); 1254130613Smlaier#endif 1255126258Smlaier MGETHDR(m, M_DONTWAIT, MT_DATA); 1256126258Smlaier if (m == NULL) { 1257141584Smlaier#ifdef __FreeBSD__ 1258141584Smlaier SCP2IFP(sc)->if_oerrors++; 1259141584Smlaier#else 1260126258Smlaier sc->sc_if.if_oerrors++; 1261141584Smlaier#endif 1262126258Smlaier return (NULL); 1263126258Smlaier } 1264126258Smlaier 1265130613Smlaier switch (action) { 1266130613Smlaier case PFSYNC_ACT_CLR: 1267130613Smlaier len = sizeof(struct pfsync_header) + 1268130613Smlaier sizeof(struct pfsync_state_clr); 1269130613Smlaier break; 1270130613Smlaier case PFSYNC_ACT_UPD_C: 1271130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 1272130613Smlaier sizeof(struct pfsync_header); 1273130613Smlaier break; 1274130613Smlaier case PFSYNC_ACT_DEL_C: 1275130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 1276130613Smlaier sizeof(struct pfsync_header); 1277130613Smlaier break; 1278130613Smlaier case PFSYNC_ACT_UREQ: 1279130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 1280130613Smlaier sizeof(struct pfsync_header); 1281130613Smlaier break; 1282130613Smlaier case PFSYNC_ACT_BUS: 1283130613Smlaier len = sizeof(struct pfsync_header) + 1284130613Smlaier sizeof(struct pfsync_state_bus); 1285130613Smlaier break; 1286130613Smlaier default: 1287130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 1288130613Smlaier sizeof(struct pfsync_header); 1289130613Smlaier break; 1290130613Smlaier } 1291130613Smlaier 1292126258Smlaier if (len > MHLEN) { 1293126258Smlaier MCLGET(m, M_DONTWAIT); 1294126258Smlaier if ((m->m_flags & M_EXT) == 0) { 1295126258Smlaier m_free(m); 1296141584Smlaier#ifdef __FreeBSD__ 1297141584Smlaier SCP2IFP(sc)->if_oerrors++; 1298141584Smlaier#else 1299126258Smlaier sc->sc_if.if_oerrors++; 1300141584Smlaier#endif 1301126258Smlaier return (NULL); 1302126258Smlaier } 1303130613Smlaier m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 1304130613Smlaier } else 1305130613Smlaier MH_ALIGN(m, len); 1306130613Smlaier 1307126258Smlaier m->m_pkthdr.rcvif = NULL; 1308130613Smlaier m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 1309126258Smlaier h = mtod(m, struct pfsync_header *); 1310126258Smlaier h->version = PFSYNC_VERSION; 1311126258Smlaier h->af = 0; 1312126258Smlaier h->count = 0; 1313126258Smlaier h->action = action; 1314126258Smlaier 1315130613Smlaier *sp = (void *)((char *)h + PFSYNC_HDRLEN); 1316127145Smlaier#ifdef __FreeBSD__ 1317126261Smlaier callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 1318126261Smlaier LIST_FIRST(&pfsync_list)); 1319126261Smlaier#else 1320126258Smlaier timeout_add(&sc->sc_tmo, hz); 1321126261Smlaier#endif 1322126258Smlaier return (m); 1323126258Smlaier} 1324126258Smlaier 1325126258Smlaierint 1326145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) 1327126258Smlaier{ 1328127145Smlaier#ifdef __FreeBSD__ 1329141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1330126261Smlaier#else 1331126258Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1332130613Smlaier#endif 1333126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1334130613Smlaier struct pfsync_header *h, *h_net; 1335130613Smlaier struct pfsync_state *sp = NULL; 1336130613Smlaier struct pfsync_state_upd *up = NULL; 1337130613Smlaier struct pfsync_state_del *dp = NULL; 1338130613Smlaier struct pf_rule *r; 1339126258Smlaier u_long secs; 1340130613Smlaier int s, ret = 0; 1341130613Smlaier u_int8_t i = 255, newaction = 0; 1342126258Smlaier 1343130613Smlaier#ifdef __FreeBSD__ 1344130613Smlaier PF_ASSERT(MA_OWNED); 1345130613Smlaier#endif 1346130613Smlaier /* 1347130613Smlaier * If a packet falls in the forest and there's nobody around to 1348130613Smlaier * hear, does it make a sound? 1349130613Smlaier */ 1350145836Smlaier if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && 1351159603Smlaier#ifdef __FreeBSD__ 1352159603Smlaier sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1353159603Smlaier#else 1354145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1355159603Smlaier#endif 1356130613Smlaier /* Don't leave any stale pfsync packets hanging around. */ 1357130613Smlaier if (sc->sc_mbuf != NULL) { 1358130613Smlaier m_freem(sc->sc_mbuf); 1359130613Smlaier sc->sc_mbuf = NULL; 1360130613Smlaier sc->sc_statep.s = NULL; 1361130613Smlaier } 1362130613Smlaier return (0); 1363130613Smlaier } 1364130613Smlaier 1365126258Smlaier if (action >= PFSYNC_ACT_MAX) 1366126258Smlaier return (EINVAL); 1367126258Smlaier 1368126258Smlaier s = splnet(); 1369130613Smlaier if (sc->sc_mbuf == NULL) { 1370130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1371130613Smlaier (void *)&sc->sc_statep.s)) == NULL) { 1372126258Smlaier splx(s); 1373126258Smlaier return (ENOMEM); 1374126258Smlaier } 1375130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1376126258Smlaier } else { 1377130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1378126258Smlaier if (h->action != action) { 1379126258Smlaier pfsync_sendout(sc); 1380130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1381130613Smlaier (void *)&sc->sc_statep.s)) == NULL) { 1382126258Smlaier splx(s); 1383126258Smlaier return (ENOMEM); 1384126258Smlaier } 1385130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1386130613Smlaier } else { 1387130613Smlaier /* 1388130613Smlaier * If it's an update, look in the packet to see if 1389130613Smlaier * we already have an update for the state. 1390130613Smlaier */ 1391130613Smlaier if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 1392130613Smlaier struct pfsync_state *usp = 1393130613Smlaier (void *)((char *)h + PFSYNC_HDRLEN); 1394130613Smlaier 1395130613Smlaier for (i = 0; i < h->count; i++) { 1396130613Smlaier if (!memcmp(usp->id, &st->id, 1397130613Smlaier PFSYNC_ID_LEN) && 1398130613Smlaier usp->creatorid == st->creatorid) { 1399130613Smlaier sp = usp; 1400130613Smlaier sp->updates++; 1401130613Smlaier break; 1402130613Smlaier } 1403130613Smlaier usp++; 1404130613Smlaier } 1405130613Smlaier } 1406126258Smlaier } 1407126258Smlaier } 1408126258Smlaier 1409130613Smlaier secs = time_second; 1410126258Smlaier 1411130613Smlaier st->pfsync_time = time_uptime; 1412130613Smlaier TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 1413130613Smlaier TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 1414130613Smlaier 1415130613Smlaier if (sp == NULL) { 1416130613Smlaier /* not a "duplicate" update */ 1417130613Smlaier i = 255; 1418130613Smlaier sp = sc->sc_statep.s++; 1419130613Smlaier sc->sc_mbuf->m_pkthdr.len = 1420130613Smlaier sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 1421130613Smlaier h->count++; 1422130613Smlaier bzero(sp, sizeof(*sp)); 1423130613Smlaier 1424130613Smlaier bcopy(&st->id, sp->id, sizeof(sp->id)); 1425130613Smlaier sp->creatorid = st->creatorid; 1426130613Smlaier 1427130613Smlaier strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 1428130613Smlaier pf_state_host_hton(&st->lan, &sp->lan); 1429130613Smlaier pf_state_host_hton(&st->gwy, &sp->gwy); 1430130613Smlaier pf_state_host_hton(&st->ext, &sp->ext); 1431130613Smlaier 1432130613Smlaier bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 1433130613Smlaier 1434130613Smlaier sp->creation = htonl(secs - st->creation); 1435130613Smlaier sp->packets[0] = htonl(st->packets[0]); 1436130613Smlaier sp->packets[1] = htonl(st->packets[1]); 1437130613Smlaier sp->bytes[0] = htonl(st->bytes[0]); 1438130613Smlaier sp->bytes[1] = htonl(st->bytes[1]); 1439130613Smlaier if ((r = st->rule.ptr) == NULL) 1440130613Smlaier sp->rule = htonl(-1); 1441130613Smlaier else 1442130613Smlaier sp->rule = htonl(r->nr); 1443130613Smlaier if ((r = st->anchor.ptr) == NULL) 1444130613Smlaier sp->anchor = htonl(-1); 1445130613Smlaier else 1446130613Smlaier sp->anchor = htonl(r->nr); 1447130613Smlaier sp->af = st->af; 1448130613Smlaier sp->proto = st->proto; 1449130613Smlaier sp->direction = st->direction; 1450130613Smlaier sp->log = st->log; 1451130613Smlaier sp->allow_opts = st->allow_opts; 1452130613Smlaier sp->timeout = st->timeout; 1453130613Smlaier 1454145836Smlaier if (flags & PFSYNC_FLAG_STALE) 1455145836Smlaier sp->sync_flags |= PFSTATE_STALE; 1456130613Smlaier } 1457130613Smlaier 1458126258Smlaier pf_state_peer_hton(&st->src, &sp->src); 1459126258Smlaier pf_state_peer_hton(&st->dst, &sp->dst); 1460126258Smlaier 1461126258Smlaier if (st->expire <= secs) 1462126258Smlaier sp->expire = htonl(0); 1463126258Smlaier else 1464126258Smlaier sp->expire = htonl(st->expire - secs); 1465126258Smlaier 1466130613Smlaier /* do we need to build "compressed" actions for network transfer? */ 1467145836Smlaier if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { 1468130613Smlaier switch (action) { 1469130613Smlaier case PFSYNC_ACT_UPD: 1470130613Smlaier newaction = PFSYNC_ACT_UPD_C; 1471130613Smlaier break; 1472130613Smlaier case PFSYNC_ACT_DEL: 1473130613Smlaier newaction = PFSYNC_ACT_DEL_C; 1474130613Smlaier break; 1475130613Smlaier default: 1476130613Smlaier /* by default we just send the uncompressed states */ 1477130613Smlaier break; 1478130613Smlaier } 1479130613Smlaier } 1480130613Smlaier 1481130613Smlaier if (newaction) { 1482130613Smlaier if (sc->sc_mbuf_net == NULL) { 1483130613Smlaier if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 1484130613Smlaier (void *)&sc->sc_statep_net.s)) == NULL) { 1485130613Smlaier splx(s); 1486130613Smlaier return (ENOMEM); 1487130613Smlaier } 1488130613Smlaier } 1489130613Smlaier h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 1490130613Smlaier 1491130613Smlaier switch (newaction) { 1492130613Smlaier case PFSYNC_ACT_UPD_C: 1493130613Smlaier if (i != 255) { 1494130613Smlaier up = (void *)((char *)h_net + 1495130613Smlaier PFSYNC_HDRLEN + (i * sizeof(*up))); 1496130613Smlaier up->updates++; 1497130613Smlaier } else { 1498130613Smlaier h_net->count++; 1499130613Smlaier sc->sc_mbuf_net->m_pkthdr.len = 1500130613Smlaier sc->sc_mbuf_net->m_len += sizeof(*up); 1501130613Smlaier up = sc->sc_statep_net.u++; 1502130613Smlaier 1503130613Smlaier bzero(up, sizeof(*up)); 1504130613Smlaier bcopy(&st->id, up->id, sizeof(up->id)); 1505130613Smlaier up->creatorid = st->creatorid; 1506130613Smlaier } 1507130613Smlaier up->timeout = st->timeout; 1508130613Smlaier up->expire = sp->expire; 1509130613Smlaier up->src = sp->src; 1510130613Smlaier up->dst = sp->dst; 1511130613Smlaier break; 1512130613Smlaier case PFSYNC_ACT_DEL_C: 1513130613Smlaier sc->sc_mbuf_net->m_pkthdr.len = 1514130613Smlaier sc->sc_mbuf_net->m_len += sizeof(*dp); 1515130613Smlaier dp = sc->sc_statep_net.d++; 1516130613Smlaier h_net->count++; 1517130613Smlaier 1518130613Smlaier bzero(dp, sizeof(*dp)); 1519130613Smlaier bcopy(&st->id, dp->id, sizeof(dp->id)); 1520130613Smlaier dp->creatorid = st->creatorid; 1521130613Smlaier break; 1522130613Smlaier } 1523130613Smlaier } 1524130613Smlaier 1525130613Smlaier if (h->count == sc->sc_maxcount || 1526130613Smlaier (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 1527126258Smlaier ret = pfsync_sendout(sc); 1528126258Smlaier 1529126258Smlaier splx(s); 1530130613Smlaier return (ret); 1531126258Smlaier} 1532126258Smlaier 1533130613Smlaier/* This must be called in splnet() */ 1534126258Smlaierint 1535130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 1536126258Smlaier{ 1537127145Smlaier#ifdef __FreeBSD__ 1538141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1539126261Smlaier#else 1540126258Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1541130613Smlaier#endif 1542130613Smlaier struct pfsync_header *h; 1543126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1544130613Smlaier struct pfsync_state_upd_req *rup; 1545145836Smlaier int ret = 0; 1546130613Smlaier 1547130613Smlaier#ifdef __FreeBSD__ 1548130613Smlaier PF_ASSERT(MA_OWNED); 1549126261Smlaier#endif 1550130613Smlaier if (sc->sc_mbuf == NULL) { 1551130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1552145836Smlaier (void *)&sc->sc_statep.s)) == NULL) 1553130613Smlaier return (ENOMEM); 1554130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1555130613Smlaier } else { 1556130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1557130613Smlaier if (h->action != PFSYNC_ACT_UREQ) { 1558130613Smlaier pfsync_sendout(sc); 1559130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1560145836Smlaier (void *)&sc->sc_statep.s)) == NULL) 1561130613Smlaier return (ENOMEM); 1562130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1563130613Smlaier } 1564130613Smlaier } 1565130613Smlaier 1566130613Smlaier if (src != NULL) 1567130613Smlaier sc->sc_sendaddr = *src; 1568130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 1569130613Smlaier h->count++; 1570130613Smlaier rup = sc->sc_statep.r++; 1571130613Smlaier bzero(rup, sizeof(*rup)); 1572130613Smlaier if (up != NULL) { 1573130613Smlaier bcopy(up->id, rup->id, sizeof(rup->id)); 1574130613Smlaier rup->creatorid = up->creatorid; 1575130613Smlaier } 1576130613Smlaier 1577130613Smlaier if (h->count == sc->sc_maxcount) 1578130613Smlaier ret = pfsync_sendout(sc); 1579130613Smlaier 1580130613Smlaier return (ret); 1581130613Smlaier} 1582130613Smlaier 1583130613Smlaierint 1584130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname) 1585130613Smlaier{ 1586130613Smlaier#ifdef __FreeBSD__ 1587141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1588130613Smlaier#else 1589130613Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1590130613Smlaier#endif 1591130613Smlaier struct pfsync_softc *sc = ifp->if_softc; 1592130613Smlaier struct pfsync_state_clr *cp; 1593126258Smlaier int s, ret; 1594126258Smlaier 1595126258Smlaier s = splnet(); 1596130613Smlaier#ifdef __FreeBSD__ 1597130613Smlaier PF_ASSERT(MA_OWNED); 1598130613Smlaier#endif 1599130613Smlaier if (sc->sc_mbuf != NULL) 1600130613Smlaier pfsync_sendout(sc); 1601130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 1602130613Smlaier (void *)&sc->sc_statep.c)) == NULL) { 1603126258Smlaier splx(s); 1604126258Smlaier return (ENOMEM); 1605126258Smlaier } 1606130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 1607130613Smlaier cp = sc->sc_statep.c; 1608130613Smlaier cp->creatorid = creatorid; 1609130613Smlaier if (ifname != NULL) 1610130613Smlaier strlcpy(cp->ifname, ifname, IFNAMSIZ); 1611126258Smlaier 1612126258Smlaier ret = (pfsync_sendout(sc)); 1613126258Smlaier splx(s); 1614126258Smlaier return (ret); 1615126258Smlaier} 1616126258Smlaier 1617126258Smlaiervoid 1618126258Smlaierpfsync_timeout(void *v) 1619126258Smlaier{ 1620126258Smlaier struct pfsync_softc *sc = v; 1621126258Smlaier int s; 1622126258Smlaier 1623126258Smlaier s = splnet(); 1624130613Smlaier#ifdef __FreeBSD__ 1625130613Smlaier PF_LOCK(); 1626130613Smlaier#endif 1627126258Smlaier pfsync_sendout(sc); 1628130613Smlaier#ifdef __FreeBSD__ 1629130613Smlaier PF_UNLOCK(); 1630130613Smlaier#endif 1631126258Smlaier splx(s); 1632126258Smlaier} 1633126258Smlaier 1634145836Smlaier/* This must be called in splnet() */ 1635130613Smlaiervoid 1636130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 1637130613Smlaier{ 1638130613Smlaier struct pfsync_state_bus *bus; 1639130613Smlaier 1640130613Smlaier#ifdef __FreeBSD__ 1641130613Smlaier PF_ASSERT(MA_OWNED); 1642130613Smlaier#endif 1643130613Smlaier if (sc->sc_mbuf != NULL) 1644130613Smlaier pfsync_sendout(sc); 1645130613Smlaier 1646130613Smlaier if (pfsync_sync_ok && 1647130613Smlaier (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 1648130613Smlaier (void *)&sc->sc_statep.b)) != NULL) { 1649130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 1650130613Smlaier bus = sc->sc_statep.b; 1651130613Smlaier bus->creatorid = pf_status.hostid; 1652130613Smlaier bus->status = status; 1653130613Smlaier bus->endtime = htonl(time_uptime - sc->sc_ureq_received); 1654130613Smlaier pfsync_sendout(sc); 1655130613Smlaier } 1656130613Smlaier} 1657130613Smlaier 1658130613Smlaiervoid 1659130613Smlaierpfsync_bulk_update(void *v) 1660130613Smlaier{ 1661130613Smlaier struct pfsync_softc *sc = v; 1662130613Smlaier int s, i = 0; 1663130613Smlaier struct pf_state *state; 1664130613Smlaier 1665130613Smlaier#ifdef __FreeBSD__ 1666130613Smlaier PF_LOCK(); 1667130613Smlaier#endif 1668130613Smlaier s = splnet(); 1669130613Smlaier if (sc->sc_mbuf != NULL) 1670130613Smlaier pfsync_sendout(sc); 1671130613Smlaier 1672130613Smlaier /* 1673130613Smlaier * Grab at most PFSYNC_BULKPACKETS worth of states which have not 1674130613Smlaier * been sent since the latest request was made. 1675130613Smlaier */ 1676130613Smlaier while ((state = TAILQ_FIRST(&state_updates)) != NULL && 1677130613Smlaier ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 1678130613Smlaier if (state->pfsync_time > sc->sc_ureq_received) { 1679130613Smlaier /* we're done */ 1680130613Smlaier pfsync_send_bus(sc, PFSYNC_BUS_END); 1681130613Smlaier sc->sc_ureq_received = 0; 1682130613Smlaier#ifdef __FreeBSD__ 1683130613Smlaier callout_stop(&sc->sc_bulk_tmo); 1684130613Smlaier#else 1685130613Smlaier timeout_del(&sc->sc_bulk_tmo); 1686130613Smlaier#endif 1687130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1688130613Smlaier printf("pfsync: bulk update complete\n"); 1689130613Smlaier break; 1690130613Smlaier } else { 1691130613Smlaier /* send an update and move to end of list */ 1692130613Smlaier if (!state->sync_flags) 1693130613Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 1694130613Smlaier state->pfsync_time = time_uptime; 1695130613Smlaier TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 1696130613Smlaier TAILQ_INSERT_TAIL(&state_updates, state, 1697130613Smlaier u.s.entry_updates); 1698130613Smlaier 1699130613Smlaier /* look again for more in a bit */ 1700130613Smlaier#ifdef __FreeBSD__ 1701130613Smlaier callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 1702130613Smlaier LIST_FIRST(&pfsync_list)); 1703130613Smlaier#else 1704130613Smlaier timeout_add(&sc->sc_bulk_tmo, 1); 1705130613Smlaier#endif 1706130613Smlaier } 1707130613Smlaier } 1708130613Smlaier if (sc->sc_mbuf != NULL) 1709130613Smlaier pfsync_sendout(sc); 1710130613Smlaier splx(s); 1711130613Smlaier#ifdef __FreeBSD__ 1712130613Smlaier PF_UNLOCK(); 1713130613Smlaier#endif 1714130613Smlaier} 1715130613Smlaier 1716130613Smlaiervoid 1717130613Smlaierpfsync_bulkfail(void *v) 1718130613Smlaier{ 1719130613Smlaier struct pfsync_softc *sc = v; 1720145836Smlaier int s, error; 1721130613Smlaier 1722130613Smlaier#ifdef __FreeBSD__ 1723130613Smlaier PF_LOCK(); 1724130613Smlaier#endif 1725130613Smlaier if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1726130613Smlaier /* Try again in a bit */ 1727130613Smlaier#ifdef __FreeBSD__ 1728130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1729130613Smlaier LIST_FIRST(&pfsync_list)); 1730130613Smlaier#else 1731130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1732130613Smlaier#endif 1733145836Smlaier s = splnet(); 1734145836Smlaier error = pfsync_request_update(NULL, NULL); 1735145836Smlaier if (error == ENOMEM) { 1736145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1737145836Smlaier printf("pfsync: cannot allocate mbufs for " 1738145836Smlaier "bulk update\n"); 1739145836Smlaier } else 1740145836Smlaier pfsync_sendout(sc); 1741145836Smlaier splx(s); 1742130613Smlaier } else { 1743130613Smlaier /* Pretend like the transfer was ok */ 1744130613Smlaier sc->sc_ureq_sent = 0; 1745130613Smlaier sc->sc_bulk_tries = 0; 1746145836Smlaier#if NCARP > 0 1747145836Smlaier if (!pfsync_sync_ok) 1748145836Smlaier carp_suppress_preempt--; 1749145836Smlaier#endif 1750130613Smlaier pfsync_sync_ok = 1; 1751130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1752130613Smlaier printf("pfsync: failed to receive " 1753130613Smlaier "bulk update status\n"); 1754130613Smlaier#ifdef __FreeBSD__ 1755130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 1756130613Smlaier#else 1757130613Smlaier timeout_del(&sc->sc_bulkfail_tmo); 1758130613Smlaier#endif 1759130613Smlaier } 1760130613Smlaier#ifdef __FreeBSD__ 1761130613Smlaier PF_UNLOCK(); 1762130613Smlaier#endif 1763130613Smlaier} 1764130613Smlaier 1765145836Smlaier/* This must be called in splnet() */ 1766126258Smlaierint 1767126258Smlaierpfsync_sendout(sc) 1768126258Smlaier struct pfsync_softc *sc; 1769126258Smlaier{ 1770138666Smlaier#if NBPFILTER > 0 1771141584Smlaier# ifdef __FreeBSD__ 1772141584Smlaier struct ifnet *ifp = SCP2IFP(sc); 1773141584Smlaier# else 1774141584Smlaier struct ifnet *ifp = &sc->if_sc; 1775141584Smlaier# endif 1776138666Smlaier#endif 1777130613Smlaier struct mbuf *m; 1778126258Smlaier 1779127145Smlaier#ifdef __FreeBSD__ 1780130613Smlaier PF_ASSERT(MA_OWNED); 1781126261Smlaier callout_stop(&sc->sc_tmo); 1782126261Smlaier#else 1783126258Smlaier timeout_del(&sc->sc_tmo); 1784126261Smlaier#endif 1785130613Smlaier 1786130613Smlaier if (sc->sc_mbuf == NULL) 1787130613Smlaier return (0); 1788130613Smlaier m = sc->sc_mbuf; 1789126258Smlaier sc->sc_mbuf = NULL; 1790130613Smlaier sc->sc_statep.s = NULL; 1791126258Smlaier 1792127145Smlaier#ifdef __FreeBSD__ 1793126261Smlaier KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1794126261Smlaier#endif 1795126258Smlaier#if NBPFILTER > 0 1796165632Sjhb#ifdef __FreeBSD__ 1797165632Sjhb BPF_MTAP(ifp, m); 1798165632Sjhb#else 1799126258Smlaier if (ifp->if_bpf) 1800126258Smlaier bpf_mtap(ifp->if_bpf, m); 1801126258Smlaier#endif 1802165632Sjhb#endif 1803126258Smlaier 1804130613Smlaier if (sc->sc_mbuf_net) { 1805130613Smlaier m_freem(m); 1806130613Smlaier m = sc->sc_mbuf_net; 1807130613Smlaier sc->sc_mbuf_net = NULL; 1808130613Smlaier sc->sc_statep_net.s = NULL; 1809130613Smlaier } 1810126258Smlaier 1811159603Smlaier#ifdef __FreeBSD__ 1812159603Smlaier if (sc->sc_sync_ifp || 1813159603Smlaier sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) { 1814159603Smlaier#else 1815159603Smlaier if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { 1816159603Smlaier#endif 1817130613Smlaier struct ip *ip; 1818130613Smlaier struct sockaddr sa; 1819130613Smlaier 1820130613Smlaier M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 1821130613Smlaier if (m == NULL) { 1822130613Smlaier pfsyncstats.pfsyncs_onomem++; 1823130613Smlaier return (0); 1824130613Smlaier } 1825130613Smlaier ip = mtod(m, struct ip *); 1826130613Smlaier ip->ip_v = IPVERSION; 1827130613Smlaier ip->ip_hl = sizeof(*ip) >> 2; 1828130613Smlaier ip->ip_tos = IPTOS_LOWDELAY; 1829130613Smlaier#ifdef __FreeBSD__ 1830130613Smlaier ip->ip_len = m->m_pkthdr.len; 1831130613Smlaier#else 1832130613Smlaier ip->ip_len = htons(m->m_pkthdr.len); 1833130613Smlaier#endif 1834130613Smlaier ip->ip_id = htons(ip_randomid()); 1835130613Smlaier#ifdef __FreeBSD__ 1836130613Smlaier ip->ip_off = IP_DF; 1837130613Smlaier#else 1838130613Smlaier ip->ip_off = htons(IP_DF); 1839130613Smlaier#endif 1840130613Smlaier ip->ip_ttl = PFSYNC_DFLTTL; 1841130613Smlaier ip->ip_p = IPPROTO_PFSYNC; 1842130613Smlaier ip->ip_sum = 0; 1843130613Smlaier 1844130613Smlaier bzero(&sa, sizeof(sa)); 1845145836Smlaier ip->ip_src.s_addr = INADDR_ANY; 1846130613Smlaier 1847130613Smlaier#ifdef __FreeBSD__ 1848130613Smlaier if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1849130613Smlaier#else 1850130613Smlaier if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) 1851130613Smlaier#endif 1852130613Smlaier m->m_flags |= M_MCAST; 1853130613Smlaier ip->ip_dst = sc->sc_sendaddr; 1854145836Smlaier sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr; 1855130613Smlaier 1856130613Smlaier pfsyncstats.pfsyncs_opackets++; 1857130613Smlaier#ifdef __FreeBSD__ 1858147614Smlaier if (!IF_HANDOFF(&sc->sc_ifq, m, NULL)) 1859147261Smlaier pfsyncstats.pfsyncs_oerrors++; 1860147261Smlaier callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc); 1861147261Smlaier#else 1862130613Smlaier if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1863130613Smlaier pfsyncstats.pfsyncs_oerrors++; 1864130613Smlaier#endif 1865130613Smlaier } else 1866130613Smlaier m_freem(m); 1867130613Smlaier 1868126258Smlaier return (0); 1869126258Smlaier} 1870126261Smlaier 1871147261Smlaier#ifdef __FreeBSD__ 1872147261Smlaierstatic void 1873147261Smlaierpfsync_senddef(void *arg) 1874147261Smlaier{ 1875147261Smlaier struct pfsync_softc *sc = (struct pfsync_softc *)arg; 1876147261Smlaier struct mbuf *m; 1877126261Smlaier 1878147261Smlaier for(;;) { 1879147261Smlaier IF_DEQUEUE(&sc->sc_ifq, m); 1880147261Smlaier if (m == NULL) 1881147261Smlaier break; 1882147261Smlaier if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1883147261Smlaier pfsyncstats.pfsyncs_oerrors++; 1884147261Smlaier } 1885147261Smlaier} 1886147261Smlaier 1887126261Smlaierstatic int 1888126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 1889126261Smlaier{ 1890126261Smlaier int error = 0; 1891126261Smlaier 1892126261Smlaier switch (type) { 1893126261Smlaier case MOD_LOAD: 1894126261Smlaier LIST_INIT(&pfsync_list); 1895126261Smlaier if_clone_attach(&pfsync_cloner); 1896126261Smlaier break; 1897126261Smlaier 1898126261Smlaier case MOD_UNLOAD: 1899126261Smlaier if_clone_detach(&pfsync_cloner); 1900126261Smlaier break; 1901126261Smlaier 1902126261Smlaier default: 1903126261Smlaier error = EINVAL; 1904126261Smlaier break; 1905126261Smlaier } 1906126261Smlaier 1907126261Smlaier return error; 1908126261Smlaier} 1909126261Smlaier 1910126261Smlaierstatic moduledata_t pfsync_mod = { 1911126261Smlaier "pfsync", 1912126261Smlaier pfsync_modevent, 1913126261Smlaier 0 1914126261Smlaier}; 1915126261Smlaier 1916126261Smlaier#define PFSYNC_MODVER 1 1917126261Smlaier 1918135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 1919126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 1920126261Smlaier#endif /* __FreeBSD__ */ 1921