if_pfsync.c revision 145836
1126261Smlaier/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 145836 2005-05-03 16:43:32Z mlaier $ */ 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" 41127145Smlaier#define NBPFILTER DEV_BPF 42127145Smlaier#define NPFSYNC DEV_PFSYNC 43126261Smlaier#endif 44126258Smlaier 45126258Smlaier#include <sys/param.h> 46130613Smlaier#include <sys/proc.h> 47126258Smlaier#include <sys/systm.h> 48126258Smlaier#include <sys/time.h> 49126258Smlaier#include <sys/mbuf.h> 50126258Smlaier#include <sys/socket.h> 51145836Smlaier#include <sys/kernel.h> 52127145Smlaier#ifdef __FreeBSD__ 53145836Smlaier#include <sys/endian.h> 54126261Smlaier#include <sys/malloc.h> 55129907Smlaier#include <sys/module.h> 56126261Smlaier#include <sys/sockio.h> 57130613Smlaier#include <sys/lock.h> 58130613Smlaier#include <sys/mutex.h> 59126261Smlaier#else 60126258Smlaier#include <sys/ioctl.h> 61126258Smlaier#include <sys/timeout.h> 62126261Smlaier#endif 63126258Smlaier 64126258Smlaier#include <net/if.h> 65130933Sbrooks#if defined(__FreeBSD__) 66130933Sbrooks#include <net/if_clone.h> 67130933Sbrooks#endif 68126258Smlaier#include <net/if_types.h> 69126258Smlaier#include <net/route.h> 70126258Smlaier#include <net/bpf.h> 71145836Smlaier#include <netinet/tcp.h> 72145836Smlaier#include <netinet/tcp_seq.h> 73126258Smlaier 74126258Smlaier#ifdef INET 75126258Smlaier#include <netinet/in.h> 76130613Smlaier#include <netinet/in_systm.h> 77126258Smlaier#include <netinet/in_var.h> 78130613Smlaier#include <netinet/ip.h> 79130613Smlaier#include <netinet/ip_var.h> 80126258Smlaier#endif 81126258Smlaier 82126258Smlaier#ifdef INET6 83126258Smlaier#ifndef INET 84126258Smlaier#include <netinet/in.h> 85126258Smlaier#endif 86126258Smlaier#include <netinet6/nd6.h> 87126258Smlaier#endif /* INET6 */ 88126258Smlaier 89145836Smlaier#ifdef __FreeBSD__ 90145836Smlaier#include "opt_carp.h" 91145836Smlaier#ifdef DEV_CARP 92145836Smlaier#define NCARP 1 93145836Smlaier#endif 94145836Smlaier#else 95145836Smlaier#include "carp.h" 96145836Smlaier#endif 97145836Smlaier#if NCARP > 0 98145836Smlaierextern int carp_suppress_preempt; 99145836Smlaier#endif 100145836Smlaier 101126258Smlaier#include <net/pfvar.h> 102126258Smlaier#include <net/if_pfsync.h> 103126258Smlaier 104127145Smlaier#ifdef __FreeBSD__ 105127145Smlaier#define PFSYNCNAME "pfsync" 106126261Smlaier#endif 107126261Smlaier 108126258Smlaier#define PFSYNC_MINMTU \ 109126258Smlaier (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 110126258Smlaier 111126258Smlaier#ifdef PFSYNCDEBUG 112126258Smlaier#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 113126258Smlaierint pfsyncdebug; 114126258Smlaier#else 115126258Smlaier#define DPRINTF(x) 116126258Smlaier#endif 117126258Smlaier 118127145Smlaier#ifndef __FreeBSD__ 119130613Smlaierstruct pfsync_softc pfsyncif; 120126261Smlaier#endif 121130613Smlaierstruct pfsyncstats pfsyncstats; 122126258Smlaier 123127145Smlaier#ifdef __FreeBSD__ 124130613Smlaier 125130613Smlaier/* 126130613Smlaier * Locking notes: 127130613Smlaier * Whenever we really touch/look at the state table we have to hold the 128130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per 129130613Smlaier * softc lock instead. 130130613Smlaier * 131130613Smlaier */ 132130613Smlaier 133128209Sbrooksstatic void pfsync_clone_destroy(struct ifnet *); 134128209Sbrooksstatic int pfsync_clone_create(struct if_clone *, int); 135126261Smlaier#else 136126258Smlaiervoid pfsyncattach(int); 137126261Smlaier#endif 138130613Smlaiervoid pfsync_setmtu(struct pfsync_softc *, int); 139130613Smlaierint pfsync_insert_net_state(struct pfsync_state *); 140126258Smlaierint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 141130613Smlaier struct rtentry *); 142126258Smlaierint pfsyncioctl(struct ifnet *, u_long, caddr_t); 143126258Smlaiervoid pfsyncstart(struct ifnet *); 144126258Smlaier 145130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 146130613Smlaierint pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 147130613Smlaierint pfsync_sendout(struct pfsync_softc *); 148130613Smlaiervoid pfsync_timeout(void *); 149130613Smlaiervoid pfsync_send_bus(struct pfsync_softc *, u_int8_t); 150130613Smlaiervoid pfsync_bulk_update(void *); 151130613Smlaiervoid pfsync_bulkfail(void *); 152126258Smlaier 153145836Smlaierint pfsync_sync_ok; 154127145Smlaier#ifndef __FreeBSD__ 155126258Smlaierextern int ifqmaxlen; 156130613Smlaierextern struct timeval time; 157130613Smlaierextern struct timeval mono_time; 158130613Smlaierextern int hz; 159126261Smlaier#endif 160126258Smlaier 161127145Smlaier#ifdef __FreeBSD__ 162126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 163126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 164141584Smlaier#define SCP2IFP(sc) (&(sc)->sc_if) 165130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1); 166126261Smlaier 167128209Sbrooksstatic void 168126261Smlaierpfsync_clone_destroy(struct ifnet *ifp) 169126261Smlaier{ 170126261Smlaier struct pfsync_softc *sc; 171126261Smlaier 172130613Smlaier sc = ifp->if_softc; 173126261Smlaier callout_stop(&sc->sc_tmo); 174130613Smlaier callout_stop(&sc->sc_bulk_tmo); 175130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 176126261Smlaier 177126261Smlaier#if NBPFILTER > 0 178126261Smlaier bpfdetach(ifp); 179126261Smlaier#endif 180126261Smlaier if_detach(ifp); 181126261Smlaier LIST_REMOVE(sc, sc_next); 182126261Smlaier free(sc, M_PFSYNC); 183126261Smlaier} 184126261Smlaier 185128209Sbrooksstatic int 186126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit) 187126261Smlaier{ 188126261Smlaier struct pfsync_softc *sc; 189130613Smlaier struct ifnet *ifp; 190126261Smlaier 191126261Smlaier MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 192130613Smlaier M_WAITOK|M_ZERO); 193126261Smlaier 194130613Smlaier pfsync_sync_ok = 1; 195130613Smlaier sc->sc_mbuf = NULL; 196130613Smlaier sc->sc_mbuf_net = NULL; 197130613Smlaier sc->sc_statep.s = NULL; 198130613Smlaier sc->sc_statep_net.s = NULL; 199130613Smlaier sc->sc_maxupdates = 128; 200130613Smlaier sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 201130613Smlaier sc->sc_ureq_received = 0; 202130613Smlaier sc->sc_ureq_sent = 0; 203130613Smlaier 204141584Smlaier ifp = SCP2IFP(sc); 205130613Smlaier if_initname(ifp, ifc->ifc_name, unit); 206130613Smlaier ifp->if_ioctl = pfsyncioctl; 207130613Smlaier ifp->if_output = pfsyncoutput; 208130613Smlaier ifp->if_start = pfsyncstart; 209130613Smlaier ifp->if_type = IFT_PFSYNC; 210130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 211130613Smlaier ifp->if_hdrlen = PFSYNC_HDRLEN; 212130613Smlaier ifp->if_baudrate = IF_Mbps(100); 213130613Smlaier ifp->if_softc = sc; 214126261Smlaier pfsync_setmtu(sc, MCLBYTES); 215126261Smlaier /* 216126261Smlaier * XXX 217126261Smlaier * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE 218126261Smlaier * if Gaint lock is removed from the network stack. 219126261Smlaier */ 220126261Smlaier callout_init(&sc->sc_tmo, 0); 221130613Smlaier callout_init(&sc->sc_bulk_tmo, 0); 222130613Smlaier callout_init(&sc->sc_bulkfail_tmo, 0); 223141584Smlaier if_attach(ifp); 224126261Smlaier 225126261Smlaier LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 226126261Smlaier#if NBPFILTER > 0 227141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 228126261Smlaier#endif 229126261Smlaier 230126261Smlaier return (0); 231126261Smlaier} 232126261Smlaier#else /* !__FreeBSD__ */ 233126261Smlaiervoid 234126258Smlaierpfsyncattach(int npfsync) 235126258Smlaier{ 236126258Smlaier struct ifnet *ifp; 237126258Smlaier 238130613Smlaier pfsync_sync_ok = 1; 239130613Smlaier bzero(&pfsyncif, sizeof(pfsyncif)); 240126258Smlaier pfsyncif.sc_mbuf = NULL; 241130613Smlaier pfsyncif.sc_mbuf_net = NULL; 242130613Smlaier pfsyncif.sc_statep.s = NULL; 243130613Smlaier pfsyncif.sc_statep_net.s = NULL; 244130613Smlaier pfsyncif.sc_maxupdates = 128; 245145836Smlaier pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 246130613Smlaier pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 247130613Smlaier pfsyncif.sc_ureq_received = 0; 248130613Smlaier pfsyncif.sc_ureq_sent = 0; 249126258Smlaier ifp = &pfsyncif.sc_if; 250126258Smlaier strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); 251126258Smlaier ifp->if_softc = &pfsyncif; 252126258Smlaier ifp->if_ioctl = pfsyncioctl; 253126258Smlaier ifp->if_output = pfsyncoutput; 254126258Smlaier ifp->if_start = pfsyncstart; 255126258Smlaier ifp->if_type = IFT_PFSYNC; 256126258Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 257126258Smlaier ifp->if_hdrlen = PFSYNC_HDRLEN; 258126258Smlaier pfsync_setmtu(&pfsyncif, MCLBYTES); 259126258Smlaier timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); 260130613Smlaier timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); 261130613Smlaier timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); 262126258Smlaier if_attach(ifp); 263126258Smlaier if_alloc_sadl(ifp); 264126258Smlaier 265126258Smlaier#if NBPFILTER > 0 266126258Smlaier bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 267126258Smlaier#endif 268126258Smlaier} 269126261Smlaier#endif 270126258Smlaier 271126258Smlaier/* 272126258Smlaier * Start output on the pfsync interface. 273126258Smlaier */ 274126258Smlaiervoid 275126258Smlaierpfsyncstart(struct ifnet *ifp) 276126258Smlaier{ 277130613Smlaier#ifdef __FreeBSD__ 278130613Smlaier IF_LOCK(&ifp->if_snd); 279130613Smlaier _IF_DROP(&ifp->if_snd); 280130613Smlaier _IF_DRAIN(&ifp->if_snd); 281130613Smlaier IF_UNLOCK(&ifp->if_snd); 282130613Smlaier#else 283126258Smlaier struct mbuf *m; 284126258Smlaier int s; 285126258Smlaier 286126258Smlaier for (;;) { 287126258Smlaier s = splimp(); 288126258Smlaier IF_DROP(&ifp->if_snd); 289126258Smlaier IF_DEQUEUE(&ifp->if_snd, m); 290126258Smlaier splx(s); 291126258Smlaier 292126258Smlaier if (m == NULL) 293126258Smlaier return; 294126258Smlaier else 295126258Smlaier m_freem(m); 296126258Smlaier } 297130613Smlaier#endif 298126258Smlaier} 299126258Smlaier 300126258Smlaierint 301130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp) 302130613Smlaier{ 303130613Smlaier struct pf_state *st = NULL; 304130613Smlaier struct pf_rule *r = NULL; 305130613Smlaier struct pfi_kif *kif; 306130613Smlaier 307130613Smlaier#ifdef __FreeBSD__ 308130613Smlaier PF_ASSERT(MA_OWNED); 309130613Smlaier#endif 310130613Smlaier if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 311130613Smlaier printf("pfsync_insert_net_state: invalid creator id:" 312130613Smlaier " %08x\n", ntohl(sp->creatorid)); 313130613Smlaier return (EINVAL); 314130613Smlaier } 315130613Smlaier 316130613Smlaier kif = pfi_lookup_create(sp->ifname); 317130613Smlaier if (kif == NULL) { 318130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 319130613Smlaier printf("pfsync_insert_net_state: " 320130613Smlaier "unknown interface: %s\n", sp->ifname); 321130613Smlaier /* skip this state */ 322130613Smlaier return (0); 323130613Smlaier } 324130613Smlaier 325130613Smlaier /* 326130613Smlaier * Just use the default rule until we have infrastructure to find the 327130613Smlaier * best matching rule. 328130613Smlaier */ 329130613Smlaier r = &pf_default_rule; 330130613Smlaier 331130613Smlaier if (!r->max_states || r->states < r->max_states) 332130613Smlaier st = pool_get(&pf_state_pl, PR_NOWAIT); 333130613Smlaier if (st == NULL) { 334130613Smlaier pfi_maybe_destroy(kif); 335130613Smlaier return (ENOMEM); 336130613Smlaier } 337130613Smlaier bzero(st, sizeof(*st)); 338130613Smlaier 339130613Smlaier st->rule.ptr = r; 340130613Smlaier /* XXX get pointers to nat_rule and anchor */ 341130613Smlaier 342145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 343145836Smlaier r->states++; 344145836Smlaier 345130613Smlaier /* fill in the rest of the state entry */ 346130613Smlaier pf_state_host_ntoh(&sp->lan, &st->lan); 347130613Smlaier pf_state_host_ntoh(&sp->gwy, &st->gwy); 348130613Smlaier pf_state_host_ntoh(&sp->ext, &st->ext); 349130613Smlaier 350130613Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 351130613Smlaier pf_state_peer_ntoh(&sp->dst, &st->dst); 352130613Smlaier 353130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 354145836Smlaier st->creation = time_second - ntohl(sp->creation); 355130613Smlaier st->expire = ntohl(sp->expire) + time_second; 356130613Smlaier 357130613Smlaier st->af = sp->af; 358130613Smlaier st->proto = sp->proto; 359130613Smlaier st->direction = sp->direction; 360130613Smlaier st->log = sp->log; 361130613Smlaier st->timeout = sp->timeout; 362130613Smlaier st->allow_opts = sp->allow_opts; 363130613Smlaier 364130613Smlaier bcopy(sp->id, &st->id, sizeof(st->id)); 365130613Smlaier st->creatorid = sp->creatorid; 366145836Smlaier st->sync_flags = PFSTATE_FROMSYNC; 367130613Smlaier 368130613Smlaier 369130613Smlaier if (pf_insert_state(kif, st)) { 370130613Smlaier pfi_maybe_destroy(kif); 371145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 372145836Smlaier r->states--; 373130613Smlaier pool_put(&pf_state_pl, st); 374130613Smlaier return (EINVAL); 375130613Smlaier } 376130613Smlaier 377130613Smlaier return (0); 378130613Smlaier} 379130613Smlaier 380130613Smlaiervoid 381130613Smlaier#ifdef __FreeBSD__ 382130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 383130613Smlaier#else 384130613Smlaierpfsync_input(struct mbuf *m, ...) 385130613Smlaier#endif 386130613Smlaier{ 387130613Smlaier struct ip *ip = mtod(m, struct ip *); 388130613Smlaier struct pfsync_header *ph; 389130613Smlaier#ifdef __FreeBSD__ 390130613Smlaier struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 391130613Smlaier#else 392130613Smlaier struct pfsync_softc *sc = &pfsyncif; 393130613Smlaier#endif 394130613Smlaier struct pf_state *st, key; 395130613Smlaier struct pfsync_state *sp; 396130613Smlaier struct pfsync_state_upd *up; 397130613Smlaier struct pfsync_state_del *dp; 398130613Smlaier struct pfsync_state_clr *cp; 399130613Smlaier struct pfsync_state_upd_req *rup; 400130613Smlaier struct pfsync_state_bus *bus; 401130613Smlaier struct in_addr src; 402130613Smlaier struct mbuf *mp; 403145836Smlaier int iplen, action, error, i, s, count, offp, sfail, stale = 0; 404130613Smlaier 405130613Smlaier pfsyncstats.pfsyncs_ipackets++; 406130613Smlaier 407130613Smlaier /* verify that we have a sync interface configured */ 408130613Smlaier if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ 409130613Smlaier goto done; 410130613Smlaier 411130613Smlaier /* verify that the packet came in on the right interface */ 412130613Smlaier if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 413130613Smlaier pfsyncstats.pfsyncs_badif++; 414130613Smlaier goto done; 415130613Smlaier } 416130613Smlaier 417130613Smlaier /* verify that the IP TTL is 255. */ 418130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 419130613Smlaier pfsyncstats.pfsyncs_badttl++; 420130613Smlaier goto done; 421130613Smlaier } 422130613Smlaier 423130613Smlaier iplen = ip->ip_hl << 2; 424130613Smlaier 425130613Smlaier if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 426130613Smlaier pfsyncstats.pfsyncs_hdrops++; 427130613Smlaier goto done; 428130613Smlaier } 429130613Smlaier 430130613Smlaier if (iplen + sizeof(*ph) > m->m_len) { 431130613Smlaier if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 432130613Smlaier pfsyncstats.pfsyncs_hdrops++; 433130613Smlaier goto done; 434130613Smlaier } 435130613Smlaier ip = mtod(m, struct ip *); 436130613Smlaier } 437130613Smlaier ph = (struct pfsync_header *)((char *)ip + iplen); 438130613Smlaier 439130613Smlaier /* verify the version */ 440130613Smlaier if (ph->version != PFSYNC_VERSION) { 441130613Smlaier pfsyncstats.pfsyncs_badver++; 442130613Smlaier goto done; 443130613Smlaier } 444130613Smlaier 445130613Smlaier action = ph->action; 446130613Smlaier count = ph->count; 447130613Smlaier 448130613Smlaier /* make sure it's a valid action code */ 449130613Smlaier if (action >= PFSYNC_ACT_MAX) { 450130613Smlaier pfsyncstats.pfsyncs_badact++; 451130613Smlaier goto done; 452130613Smlaier } 453130613Smlaier 454130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 455130613Smlaier src = ip->ip_src; 456130613Smlaier 457130613Smlaier switch (action) { 458130613Smlaier case PFSYNC_ACT_CLR: { 459145836Smlaier struct pf_state *nexts; 460130613Smlaier struct pfi_kif *kif; 461130613Smlaier u_int32_t creatorid; 462130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 463130613Smlaier sizeof(*cp), &offp)) == NULL) { 464130613Smlaier pfsyncstats.pfsyncs_badlen++; 465130613Smlaier return; 466130613Smlaier } 467130613Smlaier cp = (struct pfsync_state_clr *)(mp->m_data + offp); 468130613Smlaier creatorid = cp->creatorid; 469130613Smlaier 470130613Smlaier s = splsoftnet(); 471130613Smlaier#ifdef __FreeBSD__ 472130613Smlaier PF_LOCK(); 473130613Smlaier#endif 474130613Smlaier if (cp->ifname[0] == '\0') { 475145836Smlaier for (st = RB_MIN(pf_state_tree_id, &tree_id); 476145836Smlaier st; st = nexts) { 477145836Smlaier nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 478145836Smlaier if (st->creatorid == creatorid) { 479130613Smlaier st->timeout = PFTM_PURGE; 480145836Smlaier pf_purge_expired_state(st); 481145836Smlaier } 482130613Smlaier } 483130613Smlaier } else { 484130613Smlaier kif = pfi_lookup_if(cp->ifname); 485130613Smlaier if (kif == NULL) { 486130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 487130613Smlaier printf("pfsync_input: PFSYNC_ACT_CLR " 488130613Smlaier "bad interface: %s\n", cp->ifname); 489130613Smlaier splx(s); 490130613Smlaier#ifdef __FreeBSD__ 491130613Smlaier PF_UNLOCK(); 492130613Smlaier#endif 493130613Smlaier goto done; 494130613Smlaier } 495145836Smlaier for (st = RB_MIN(pf_state_tree_lan_ext, 496145836Smlaier &kif->pfik_lan_ext); st; st = nexts) { 497145836Smlaier nexts = RB_NEXT(pf_state_tree_lan_ext, 498145836Smlaier &kif->pfik_lan_ext, st); 499145836Smlaier if (st->creatorid == creatorid) { 500130613Smlaier st->timeout = PFTM_PURGE; 501145836Smlaier pf_purge_expired_state(st); 502145836Smlaier } 503130613Smlaier } 504130613Smlaier } 505130613Smlaier#ifdef __FreeBSD__ 506130613Smlaier PF_UNLOCK(); 507130613Smlaier#endif 508130613Smlaier splx(s); 509130613Smlaier 510130613Smlaier break; 511130613Smlaier } 512130613Smlaier case PFSYNC_ACT_INS: 513130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 514130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 515130613Smlaier pfsyncstats.pfsyncs_badlen++; 516130613Smlaier return; 517130613Smlaier } 518130613Smlaier 519130613Smlaier s = splsoftnet(); 520130613Smlaier#ifdef __FreeBSD__ 521130613Smlaier PF_LOCK(); 522130613Smlaier#endif 523130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 524130613Smlaier i < count; i++, sp++) { 525130613Smlaier /* check for invalid values */ 526130613Smlaier if (sp->timeout >= PFTM_MAX || 527130613Smlaier sp->src.state > PF_TCPS_PROXY_DST || 528130613Smlaier sp->dst.state > PF_TCPS_PROXY_DST || 529130613Smlaier sp->direction > PF_OUT || 530130613Smlaier (sp->af != AF_INET && sp->af != AF_INET6)) { 531130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 532130613Smlaier printf("pfsync_insert: PFSYNC_ACT_INS: " 533130613Smlaier "invalid value\n"); 534130613Smlaier pfsyncstats.pfsyncs_badstate++; 535130613Smlaier continue; 536130613Smlaier } 537130613Smlaier 538130613Smlaier if ((error = pfsync_insert_net_state(sp))) { 539130613Smlaier if (error == ENOMEM) { 540130613Smlaier splx(s); 541130613Smlaier#ifdef __FreeBSD__ 542130613Smlaier PF_UNLOCK(); 543130613Smlaier#endif 544130613Smlaier goto done; 545130613Smlaier } 546130613Smlaier continue; 547130613Smlaier } 548130613Smlaier } 549130613Smlaier#ifdef __FreeBSD__ 550130613Smlaier PF_UNLOCK(); 551130613Smlaier#endif 552130613Smlaier splx(s); 553130613Smlaier break; 554130613Smlaier case PFSYNC_ACT_UPD: 555130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 556130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 557130613Smlaier pfsyncstats.pfsyncs_badlen++; 558130613Smlaier return; 559130613Smlaier } 560130613Smlaier 561130613Smlaier s = splsoftnet(); 562130613Smlaier#ifdef __FreeBSD__ 563130613Smlaier PF_LOCK(); 564130613Smlaier#endif 565130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 566130613Smlaier i < count; i++, sp++) { 567145836Smlaier int flags = PFSYNC_FLAG_STALE; 568145836Smlaier 569130613Smlaier /* check for invalid values */ 570130613Smlaier if (sp->timeout >= PFTM_MAX || 571130613Smlaier sp->src.state > PF_TCPS_PROXY_DST || 572130613Smlaier sp->dst.state > PF_TCPS_PROXY_DST) { 573130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 574130613Smlaier printf("pfsync_insert: PFSYNC_ACT_UPD: " 575130613Smlaier "invalid value\n"); 576130613Smlaier pfsyncstats.pfsyncs_badstate++; 577130613Smlaier continue; 578130613Smlaier } 579130613Smlaier 580130613Smlaier bcopy(sp->id, &key.id, sizeof(key.id)); 581130613Smlaier key.creatorid = sp->creatorid; 582130613Smlaier 583130613Smlaier st = pf_find_state_byid(&key); 584130613Smlaier if (st == NULL) { 585130613Smlaier /* insert the update */ 586130613Smlaier if (pfsync_insert_net_state(sp)) 587130613Smlaier pfsyncstats.pfsyncs_badstate++; 588130613Smlaier continue; 589130613Smlaier } 590145836Smlaier sfail = 0; 591145836Smlaier if (st->proto == IPPROTO_TCP) { 592145836Smlaier /* 593145836Smlaier * The state should never go backwards except 594145836Smlaier * for syn-proxy states. Neither should the 595145836Smlaier * sequence window slide backwards. 596145836Smlaier */ 597145836Smlaier if (st->src.state > sp->src.state && 598145836Smlaier (st->src.state < PF_TCPS_PROXY_SRC || 599145836Smlaier sp->src.state >= PF_TCPS_PROXY_SRC)) 600145836Smlaier sfail = 1; 601145836Smlaier else if (SEQ_GT(st->src.seqlo, 602145836Smlaier ntohl(sp->src.seqlo))) 603145836Smlaier sfail = 3; 604145836Smlaier else if (st->dst.state > sp->dst.state) { 605145836Smlaier /* There might still be useful 606145836Smlaier * information about the src state here, 607145836Smlaier * so import that part of the update, 608145836Smlaier * then "fail" so we send the updated 609145836Smlaier * state back to the peer who is missing 610145836Smlaier * our what we know. */ 611145836Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 612145836Smlaier /* XXX do anything with timeouts? */ 613145836Smlaier sfail = 7; 614145836Smlaier flags = 0; 615145836Smlaier } else if (st->dst.state >= TCPS_SYN_SENT && 616145836Smlaier SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo))) 617145836Smlaier sfail = 4; 618145836Smlaier } else { 619145836Smlaier /* 620145836Smlaier * Non-TCP protocol state machine always go 621145836Smlaier * forwards 622145836Smlaier */ 623145836Smlaier if (st->src.state > sp->src.state) 624145836Smlaier sfail = 5; 625145836Smlaier else if ( st->dst.state > sp->dst.state) 626145836Smlaier sfail = 6; 627145836Smlaier } 628145836Smlaier if (sfail) { 629145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 630145836Smlaier printf("pfsync: %s stale update " 631145836Smlaier "(%d) id: %016llx " 632145836Smlaier "creatorid: %08x\n", 633145836Smlaier (sfail < 7 ? "ignoring" 634145836Smlaier : "partial"), sfail, 635145836Smlaier#ifdef __FreeBSD__ 636145836Smlaier (unsigned long long)be64toh(st->id), 637145836Smlaier#else 638145836Smlaier betoh64(st->id), 639145836Smlaier#endif 640145836Smlaier ntohl(st->creatorid)); 641145836Smlaier pfsyncstats.pfsyncs_badstate++; 642145836Smlaier 643145836Smlaier if (!(sp->sync_flags & PFSTATE_STALE)) { 644145836Smlaier /* we have a better state, send it */ 645145836Smlaier if (sc->sc_mbuf != NULL && !stale) 646145836Smlaier pfsync_sendout(sc); 647145836Smlaier stale++; 648145836Smlaier if (!st->sync_flags) 649145836Smlaier pfsync_pack_state( 650145836Smlaier PFSYNC_ACT_UPD, st, flags); 651145836Smlaier } 652145836Smlaier continue; 653145836Smlaier } 654130613Smlaier pf_state_peer_ntoh(&sp->src, &st->src); 655130613Smlaier pf_state_peer_ntoh(&sp->dst, &st->dst); 656130613Smlaier st->expire = ntohl(sp->expire) + time_second; 657130613Smlaier st->timeout = sp->timeout; 658130613Smlaier } 659145836Smlaier if (stale && sc->sc_mbuf != NULL) 660145836Smlaier pfsync_sendout(sc); 661130613Smlaier#ifdef __FreeBSD__ 662130613Smlaier PF_UNLOCK(); 663130613Smlaier#endif 664130613Smlaier splx(s); 665130613Smlaier break; 666130613Smlaier /* 667130613Smlaier * It's not strictly necessary for us to support the "uncompressed" 668130613Smlaier * delete action, but it's relatively simple and maintains consistency. 669130613Smlaier */ 670130613Smlaier case PFSYNC_ACT_DEL: 671130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 672130613Smlaier count * sizeof(*sp), &offp)) == NULL) { 673130613Smlaier pfsyncstats.pfsyncs_badlen++; 674130613Smlaier return; 675130613Smlaier } 676130613Smlaier 677130613Smlaier s = splsoftnet(); 678130613Smlaier#ifdef __FreeBSD__ 679130613Smlaier PF_LOCK(); 680130613Smlaier#endif 681130613Smlaier for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 682130613Smlaier i < count; i++, sp++) { 683130613Smlaier bcopy(sp->id, &key.id, sizeof(key.id)); 684130613Smlaier key.creatorid = sp->creatorid; 685130613Smlaier 686130613Smlaier st = pf_find_state_byid(&key); 687130613Smlaier if (st == NULL) { 688130613Smlaier pfsyncstats.pfsyncs_badstate++; 689130613Smlaier continue; 690130613Smlaier } 691130613Smlaier st->timeout = PFTM_PURGE; 692130613Smlaier st->sync_flags |= PFSTATE_FROMSYNC; 693145836Smlaier pf_purge_expired_state(st); 694130613Smlaier } 695130613Smlaier#ifdef __FreeBSD__ 696130613Smlaier PF_UNLOCK(); 697130613Smlaier#endif 698130613Smlaier splx(s); 699130613Smlaier break; 700130613Smlaier case PFSYNC_ACT_UPD_C: { 701130613Smlaier int update_requested = 0; 702130613Smlaier 703130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 704130613Smlaier count * sizeof(*up), &offp)) == NULL) { 705130613Smlaier pfsyncstats.pfsyncs_badlen++; 706130613Smlaier return; 707130613Smlaier } 708130613Smlaier 709130613Smlaier s = splsoftnet(); 710130613Smlaier#ifdef __FreeBSD__ 711130613Smlaier PF_LOCK(); 712130613Smlaier#endif 713130613Smlaier for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 714130613Smlaier i < count; i++, up++) { 715130613Smlaier /* check for invalid values */ 716130613Smlaier if (up->timeout >= PFTM_MAX || 717130613Smlaier up->src.state > PF_TCPS_PROXY_DST || 718130613Smlaier up->dst.state > PF_TCPS_PROXY_DST) { 719130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 720130613Smlaier printf("pfsync_insert: " 721130613Smlaier "PFSYNC_ACT_UPD_C: " 722130613Smlaier "invalid value\n"); 723130613Smlaier pfsyncstats.pfsyncs_badstate++; 724130613Smlaier continue; 725130613Smlaier } 726130613Smlaier 727130613Smlaier bcopy(up->id, &key.id, sizeof(key.id)); 728130613Smlaier key.creatorid = up->creatorid; 729130613Smlaier 730130613Smlaier st = pf_find_state_byid(&key); 731130613Smlaier if (st == NULL) { 732130613Smlaier /* We don't have this state. Ask for it. */ 733145836Smlaier error = pfsync_request_update(up, &src); 734145836Smlaier if (error == ENOMEM) { 735145836Smlaier splx(s); 736145836Smlaier goto done; 737145836Smlaier } 738130613Smlaier update_requested = 1; 739130613Smlaier pfsyncstats.pfsyncs_badstate++; 740130613Smlaier continue; 741130613Smlaier } 742145836Smlaier sfail = 0; 743145836Smlaier if (st->proto == IPPROTO_TCP) { 744145836Smlaier /* 745145836Smlaier * The state should never go backwards except 746145836Smlaier * for syn-proxy states. Neither should the 747145836Smlaier * sequence window slide backwards. 748145836Smlaier */ 749145836Smlaier if (st->src.state > up->src.state && 750145836Smlaier (st->src.state < PF_TCPS_PROXY_SRC || 751145836Smlaier up->src.state >= PF_TCPS_PROXY_SRC)) 752145836Smlaier sfail = 1; 753145836Smlaier else if (st->dst.state > up->dst.state) 754145836Smlaier sfail = 2; 755145836Smlaier else if (SEQ_GT(st->src.seqlo, 756145836Smlaier ntohl(up->src.seqlo))) 757145836Smlaier sfail = 3; 758145836Smlaier else if (st->dst.state >= TCPS_SYN_SENT && 759145836Smlaier SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo))) 760145836Smlaier sfail = 4; 761145836Smlaier } else { 762145836Smlaier /* 763145836Smlaier * Non-TCP protocol state machine always go 764145836Smlaier * forwards 765145836Smlaier */ 766145836Smlaier if (st->src.state > up->src.state) 767145836Smlaier sfail = 5; 768145836Smlaier else if (st->dst.state > up->dst.state) 769145836Smlaier sfail = 6; 770145836Smlaier } 771145836Smlaier if (sfail) { 772145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 773145836Smlaier printf("pfsync: ignoring stale update " 774145836Smlaier "(%d) id: %016llx " 775145836Smlaier "creatorid: %08x\n", sfail, 776145836Smlaier#ifdef __FreeBSD__ 777145836Smlaier (unsigned long long)be64toh(st->id), 778145836Smlaier#else 779145836Smlaier betoh64(st->id), 780145836Smlaier#endif 781145836Smlaier ntohl(st->creatorid)); 782145836Smlaier pfsyncstats.pfsyncs_badstate++; 783145836Smlaier 784145836Smlaier /* we have a better state, send it out */ 785145836Smlaier if ((!stale || update_requested) && 786145836Smlaier sc->sc_mbuf != NULL) { 787145836Smlaier pfsync_sendout(sc); 788145836Smlaier update_requested = 0; 789145836Smlaier } 790145836Smlaier stale++; 791145836Smlaier if (!st->sync_flags) 792145836Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, st, 793145836Smlaier PFSYNC_FLAG_STALE); 794145836Smlaier continue; 795145836Smlaier } 796130613Smlaier pf_state_peer_ntoh(&up->src, &st->src); 797130613Smlaier pf_state_peer_ntoh(&up->dst, &st->dst); 798130613Smlaier st->expire = ntohl(up->expire) + time_second; 799130613Smlaier st->timeout = up->timeout; 800130613Smlaier } 801145836Smlaier if ((update_requested || stale) && sc->sc_mbuf) 802130613Smlaier pfsync_sendout(sc); 803130613Smlaier#ifdef __FreeBSD__ 804130613Smlaier PF_UNLOCK(); 805130613Smlaier#endif 806130613Smlaier splx(s); 807130613Smlaier break; 808130613Smlaier } 809130613Smlaier case PFSYNC_ACT_DEL_C: 810130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 811130613Smlaier count * sizeof(*dp), &offp)) == NULL) { 812130613Smlaier pfsyncstats.pfsyncs_badlen++; 813130613Smlaier return; 814130613Smlaier } 815130613Smlaier 816130613Smlaier s = splsoftnet(); 817130613Smlaier#ifdef __FreeBSD__ 818130613Smlaier PF_LOCK(); 819130613Smlaier#endif 820130613Smlaier for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 821130613Smlaier i < count; i++, dp++) { 822130613Smlaier bcopy(dp->id, &key.id, sizeof(key.id)); 823130613Smlaier key.creatorid = dp->creatorid; 824130613Smlaier 825130613Smlaier st = pf_find_state_byid(&key); 826130613Smlaier if (st == NULL) { 827130613Smlaier pfsyncstats.pfsyncs_badstate++; 828130613Smlaier continue; 829130613Smlaier } 830130613Smlaier st->timeout = PFTM_PURGE; 831130613Smlaier st->sync_flags |= PFSTATE_FROMSYNC; 832145836Smlaier pf_purge_expired_state(st); 833130613Smlaier } 834130613Smlaier#ifdef __FreeBSD__ 835130613Smlaier PF_UNLOCK(); 836130613Smlaier#endif 837130613Smlaier splx(s); 838130613Smlaier break; 839130613Smlaier case PFSYNC_ACT_INS_F: 840130613Smlaier case PFSYNC_ACT_DEL_F: 841130613Smlaier /* not implemented */ 842130613Smlaier break; 843130613Smlaier case PFSYNC_ACT_UREQ: 844130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 845130613Smlaier count * sizeof(*rup), &offp)) == NULL) { 846130613Smlaier pfsyncstats.pfsyncs_badlen++; 847130613Smlaier return; 848130613Smlaier } 849130613Smlaier 850130613Smlaier s = splsoftnet(); 851130613Smlaier#ifdef __FreeBSD__ 852130613Smlaier PF_LOCK(); 853130613Smlaier#endif 854130613Smlaier if (sc->sc_mbuf != NULL) 855130613Smlaier pfsync_sendout(sc); 856130613Smlaier for (i = 0, 857130613Smlaier rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 858130613Smlaier i < count; i++, rup++) { 859130613Smlaier bcopy(rup->id, &key.id, sizeof(key.id)); 860130613Smlaier key.creatorid = rup->creatorid; 861130613Smlaier 862130613Smlaier if (key.id == 0 && key.creatorid == 0) { 863130613Smlaier sc->sc_ureq_received = time_uptime; 864130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 865130613Smlaier printf("pfsync: received " 866130613Smlaier "bulk update request\n"); 867130613Smlaier pfsync_send_bus(sc, PFSYNC_BUS_START); 868130613Smlaier#ifdef __FreeBSD__ 869130613Smlaier callout_reset(&sc->sc_bulk_tmo, 1 * hz, 870130613Smlaier pfsync_bulk_update, 871130613Smlaier LIST_FIRST(&pfsync_list)); 872130613Smlaier#else 873130613Smlaier timeout_add(&sc->sc_bulk_tmo, 1 * hz); 874130613Smlaier#endif 875130613Smlaier } else { 876130613Smlaier st = pf_find_state_byid(&key); 877130613Smlaier if (st == NULL) { 878130613Smlaier pfsyncstats.pfsyncs_badstate++; 879130613Smlaier continue; 880130613Smlaier } 881145836Smlaier if (!st->sync_flags) 882145836Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, 883145836Smlaier st, 0); 884130613Smlaier } 885130613Smlaier } 886130613Smlaier if (sc->sc_mbuf != NULL) 887130613Smlaier pfsync_sendout(sc); 888130613Smlaier#ifdef __FreeBSD__ 889130613Smlaier PF_UNLOCK(); 890130613Smlaier#endif 891130613Smlaier splx(s); 892130613Smlaier break; 893130613Smlaier case PFSYNC_ACT_BUS: 894130613Smlaier /* If we're not waiting for a bulk update, who cares. */ 895130613Smlaier if (sc->sc_ureq_sent == 0) 896130613Smlaier break; 897130613Smlaier 898130613Smlaier if ((mp = m_pulldown(m, iplen + sizeof(*ph), 899130613Smlaier sizeof(*bus), &offp)) == NULL) { 900130613Smlaier pfsyncstats.pfsyncs_badlen++; 901130613Smlaier return; 902130613Smlaier } 903130613Smlaier bus = (struct pfsync_state_bus *)(mp->m_data + offp); 904130613Smlaier switch (bus->status) { 905130613Smlaier case PFSYNC_BUS_START: 906130613Smlaier#ifdef __FreeBSD__ 907130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 908130613Smlaier pf_pool_limits[PF_LIMIT_STATES].limit / 909130613Smlaier (PFSYNC_BULKPACKETS * sc->sc_maxcount), 910130613Smlaier pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 911130613Smlaier#else 912130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 913130613Smlaier pf_pool_limits[PF_LIMIT_STATES].limit / 914130613Smlaier (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 915130613Smlaier#endif 916130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 917130613Smlaier printf("pfsync: received bulk " 918130613Smlaier "update start\n"); 919130613Smlaier break; 920130613Smlaier case PFSYNC_BUS_END: 921130613Smlaier if (time_uptime - ntohl(bus->endtime) >= 922130613Smlaier sc->sc_ureq_sent) { 923130613Smlaier /* that's it, we're happy */ 924130613Smlaier sc->sc_ureq_sent = 0; 925130613Smlaier sc->sc_bulk_tries = 0; 926130613Smlaier#ifdef __FreeBSD__ 927130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 928130613Smlaier#else 929130613Smlaier timeout_del(&sc->sc_bulkfail_tmo); 930130613Smlaier#endif 931145836Smlaier#if NCARP > 0 /* XXX_IMPORT */ 932145836Smlaier if (!pfsync_sync_ok) 933145836Smlaier carp_suppress_preempt--; 934145836Smlaier#endif 935130613Smlaier pfsync_sync_ok = 1; 936130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 937130613Smlaier printf("pfsync: received valid " 938130613Smlaier "bulk update end\n"); 939130613Smlaier } else { 940130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 941130613Smlaier printf("pfsync: received invalid " 942130613Smlaier "bulk update end: bad timestamp\n"); 943130613Smlaier } 944130613Smlaier break; 945130613Smlaier } 946130613Smlaier break; 947130613Smlaier } 948130613Smlaier 949130613Smlaierdone: 950130613Smlaier if (m) 951130613Smlaier m_freem(m); 952130613Smlaier} 953130613Smlaier 954130613Smlaierint 955126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 956126258Smlaier struct rtentry *rt) 957126258Smlaier{ 958126258Smlaier m_freem(m); 959126258Smlaier return (0); 960126258Smlaier} 961126258Smlaier 962126258Smlaier/* ARGSUSED */ 963126258Smlaierint 964126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 965126258Smlaier{ 966130613Smlaier#ifndef __FreeBSD__ 967130613Smlaier struct proc *p = curproc; 968130613Smlaier#endif 969126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 970126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 971130613Smlaier struct ip_moptions *imo = &sc->sc_imo; 972130613Smlaier struct pfsyncreq pfsyncr; 973130613Smlaier struct ifnet *sifp; 974130613Smlaier int s, error; 975126258Smlaier 976126258Smlaier switch (cmd) { 977126258Smlaier case SIOCSIFADDR: 978126258Smlaier case SIOCAIFADDR: 979126258Smlaier case SIOCSIFDSTADDR: 980126258Smlaier case SIOCSIFFLAGS: 981126258Smlaier if (ifp->if_flags & IFF_UP) 982126258Smlaier ifp->if_flags |= IFF_RUNNING; 983126258Smlaier else 984126258Smlaier ifp->if_flags &= ~IFF_RUNNING; 985126258Smlaier break; 986126258Smlaier case SIOCSIFMTU: 987126258Smlaier if (ifr->ifr_mtu < PFSYNC_MINMTU) 988126258Smlaier return (EINVAL); 989126258Smlaier if (ifr->ifr_mtu > MCLBYTES) 990126258Smlaier ifr->ifr_mtu = MCLBYTES; 991126258Smlaier s = splnet(); 992130613Smlaier#ifdef __FreeBSD__ 993130613Smlaier PF_LOCK(); 994130613Smlaier#endif 995130613Smlaier if (ifr->ifr_mtu < ifp->if_mtu) { 996126258Smlaier pfsync_sendout(sc); 997130613Smlaier } 998126258Smlaier pfsync_setmtu(sc, ifr->ifr_mtu); 999130613Smlaier#ifdef __FreeBSD__ 1000130613Smlaier PF_UNLOCK(); 1001130613Smlaier#endif 1002126258Smlaier splx(s); 1003126258Smlaier break; 1004130613Smlaier case SIOCGETPFSYNC: 1005130613Smlaier#ifdef __FreeBSD__ 1006130613Smlaier /* XXX: read unlocked */ 1007130613Smlaier#endif 1008130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1009130613Smlaier if (sc->sc_sync_ifp) 1010145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1011130613Smlaier sc->sc_sync_ifp->if_xname, IFNAMSIZ); 1012145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1013130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1014130613Smlaier if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 1015130613Smlaier return (error); 1016130613Smlaier break; 1017130613Smlaier case SIOCSETPFSYNC: 1018130613Smlaier#ifdef __FreeBSD__ 1019130613Smlaier if ((error = suser(curthread)) != 0) 1020130613Smlaier#else 1021130613Smlaier if ((error = suser(p, p->p_acflag)) != 0) 1022130613Smlaier#endif 1023130613Smlaier return (error); 1024130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1025130613Smlaier return (error); 1026130613Smlaier 1027145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1028145836Smlaier sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1029145836Smlaier else 1030145836Smlaier sc->sc_sync_peer.s_addr = 1031145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1032145836Smlaier 1033130613Smlaier if (pfsyncr.pfsyncr_maxupdates > 255) 1034130613Smlaier return (EINVAL); 1035130613Smlaier#ifdef __FreeBSD__ 1036130613Smlaier PF_LOCK(); 1037130613Smlaier#endif 1038130613Smlaier sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1039130613Smlaier 1040145836Smlaier if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1041130613Smlaier sc->sc_sync_ifp = NULL; 1042130613Smlaier if (sc->sc_mbuf_net != NULL) { 1043130613Smlaier /* Don't keep stale pfsync packets around. */ 1044130613Smlaier s = splnet(); 1045130613Smlaier m_freem(sc->sc_mbuf_net); 1046130613Smlaier sc->sc_mbuf_net = NULL; 1047130613Smlaier sc->sc_statep_net.s = NULL; 1048130613Smlaier splx(s); 1049130613Smlaier } 1050145836Smlaier if (imo->imo_num_memberships > 0) { 1051145836Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1052145836Smlaier imo->imo_multicast_ifp = NULL; 1053145836Smlaier } 1054130613Smlaier#ifdef __FreeBSD__ 1055130613Smlaier PF_UNLOCK(); 1056130613Smlaier#endif 1057130613Smlaier break; 1058130613Smlaier } 1059145836Smlaier 1060145836Smlaier if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) { 1061130613Smlaier#ifdef __FreeBSD__ 1062130613Smlaier PF_UNLOCK(); 1063130613Smlaier#endif 1064130613Smlaier return (EINVAL); 1065130613Smlaier } 1066130613Smlaier 1067130613Smlaier s = splnet(); 1068141584Smlaier#ifdef __FreeBSD__ 1069141584Smlaier if (sifp->if_mtu < SCP2IFP(sc)->if_mtu || 1070141584Smlaier#else 1071130613Smlaier if (sifp->if_mtu < sc->sc_if.if_mtu || 1072141584Smlaier#endif 1073130613Smlaier (sc->sc_sync_ifp != NULL && 1074130613Smlaier sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 1075130613Smlaier sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1076130613Smlaier pfsync_sendout(sc); 1077130613Smlaier sc->sc_sync_ifp = sifp; 1078130613Smlaier 1079141584Smlaier#ifdef __FreeBSD__ 1080141584Smlaier pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu); 1081141584Smlaier#else 1082130613Smlaier pfsync_setmtu(sc, sc->sc_if.if_mtu); 1083141584Smlaier#endif 1084130613Smlaier 1085130613Smlaier if (imo->imo_num_memberships > 0) { 1086130613Smlaier in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1087130613Smlaier imo->imo_multicast_ifp = NULL; 1088130613Smlaier } 1089130613Smlaier 1090145836Smlaier if (sc->sc_sync_ifp && 1091145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1092130613Smlaier struct in_addr addr; 1093130613Smlaier 1094145836Smlaier if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) { 1095145836Smlaier sc->sc_sync_ifp = NULL; 1096130613Smlaier#ifdef __FreeBSD__ 1097145836Smlaier PF_UNLOCK(); 1098145836Smlaier#endif 1099145836Smlaier splx(s); 1100145836Smlaier return (EADDRNOTAVAIL); 1101145836Smlaier } 1102145836Smlaier#ifdef __FreeBSD__ 1103130613Smlaier PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ 1104130613Smlaier addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1105130613Smlaier#else 1106130613Smlaier addr.s_addr = INADDR_PFSYNC_GROUP; 1107130613Smlaier#endif 1108145836Smlaier 1109130613Smlaier if ((imo->imo_membership[0] = 1110130613Smlaier in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 1111145836Smlaier sc->sc_sync_ifp = NULL; 1112130613Smlaier splx(s); 1113130613Smlaier return (ENOBUFS); 1114130613Smlaier } 1115130613Smlaier imo->imo_num_memberships++; 1116130613Smlaier imo->imo_multicast_ifp = sc->sc_sync_ifp; 1117130613Smlaier imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1118130613Smlaier imo->imo_multicast_loop = 0; 1119145836Smlaier } 1120130613Smlaier 1121145836Smlaier if (sc->sc_sync_ifp || 1122145836Smlaier sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) { 1123130613Smlaier /* Request a full state table update. */ 1124130613Smlaier#ifdef __FreeBSD__ 1125130613Smlaier PF_LOCK(); 1126145836Smlaier#endif 1127130613Smlaier sc->sc_ureq_sent = time_uptime; 1128145836Smlaier#if NCARP > 0 1129145836Smlaier if (pfsync_sync_ok) 1130145836Smlaier carp_suppress_preempt++; 1131130613Smlaier#endif 1132130613Smlaier pfsync_sync_ok = 0; 1133130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1134130613Smlaier printf("pfsync: requesting bulk update\n"); 1135130613Smlaier#ifdef __FreeBSD__ 1136130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1137130613Smlaier pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 1138130613Smlaier#else 1139130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1140130613Smlaier#endif 1141145836Smlaier error = pfsync_request_update(NULL, NULL); 1142145836Smlaier if (error == ENOMEM) { 1143145836Smlaier#ifdef __FreeBSD__ 1144145836Smlaier PF_UNLOCK(); 1145145836Smlaier#endif 1146145836Smlaier splx(s); 1147145836Smlaier return (ENOMEM); 1148145836Smlaier } 1149130613Smlaier pfsync_sendout(sc); 1150130613Smlaier } 1151130613Smlaier#ifdef __FreeBSD__ 1152130613Smlaier PF_UNLOCK(); 1153130613Smlaier#endif 1154130613Smlaier splx(s); 1155130613Smlaier 1156130613Smlaier break; 1157130613Smlaier 1158126258Smlaier default: 1159126258Smlaier return (ENOTTY); 1160126258Smlaier } 1161126258Smlaier 1162126258Smlaier return (0); 1163126258Smlaier} 1164126258Smlaier 1165126258Smlaiervoid 1166130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 1167130613Smlaier{ 1168126258Smlaier int mtu; 1169130613Smlaier 1170130613Smlaier if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 1171130613Smlaier mtu = sc->sc_sync_ifp->if_mtu; 1172130613Smlaier else 1173130613Smlaier mtu = mtu_req; 1174130613Smlaier 1175130613Smlaier sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 1176130613Smlaier sizeof(struct pfsync_state); 1177130613Smlaier if (sc->sc_maxcount > 254) 1178130613Smlaier sc->sc_maxcount = 254; 1179141584Smlaier#ifdef __FreeBSD__ 1180141584Smlaier SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) + 1181141584Smlaier sc->sc_maxcount * sizeof(struct pfsync_state); 1182141584Smlaier#else 1183126258Smlaier sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 1184130613Smlaier sc->sc_maxcount * sizeof(struct pfsync_state); 1185141584Smlaier#endif 1186126258Smlaier} 1187126258Smlaier 1188126258Smlaierstruct mbuf * 1189130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 1190126258Smlaier{ 1191126258Smlaier struct pfsync_header *h; 1192126258Smlaier struct mbuf *m; 1193126258Smlaier int len; 1194126258Smlaier 1195130613Smlaier#ifdef __FreeBSD__ 1196130613Smlaier PF_ASSERT(MA_OWNED); 1197130613Smlaier#endif 1198126258Smlaier MGETHDR(m, M_DONTWAIT, MT_DATA); 1199126258Smlaier if (m == NULL) { 1200141584Smlaier#ifdef __FreeBSD__ 1201141584Smlaier SCP2IFP(sc)->if_oerrors++; 1202141584Smlaier#else 1203126258Smlaier sc->sc_if.if_oerrors++; 1204141584Smlaier#endif 1205126258Smlaier return (NULL); 1206126258Smlaier } 1207126258Smlaier 1208130613Smlaier switch (action) { 1209130613Smlaier case PFSYNC_ACT_CLR: 1210130613Smlaier len = sizeof(struct pfsync_header) + 1211130613Smlaier sizeof(struct pfsync_state_clr); 1212130613Smlaier break; 1213130613Smlaier case PFSYNC_ACT_UPD_C: 1214130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 1215130613Smlaier sizeof(struct pfsync_header); 1216130613Smlaier break; 1217130613Smlaier case PFSYNC_ACT_DEL_C: 1218130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 1219130613Smlaier sizeof(struct pfsync_header); 1220130613Smlaier break; 1221130613Smlaier case PFSYNC_ACT_UREQ: 1222130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 1223130613Smlaier sizeof(struct pfsync_header); 1224130613Smlaier break; 1225130613Smlaier case PFSYNC_ACT_BUS: 1226130613Smlaier len = sizeof(struct pfsync_header) + 1227130613Smlaier sizeof(struct pfsync_state_bus); 1228130613Smlaier break; 1229130613Smlaier default: 1230130613Smlaier len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 1231130613Smlaier sizeof(struct pfsync_header); 1232130613Smlaier break; 1233130613Smlaier } 1234130613Smlaier 1235126258Smlaier if (len > MHLEN) { 1236126258Smlaier MCLGET(m, M_DONTWAIT); 1237126258Smlaier if ((m->m_flags & M_EXT) == 0) { 1238126258Smlaier m_free(m); 1239141584Smlaier#ifdef __FreeBSD__ 1240141584Smlaier SCP2IFP(sc)->if_oerrors++; 1241141584Smlaier#else 1242126258Smlaier sc->sc_if.if_oerrors++; 1243141584Smlaier#endif 1244126258Smlaier return (NULL); 1245126258Smlaier } 1246130613Smlaier m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 1247130613Smlaier } else 1248130613Smlaier MH_ALIGN(m, len); 1249130613Smlaier 1250126258Smlaier m->m_pkthdr.rcvif = NULL; 1251130613Smlaier m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 1252126258Smlaier h = mtod(m, struct pfsync_header *); 1253126258Smlaier h->version = PFSYNC_VERSION; 1254126258Smlaier h->af = 0; 1255126258Smlaier h->count = 0; 1256126258Smlaier h->action = action; 1257126258Smlaier 1258130613Smlaier *sp = (void *)((char *)h + PFSYNC_HDRLEN); 1259127145Smlaier#ifdef __FreeBSD__ 1260126261Smlaier callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 1261126261Smlaier LIST_FIRST(&pfsync_list)); 1262126261Smlaier#else 1263126258Smlaier timeout_add(&sc->sc_tmo, hz); 1264126261Smlaier#endif 1265126258Smlaier return (m); 1266126258Smlaier} 1267126258Smlaier 1268126258Smlaierint 1269145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) 1270126258Smlaier{ 1271127145Smlaier#ifdef __FreeBSD__ 1272141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1273126261Smlaier#else 1274126258Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1275130613Smlaier#endif 1276126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1277130613Smlaier struct pfsync_header *h, *h_net; 1278130613Smlaier struct pfsync_state *sp = NULL; 1279130613Smlaier struct pfsync_state_upd *up = NULL; 1280130613Smlaier struct pfsync_state_del *dp = NULL; 1281130613Smlaier struct pf_rule *r; 1282126258Smlaier u_long secs; 1283130613Smlaier int s, ret = 0; 1284130613Smlaier u_int8_t i = 255, newaction = 0; 1285126258Smlaier 1286130613Smlaier#ifdef __FreeBSD__ 1287130613Smlaier PF_ASSERT(MA_OWNED); 1288130613Smlaier#endif 1289130613Smlaier /* 1290130613Smlaier * If a packet falls in the forest and there's nobody around to 1291130613Smlaier * hear, does it make a sound? 1292130613Smlaier */ 1293145836Smlaier if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && 1294145836Smlaier sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1295130613Smlaier /* Don't leave any stale pfsync packets hanging around. */ 1296130613Smlaier if (sc->sc_mbuf != NULL) { 1297130613Smlaier m_freem(sc->sc_mbuf); 1298130613Smlaier sc->sc_mbuf = NULL; 1299130613Smlaier sc->sc_statep.s = NULL; 1300130613Smlaier } 1301130613Smlaier return (0); 1302130613Smlaier } 1303130613Smlaier 1304126258Smlaier if (action >= PFSYNC_ACT_MAX) 1305126258Smlaier return (EINVAL); 1306126258Smlaier 1307126258Smlaier s = splnet(); 1308130613Smlaier if (sc->sc_mbuf == NULL) { 1309130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1310130613Smlaier (void *)&sc->sc_statep.s)) == NULL) { 1311126258Smlaier splx(s); 1312126258Smlaier return (ENOMEM); 1313126258Smlaier } 1314130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1315126258Smlaier } else { 1316130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1317126258Smlaier if (h->action != action) { 1318126258Smlaier pfsync_sendout(sc); 1319130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1320130613Smlaier (void *)&sc->sc_statep.s)) == NULL) { 1321126258Smlaier splx(s); 1322126258Smlaier return (ENOMEM); 1323126258Smlaier } 1324130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1325130613Smlaier } else { 1326130613Smlaier /* 1327130613Smlaier * If it's an update, look in the packet to see if 1328130613Smlaier * we already have an update for the state. 1329130613Smlaier */ 1330130613Smlaier if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 1331130613Smlaier struct pfsync_state *usp = 1332130613Smlaier (void *)((char *)h + PFSYNC_HDRLEN); 1333130613Smlaier 1334130613Smlaier for (i = 0; i < h->count; i++) { 1335130613Smlaier if (!memcmp(usp->id, &st->id, 1336130613Smlaier PFSYNC_ID_LEN) && 1337130613Smlaier usp->creatorid == st->creatorid) { 1338130613Smlaier sp = usp; 1339130613Smlaier sp->updates++; 1340130613Smlaier break; 1341130613Smlaier } 1342130613Smlaier usp++; 1343130613Smlaier } 1344130613Smlaier } 1345126258Smlaier } 1346126258Smlaier } 1347126258Smlaier 1348130613Smlaier secs = time_second; 1349126258Smlaier 1350130613Smlaier st->pfsync_time = time_uptime; 1351130613Smlaier TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 1352130613Smlaier TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 1353130613Smlaier 1354130613Smlaier if (sp == NULL) { 1355130613Smlaier /* not a "duplicate" update */ 1356130613Smlaier i = 255; 1357130613Smlaier sp = sc->sc_statep.s++; 1358130613Smlaier sc->sc_mbuf->m_pkthdr.len = 1359130613Smlaier sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 1360130613Smlaier h->count++; 1361130613Smlaier bzero(sp, sizeof(*sp)); 1362130613Smlaier 1363130613Smlaier bcopy(&st->id, sp->id, sizeof(sp->id)); 1364130613Smlaier sp->creatorid = st->creatorid; 1365130613Smlaier 1366130613Smlaier strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 1367130613Smlaier pf_state_host_hton(&st->lan, &sp->lan); 1368130613Smlaier pf_state_host_hton(&st->gwy, &sp->gwy); 1369130613Smlaier pf_state_host_hton(&st->ext, &sp->ext); 1370130613Smlaier 1371130613Smlaier bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 1372130613Smlaier 1373130613Smlaier sp->creation = htonl(secs - st->creation); 1374130613Smlaier sp->packets[0] = htonl(st->packets[0]); 1375130613Smlaier sp->packets[1] = htonl(st->packets[1]); 1376130613Smlaier sp->bytes[0] = htonl(st->bytes[0]); 1377130613Smlaier sp->bytes[1] = htonl(st->bytes[1]); 1378130613Smlaier if ((r = st->rule.ptr) == NULL) 1379130613Smlaier sp->rule = htonl(-1); 1380130613Smlaier else 1381130613Smlaier sp->rule = htonl(r->nr); 1382130613Smlaier if ((r = st->anchor.ptr) == NULL) 1383130613Smlaier sp->anchor = htonl(-1); 1384130613Smlaier else 1385130613Smlaier sp->anchor = htonl(r->nr); 1386130613Smlaier sp->af = st->af; 1387130613Smlaier sp->proto = st->proto; 1388130613Smlaier sp->direction = st->direction; 1389130613Smlaier sp->log = st->log; 1390130613Smlaier sp->allow_opts = st->allow_opts; 1391130613Smlaier sp->timeout = st->timeout; 1392130613Smlaier 1393145836Smlaier if (flags & PFSYNC_FLAG_STALE) 1394145836Smlaier sp->sync_flags |= PFSTATE_STALE; 1395130613Smlaier } 1396130613Smlaier 1397126258Smlaier pf_state_peer_hton(&st->src, &sp->src); 1398126258Smlaier pf_state_peer_hton(&st->dst, &sp->dst); 1399126258Smlaier 1400126258Smlaier if (st->expire <= secs) 1401126258Smlaier sp->expire = htonl(0); 1402126258Smlaier else 1403126258Smlaier sp->expire = htonl(st->expire - secs); 1404126258Smlaier 1405130613Smlaier /* do we need to build "compressed" actions for network transfer? */ 1406145836Smlaier if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { 1407130613Smlaier switch (action) { 1408130613Smlaier case PFSYNC_ACT_UPD: 1409130613Smlaier newaction = PFSYNC_ACT_UPD_C; 1410130613Smlaier break; 1411130613Smlaier case PFSYNC_ACT_DEL: 1412130613Smlaier newaction = PFSYNC_ACT_DEL_C; 1413130613Smlaier break; 1414130613Smlaier default: 1415130613Smlaier /* by default we just send the uncompressed states */ 1416130613Smlaier break; 1417130613Smlaier } 1418130613Smlaier } 1419130613Smlaier 1420130613Smlaier if (newaction) { 1421130613Smlaier if (sc->sc_mbuf_net == NULL) { 1422130613Smlaier if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 1423130613Smlaier (void *)&sc->sc_statep_net.s)) == NULL) { 1424130613Smlaier splx(s); 1425130613Smlaier return (ENOMEM); 1426130613Smlaier } 1427130613Smlaier } 1428130613Smlaier h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 1429130613Smlaier 1430130613Smlaier switch (newaction) { 1431130613Smlaier case PFSYNC_ACT_UPD_C: 1432130613Smlaier if (i != 255) { 1433130613Smlaier up = (void *)((char *)h_net + 1434130613Smlaier PFSYNC_HDRLEN + (i * sizeof(*up))); 1435130613Smlaier up->updates++; 1436130613Smlaier } else { 1437130613Smlaier h_net->count++; 1438130613Smlaier sc->sc_mbuf_net->m_pkthdr.len = 1439130613Smlaier sc->sc_mbuf_net->m_len += sizeof(*up); 1440130613Smlaier up = sc->sc_statep_net.u++; 1441130613Smlaier 1442130613Smlaier bzero(up, sizeof(*up)); 1443130613Smlaier bcopy(&st->id, up->id, sizeof(up->id)); 1444130613Smlaier up->creatorid = st->creatorid; 1445130613Smlaier } 1446130613Smlaier up->timeout = st->timeout; 1447130613Smlaier up->expire = sp->expire; 1448130613Smlaier up->src = sp->src; 1449130613Smlaier up->dst = sp->dst; 1450130613Smlaier break; 1451130613Smlaier case PFSYNC_ACT_DEL_C: 1452130613Smlaier sc->sc_mbuf_net->m_pkthdr.len = 1453130613Smlaier sc->sc_mbuf_net->m_len += sizeof(*dp); 1454130613Smlaier dp = sc->sc_statep_net.d++; 1455130613Smlaier h_net->count++; 1456130613Smlaier 1457130613Smlaier bzero(dp, sizeof(*dp)); 1458130613Smlaier bcopy(&st->id, dp->id, sizeof(dp->id)); 1459130613Smlaier dp->creatorid = st->creatorid; 1460130613Smlaier break; 1461130613Smlaier } 1462130613Smlaier } 1463130613Smlaier 1464130613Smlaier if (h->count == sc->sc_maxcount || 1465130613Smlaier (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 1466126258Smlaier ret = pfsync_sendout(sc); 1467126258Smlaier 1468126258Smlaier splx(s); 1469130613Smlaier return (ret); 1470126258Smlaier} 1471126258Smlaier 1472130613Smlaier/* This must be called in splnet() */ 1473126258Smlaierint 1474130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 1475126258Smlaier{ 1476127145Smlaier#ifdef __FreeBSD__ 1477141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1478126261Smlaier#else 1479126258Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1480130613Smlaier#endif 1481130613Smlaier struct pfsync_header *h; 1482126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1483130613Smlaier struct pfsync_state_upd_req *rup; 1484145836Smlaier int ret = 0; 1485130613Smlaier 1486130613Smlaier#ifdef __FreeBSD__ 1487130613Smlaier PF_ASSERT(MA_OWNED); 1488126261Smlaier#endif 1489130613Smlaier if (sc->sc_mbuf == NULL) { 1490130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1491145836Smlaier (void *)&sc->sc_statep.s)) == NULL) 1492130613Smlaier return (ENOMEM); 1493130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1494130613Smlaier } else { 1495130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1496130613Smlaier if (h->action != PFSYNC_ACT_UREQ) { 1497130613Smlaier pfsync_sendout(sc); 1498130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1499145836Smlaier (void *)&sc->sc_statep.s)) == NULL) 1500130613Smlaier return (ENOMEM); 1501130613Smlaier h = mtod(sc->sc_mbuf, struct pfsync_header *); 1502130613Smlaier } 1503130613Smlaier } 1504130613Smlaier 1505130613Smlaier if (src != NULL) 1506130613Smlaier sc->sc_sendaddr = *src; 1507130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 1508130613Smlaier h->count++; 1509130613Smlaier rup = sc->sc_statep.r++; 1510130613Smlaier bzero(rup, sizeof(*rup)); 1511130613Smlaier if (up != NULL) { 1512130613Smlaier bcopy(up->id, rup->id, sizeof(rup->id)); 1513130613Smlaier rup->creatorid = up->creatorid; 1514130613Smlaier } 1515130613Smlaier 1516130613Smlaier if (h->count == sc->sc_maxcount) 1517130613Smlaier ret = pfsync_sendout(sc); 1518130613Smlaier 1519130613Smlaier return (ret); 1520130613Smlaier} 1521130613Smlaier 1522130613Smlaierint 1523130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname) 1524130613Smlaier{ 1525130613Smlaier#ifdef __FreeBSD__ 1526141584Smlaier struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1527130613Smlaier#else 1528130613Smlaier struct ifnet *ifp = &pfsyncif.sc_if; 1529130613Smlaier#endif 1530130613Smlaier struct pfsync_softc *sc = ifp->if_softc; 1531130613Smlaier struct pfsync_state_clr *cp; 1532126258Smlaier int s, ret; 1533126258Smlaier 1534126258Smlaier s = splnet(); 1535130613Smlaier#ifdef __FreeBSD__ 1536130613Smlaier PF_ASSERT(MA_OWNED); 1537130613Smlaier#endif 1538130613Smlaier if (sc->sc_mbuf != NULL) 1539130613Smlaier pfsync_sendout(sc); 1540130613Smlaier if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 1541130613Smlaier (void *)&sc->sc_statep.c)) == NULL) { 1542126258Smlaier splx(s); 1543126258Smlaier return (ENOMEM); 1544126258Smlaier } 1545130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 1546130613Smlaier cp = sc->sc_statep.c; 1547130613Smlaier cp->creatorid = creatorid; 1548130613Smlaier if (ifname != NULL) 1549130613Smlaier strlcpy(cp->ifname, ifname, IFNAMSIZ); 1550126258Smlaier 1551126258Smlaier ret = (pfsync_sendout(sc)); 1552126258Smlaier splx(s); 1553126258Smlaier return (ret); 1554126258Smlaier} 1555126258Smlaier 1556126258Smlaiervoid 1557126258Smlaierpfsync_timeout(void *v) 1558126258Smlaier{ 1559126258Smlaier struct pfsync_softc *sc = v; 1560126258Smlaier int s; 1561126258Smlaier 1562126258Smlaier s = splnet(); 1563130613Smlaier#ifdef __FreeBSD__ 1564130613Smlaier PF_LOCK(); 1565130613Smlaier#endif 1566126258Smlaier pfsync_sendout(sc); 1567130613Smlaier#ifdef __FreeBSD__ 1568130613Smlaier PF_UNLOCK(); 1569130613Smlaier#endif 1570126258Smlaier splx(s); 1571126258Smlaier} 1572126258Smlaier 1573145836Smlaier/* This must be called in splnet() */ 1574130613Smlaiervoid 1575130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 1576130613Smlaier{ 1577130613Smlaier struct pfsync_state_bus *bus; 1578130613Smlaier 1579130613Smlaier#ifdef __FreeBSD__ 1580130613Smlaier PF_ASSERT(MA_OWNED); 1581130613Smlaier#endif 1582130613Smlaier if (sc->sc_mbuf != NULL) 1583130613Smlaier pfsync_sendout(sc); 1584130613Smlaier 1585130613Smlaier if (pfsync_sync_ok && 1586130613Smlaier (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 1587130613Smlaier (void *)&sc->sc_statep.b)) != NULL) { 1588130613Smlaier sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 1589130613Smlaier bus = sc->sc_statep.b; 1590130613Smlaier bus->creatorid = pf_status.hostid; 1591130613Smlaier bus->status = status; 1592130613Smlaier bus->endtime = htonl(time_uptime - sc->sc_ureq_received); 1593130613Smlaier pfsync_sendout(sc); 1594130613Smlaier } 1595130613Smlaier} 1596130613Smlaier 1597130613Smlaiervoid 1598130613Smlaierpfsync_bulk_update(void *v) 1599130613Smlaier{ 1600130613Smlaier struct pfsync_softc *sc = v; 1601130613Smlaier int s, i = 0; 1602130613Smlaier struct pf_state *state; 1603130613Smlaier 1604130613Smlaier#ifdef __FreeBSD__ 1605130613Smlaier PF_LOCK(); 1606130613Smlaier#endif 1607130613Smlaier s = splnet(); 1608130613Smlaier if (sc->sc_mbuf != NULL) 1609130613Smlaier pfsync_sendout(sc); 1610130613Smlaier 1611130613Smlaier /* 1612130613Smlaier * Grab at most PFSYNC_BULKPACKETS worth of states which have not 1613130613Smlaier * been sent since the latest request was made. 1614130613Smlaier */ 1615130613Smlaier while ((state = TAILQ_FIRST(&state_updates)) != NULL && 1616130613Smlaier ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 1617130613Smlaier if (state->pfsync_time > sc->sc_ureq_received) { 1618130613Smlaier /* we're done */ 1619130613Smlaier pfsync_send_bus(sc, PFSYNC_BUS_END); 1620130613Smlaier sc->sc_ureq_received = 0; 1621130613Smlaier#ifdef __FreeBSD__ 1622130613Smlaier callout_stop(&sc->sc_bulk_tmo); 1623130613Smlaier#else 1624130613Smlaier timeout_del(&sc->sc_bulk_tmo); 1625130613Smlaier#endif 1626130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1627130613Smlaier printf("pfsync: bulk update complete\n"); 1628130613Smlaier break; 1629130613Smlaier } else { 1630130613Smlaier /* send an update and move to end of list */ 1631130613Smlaier if (!state->sync_flags) 1632130613Smlaier pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 1633130613Smlaier state->pfsync_time = time_uptime; 1634130613Smlaier TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 1635130613Smlaier TAILQ_INSERT_TAIL(&state_updates, state, 1636130613Smlaier u.s.entry_updates); 1637130613Smlaier 1638130613Smlaier /* look again for more in a bit */ 1639130613Smlaier#ifdef __FreeBSD__ 1640130613Smlaier callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 1641130613Smlaier LIST_FIRST(&pfsync_list)); 1642130613Smlaier#else 1643130613Smlaier timeout_add(&sc->sc_bulk_tmo, 1); 1644130613Smlaier#endif 1645130613Smlaier } 1646130613Smlaier } 1647130613Smlaier if (sc->sc_mbuf != NULL) 1648130613Smlaier pfsync_sendout(sc); 1649130613Smlaier splx(s); 1650130613Smlaier#ifdef __FreeBSD__ 1651130613Smlaier PF_UNLOCK(); 1652130613Smlaier#endif 1653130613Smlaier} 1654130613Smlaier 1655130613Smlaiervoid 1656130613Smlaierpfsync_bulkfail(void *v) 1657130613Smlaier{ 1658130613Smlaier struct pfsync_softc *sc = v; 1659145836Smlaier int s, error; 1660130613Smlaier 1661130613Smlaier#ifdef __FreeBSD__ 1662130613Smlaier PF_LOCK(); 1663130613Smlaier#endif 1664130613Smlaier if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1665130613Smlaier /* Try again in a bit */ 1666130613Smlaier#ifdef __FreeBSD__ 1667130613Smlaier callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1668130613Smlaier LIST_FIRST(&pfsync_list)); 1669130613Smlaier#else 1670130613Smlaier timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1671130613Smlaier#endif 1672145836Smlaier s = splnet(); 1673145836Smlaier error = pfsync_request_update(NULL, NULL); 1674145836Smlaier if (error == ENOMEM) { 1675145836Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1676145836Smlaier printf("pfsync: cannot allocate mbufs for " 1677145836Smlaier "bulk update\n"); 1678145836Smlaier } else 1679145836Smlaier pfsync_sendout(sc); 1680145836Smlaier splx(s); 1681130613Smlaier } else { 1682130613Smlaier /* Pretend like the transfer was ok */ 1683130613Smlaier sc->sc_ureq_sent = 0; 1684130613Smlaier sc->sc_bulk_tries = 0; 1685145836Smlaier#if NCARP > 0 1686145836Smlaier if (!pfsync_sync_ok) 1687145836Smlaier carp_suppress_preempt--; 1688145836Smlaier#endif 1689130613Smlaier pfsync_sync_ok = 1; 1690130613Smlaier if (pf_status.debug >= PF_DEBUG_MISC) 1691130613Smlaier printf("pfsync: failed to receive " 1692130613Smlaier "bulk update status\n"); 1693130613Smlaier#ifdef __FreeBSD__ 1694130613Smlaier callout_stop(&sc->sc_bulkfail_tmo); 1695130613Smlaier#else 1696130613Smlaier timeout_del(&sc->sc_bulkfail_tmo); 1697130613Smlaier#endif 1698130613Smlaier } 1699130613Smlaier#ifdef __FreeBSD__ 1700130613Smlaier PF_UNLOCK(); 1701130613Smlaier#endif 1702130613Smlaier} 1703130613Smlaier 1704145836Smlaier/* This must be called in splnet() */ 1705126258Smlaierint 1706126258Smlaierpfsync_sendout(sc) 1707126258Smlaier struct pfsync_softc *sc; 1708126258Smlaier{ 1709138666Smlaier#if NBPFILTER > 0 1710141584Smlaier# ifdef __FreeBSD__ 1711141584Smlaier struct ifnet *ifp = SCP2IFP(sc); 1712141584Smlaier# else 1713141584Smlaier struct ifnet *ifp = &sc->if_sc; 1714141584Smlaier# endif 1715138666Smlaier#endif 1716130613Smlaier struct mbuf *m; 1717126258Smlaier 1718127145Smlaier#ifdef __FreeBSD__ 1719130613Smlaier PF_ASSERT(MA_OWNED); 1720126261Smlaier callout_stop(&sc->sc_tmo); 1721126261Smlaier#else 1722126258Smlaier timeout_del(&sc->sc_tmo); 1723126261Smlaier#endif 1724130613Smlaier 1725130613Smlaier if (sc->sc_mbuf == NULL) 1726130613Smlaier return (0); 1727130613Smlaier m = sc->sc_mbuf; 1728126258Smlaier sc->sc_mbuf = NULL; 1729130613Smlaier sc->sc_statep.s = NULL; 1730126258Smlaier 1731127145Smlaier#ifdef __FreeBSD__ 1732126261Smlaier KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1733126261Smlaier#endif 1734126258Smlaier#if NBPFILTER > 0 1735126258Smlaier if (ifp->if_bpf) 1736126258Smlaier bpf_mtap(ifp->if_bpf, m); 1737126258Smlaier#endif 1738126258Smlaier 1739130613Smlaier if (sc->sc_mbuf_net) { 1740130613Smlaier m_freem(m); 1741130613Smlaier m = sc->sc_mbuf_net; 1742130613Smlaier sc->sc_mbuf_net = NULL; 1743130613Smlaier sc->sc_statep_net.s = NULL; 1744130613Smlaier } 1745126258Smlaier 1746145836Smlaier if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { 1747130613Smlaier struct ip *ip; 1748130613Smlaier struct sockaddr sa; 1749130613Smlaier 1750130613Smlaier M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 1751130613Smlaier if (m == NULL) { 1752130613Smlaier pfsyncstats.pfsyncs_onomem++; 1753130613Smlaier return (0); 1754130613Smlaier } 1755130613Smlaier ip = mtod(m, struct ip *); 1756130613Smlaier ip->ip_v = IPVERSION; 1757130613Smlaier ip->ip_hl = sizeof(*ip) >> 2; 1758130613Smlaier ip->ip_tos = IPTOS_LOWDELAY; 1759130613Smlaier#ifdef __FreeBSD__ 1760130613Smlaier ip->ip_len = m->m_pkthdr.len; 1761130613Smlaier#else 1762130613Smlaier ip->ip_len = htons(m->m_pkthdr.len); 1763130613Smlaier#endif 1764130613Smlaier ip->ip_id = htons(ip_randomid()); 1765130613Smlaier#ifdef __FreeBSD__ 1766130613Smlaier ip->ip_off = IP_DF; 1767130613Smlaier#else 1768130613Smlaier ip->ip_off = htons(IP_DF); 1769130613Smlaier#endif 1770130613Smlaier ip->ip_ttl = PFSYNC_DFLTTL; 1771130613Smlaier ip->ip_p = IPPROTO_PFSYNC; 1772130613Smlaier ip->ip_sum = 0; 1773130613Smlaier 1774130613Smlaier bzero(&sa, sizeof(sa)); 1775145836Smlaier ip->ip_src.s_addr = INADDR_ANY; 1776130613Smlaier 1777130613Smlaier#ifdef __FreeBSD__ 1778130613Smlaier if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1779130613Smlaier#else 1780130613Smlaier if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) 1781130613Smlaier#endif 1782130613Smlaier m->m_flags |= M_MCAST; 1783130613Smlaier ip->ip_dst = sc->sc_sendaddr; 1784130613Smlaier#ifdef __FreeBSD__ 1785145836Smlaier /* XXX_IMPORT */ 1786145836Smlaier sc->sc_sendaddr.s_addr = htonl(sc->sc_sync_peer.s_addr); 1787130613Smlaier#else 1788145836Smlaier sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr; 1789130613Smlaier#endif 1790130613Smlaier 1791130613Smlaier pfsyncstats.pfsyncs_opackets++; 1792130613Smlaier 1793130613Smlaier#ifdef __FreeBSD__ 1794130613Smlaier PF_UNLOCK(); 1795130613Smlaier#endif 1796130613Smlaier if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1797130613Smlaier pfsyncstats.pfsyncs_oerrors++; 1798130613Smlaier 1799130613Smlaier#ifdef __FreeBSD__ 1800130613Smlaier PF_LOCK(); 1801130613Smlaier#endif 1802130613Smlaier } else 1803130613Smlaier m_freem(m); 1804130613Smlaier 1805126258Smlaier return (0); 1806126258Smlaier} 1807126261Smlaier 1808126261Smlaier 1809127145Smlaier#ifdef __FreeBSD__ 1810126261Smlaierstatic int 1811126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 1812126261Smlaier{ 1813126261Smlaier int error = 0; 1814126261Smlaier 1815126261Smlaier switch (type) { 1816126261Smlaier case MOD_LOAD: 1817126261Smlaier LIST_INIT(&pfsync_list); 1818126261Smlaier if_clone_attach(&pfsync_cloner); 1819126261Smlaier break; 1820126261Smlaier 1821126261Smlaier case MOD_UNLOAD: 1822126261Smlaier if_clone_detach(&pfsync_cloner); 1823126261Smlaier while (!LIST_EMPTY(&pfsync_list)) 1824126261Smlaier pfsync_clone_destroy( 1825141584Smlaier SCP2IFP(LIST_FIRST(&pfsync_list))); 1826126261Smlaier break; 1827126261Smlaier 1828126261Smlaier default: 1829126261Smlaier error = EINVAL; 1830126261Smlaier break; 1831126261Smlaier } 1832126261Smlaier 1833126261Smlaier return error; 1834126261Smlaier} 1835126261Smlaier 1836126261Smlaierstatic moduledata_t pfsync_mod = { 1837126261Smlaier "pfsync", 1838126261Smlaier pfsync_modevent, 1839126261Smlaier 0 1840126261Smlaier}; 1841126261Smlaier 1842126261Smlaier#define PFSYNC_MODVER 1 1843126261Smlaier 1844135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 1845126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 1846126261Smlaier#endif /* __FreeBSD__ */ 1847