if_pfsync.c revision 165632
1101704Smjacob/* $FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 165632 2006-12-29 13:59:50Z jhb $ */ 2139749Simp/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */ 3101704Smjacob 4101704Smjacob/* 5101704Smjacob * Copyright (c) 2002 Michael Shalayeff 6101704Smjacob * All rights reserved. 7101704Smjacob * 8101704Smjacob * Redistribution and use in source and binary forms, with or without 9101704Smjacob * modification, are permitted provided that the following conditions 10101704Smjacob * are met: 11101704Smjacob * 1. Redistributions of source code must retain the above copyright 12101704Smjacob * notice, this list of conditions and the following disclaimer. 13101704Smjacob * 2. Redistributions in binary form must reproduce the above copyright 14101704Smjacob * notice, this list of conditions and the following disclaimer in the 15101704Smjacob * documentation and/or other materials provided with the distribution. 16101704Smjacob * 17101704Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18101704Smjacob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19101704Smjacob * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20101704Smjacob * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21101704Smjacob * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22101704Smjacob * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23101704Smjacob * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24101704Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25101704Smjacob * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26101704Smjacob * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27101704Smjacob * THE POSSIBILITY OF SUCH DAMAGE. 28156000Smjacob */ 29156000Smjacob 30156000Smjacob#ifdef __FreeBSD__ 31156000Smjacob#include "opt_inet.h" 32156000Smjacob#include "opt_inet6.h" 33156000Smjacob#endif 34156000Smjacob 35156000Smjacob#ifndef __FreeBSD__ 36156000Smjacob#include "bpfilter.h" 37156000Smjacob#include "pfsync.h" 38156000Smjacob#elif __FreeBSD__ >= 5 39156000Smjacob#include "opt_bpf.h" 40156000Smjacob#include "opt_pf.h" 41156000Smjacob 42156000Smjacob#ifdef DEV_BPF 43156000Smjacob#define NBPFILTER DEV_BPF 44156000Smjacob#else 45156000Smjacob#define NBPFILTER 0 46156000Smjacob#endif 47156000Smjacob 48156000Smjacob#ifdef DEV_PFSYNC 49156000Smjacob#define NPFSYNC DEV_PFSYNC 50156000Smjacob#else 51156000Smjacob#define NPFSYNC 0 52156000Smjacob#endif 53156000Smjacob 54156000Smjacob#endif 55156000Smjacob 56156000Smjacob#include <sys/param.h> 57156000Smjacob#ifdef __FreeBSD__ 58147883Sscottl#include <sys/priv.h> 59156000Smjacob#endif 60156000Smjacob#include <sys/proc.h> 61159052Smjacob#include <sys/systm.h> 62159052Smjacob#include <sys/time.h> 63159052Smjacob#include <sys/mbuf.h> 64159052Smjacob#include <sys/socket.h> 65101704Smjacob#include <sys/kernel.h> 66101704Smjacob#ifdef __FreeBSD__ 67147883Sscottl#include <sys/endian.h> 68147883Sscottl#include <sys/malloc.h> 69147883Sscottl#include <sys/module.h> 70147883Sscottl#include <sys/sockio.h> 71147883Sscottl#include <sys/lock.h> 72147883Sscottl#include <sys/mutex.h> 73147883Sscottl#include <sys/sysctl.h> 74147883Sscottl#else 75147883Sscottl#include <sys/ioctl.h> 76147883Sscottl#include <sys/timeout.h> 77147883Sscottl#endif 78147883Sscottl 79147883Sscottl#include <net/if.h> 80147883Sscottl#if defined(__FreeBSD__) 81147883Sscottl#include <net/if_clone.h> 82148679Sgibbs#endif 83148679Sgibbs#include <net/if_types.h> 84148679Sgibbs#include <net/route.h> 85147883Sscottl#include <net/bpf.h> 86147883Sscottl#include <netinet/tcp.h> 87147883Sscottl#include <netinet/tcp_seq.h> 88147883Sscottl 89147883Sscottl#ifdef INET 90147883Sscottl#include <netinet/in.h> 91147883Sscottl#include <netinet/in_systm.h> 92147883Sscottl#include <netinet/in_var.h> 93147883Sscottl#include <netinet/ip.h> 94147883Sscottl#include <netinet/ip_var.h> 95147883Sscottl#endif 96147883Sscottl 97101704Smjacob#ifdef INET6 98101704Smjacob#ifndef INET 99101704Smjacob#include <netinet/in.h> 100101704Smjacob#endif 101147883Sscottl#include <netinet6/nd6.h> 102147883Sscottl#endif /* INET6 */ 103147883Sscottl 104147883Sscottl#ifdef __FreeBSD__ 105241874Smarius#include "opt_carp.h" 106241874Smarius#ifdef DEV_CARP 107147883Sscottl#define NCARP 1 108147883Sscottl#else 109147883Sscottl#define NCARP 0 110147883Sscottl#endif 111147883Sscottl#else 112241874Smarius#include "carp.h" 113147883Sscottl#endif 114147883Sscottl#if NCARP > 0 115241874Smariusextern int carp_suppress_preempt; 116241874Smarius#endif 117241874Smarius 118147883Sscottl#include <net/pfvar.h> 119241874Smarius#include <net/if_pfsync.h> 120147883Sscottl 121147883Sscottl#ifdef __FreeBSD__ 122147883Sscottl#define PFSYNCNAME "pfsync" 123207287Smarius#endif 124207287Smarius 125207287Smarius#define PFSYNC_MINMTU \ 126207287Smarius (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 127207287Smarius 128155521Smjacob#ifdef PFSYNCDEBUG 129155521Smjacob#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 130155521Smjacobint pfsyncdebug; 131147883Sscottl#else 132147883Sscottl#define DPRINTF(x) 133147883Sscottl#endif 134147883Sscottl 135147883Sscottl#ifndef __FreeBSD__ 136147883Sscottlstruct pfsync_softc pfsyncif; 137147883Sscottl#endif 138147883Sscottlstruct pfsyncstats pfsyncstats; 139147883Sscottl#ifdef __FreeBSD__ 140147883SscottlSYSCTL_DECL(_net_inet_pfsync); 141147883SscottlSYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW, 142147883Sscottl &pfsyncstats, pfsyncstats, 143147883Sscottl "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 144147883Sscottl 145147883Sscottl/* 146164990Smjacob * Locking notes: 147164990Smjacob * Whenever we really touch/look at the state table we have to hold the 148164990Smjacob * PF_LOCK. Functions that do just the interface handling, grab the per 149147883Sscottl * softc lock instead. 150165814Smjacob * 151101704Smjacob */ 152101704Smjacob 153101704Smjacobstatic void pfsync_clone_destroy(struct ifnet *); 154147883Sscottlstatic int pfsync_clone_create(struct if_clone *, int, caddr_t params); 155101704Smjacobstatic void pfsync_senddef(void *); 156157117Smjacob#else 157157117Smjacobvoid pfsyncattach(int); 158157117Smjacob#endif 159157117Smjacobvoid pfsync_setmtu(struct pfsync_softc *, int); 160157117Smjacobint pfsync_insert_net_state(struct pfsync_state *); 161157117Smjacobint pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 162207287Smarius struct rtentry *); 163207287Smariusint pfsyncioctl(struct ifnet *, u_long, caddr_t); 164147883Sscottlvoid pfsyncstart(struct ifnet *); 165147883Sscottl 166147883Sscottlstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 167147883Sscottlint pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 168101704Smjacobint pfsync_sendout(struct pfsync_softc *); 169147883Sscottlvoid pfsync_timeout(void *); 170147883Sscottlvoid pfsync_send_bus(struct pfsync_softc *, u_int8_t); 171147883Sscottlvoid pfsync_bulk_update(void *); 172147883Sscottlvoid pfsync_bulkfail(void *); 173157117Smjacob 174162133Smjacobint pfsync_sync_ok; 175147883Sscottl#ifndef __FreeBSD__ 176147883Sscottlextern int ifqmaxlen; 177147883Sscottlextern struct timeval time; 178147883Sscottlextern struct timeval mono_time; 179147883Sscottlextern int hz; 180147883Sscottl#endif 181147883Sscottl 182147883Sscottl#ifdef __FreeBSD__ 183147883Sscottlstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 184147883Sscottlstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 185147883Sscottl#define SCP2IFP(sc) ((sc)->sc_ifp) 186147883SscottlIFC_SIMPLE_DECLARE(pfsync, 1); 187147883Sscottl 188147883Sscottlstatic void 189147883Sscottlpfsync_clone_destroy(struct ifnet *ifp) 190147883Sscottl{ 191147883Sscottl struct pfsync_softc *sc; 192157117Smjacob 193162133Smjacob sc = ifp->if_softc; 194147883Sscottl callout_stop(&sc->sc_tmo); 195147883Sscottl callout_stop(&sc->sc_bulk_tmo); 196147883Sscottl callout_stop(&sc->sc_bulkfail_tmo); 197147883Sscottl 198147883Sscottl callout_stop(&sc->sc_send_tmo); 199147883Sscottl 200101704Smjacob#if NBPFILTER > 0 201101704Smjacob bpfdetach(ifp); 202147883Sscottl#endif 203101704Smjacob if_detach(ifp); 204147883Sscottl if_free(ifp); 205147883Sscottl LIST_REMOVE(sc, sc_next); 206101704Smjacob free(sc->sc_imo.imo_membership, M_PFSYNC); 207147883Sscottl free(sc, M_PFSYNC); 208147883Sscottl} 209101704Smjacob 210147883Sscottlstatic int 211147883Sscottl#ifdef __FreeBSD__ 212147883Sscottlpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params) 213147883Sscottl#else 214147883Sscottlpfsync_clone_create(struct if_clone *ifc, int unit) 215147883Sscottl#endif 216147883Sscottl{ 217147883Sscottl struct pfsync_softc *sc; 218147883Sscottl struct ifnet *ifp; 219147883Sscottl 220147883Sscottl MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 221147883Sscottl M_WAITOK|M_ZERO); 222147883Sscottl ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 223167426Smjacob if (ifp == NULL) { 224167426Smjacob free(sc, M_PFSYNC); 225167426Smjacob return (ENOSPC); 226147883Sscottl } 227147883Sscottl 228147883Sscottl pfsync_sync_ok = 1; 229147883Sscottl sc->sc_mbuf = NULL; 230147883Sscottl sc->sc_mbuf_net = NULL; 231147883Sscottl sc->sc_statep.s = NULL; 232147883Sscottl sc->sc_statep_net.s = NULL; 233169293Smjacob sc->sc_maxupdates = 128; 234147883Sscottl sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 235147883Sscottl sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 236147883Sscottl sc->sc_ureq_received = 0; 237147883Sscottl sc->sc_ureq_sent = 0; 238147883Sscottl sc->sc_imo.imo_membership = (struct in_multi **)malloc( 239147883Sscottl (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, 240147883Sscottl M_WAITOK); 241147883Sscottl sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 242166935Smjacob 243166935Smjacob ifp = SCP2IFP(sc); 244166935Smjacob if_initname(ifp, ifc->ifc_name, unit); 245166935Smjacob ifp->if_ioctl = pfsyncioctl; 246166935Smjacob ifp->if_output = pfsyncoutput; 247166935Smjacob ifp->if_start = pfsyncstart; 248166935Smjacob ifp->if_snd.ifq_maxlen = ifqmaxlen; 249147883Sscottl ifp->if_hdrlen = PFSYNC_HDRLEN; 250178725Sjkim ifp->if_baudrate = IF_Mbps(100); 251178725Sjkim ifp->if_softc = sc; 252178725Sjkim pfsync_setmtu(sc, MCLBYTES); 253178725Sjkim callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE); 254178725Sjkim callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE); 255178725Sjkim callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE); 256178725Sjkim callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE); 257178725Sjkim sc->sc_ifq.ifq_maxlen = ifqmaxlen; 258147883Sscottl mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue", 259172842Sjulian MTX_DEF); 260147883Sscottl if_attach(ifp); 261172836Sjulian 262178725Sjkim LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 263178725Sjkim#if NBPFILTER > 0 264241874Smarius bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 265147883Sscottl#endif 266172842Sjulian 267178725Sjkim return (0); 268178725Sjkim} 269172842Sjulian#else /* !__FreeBSD__ */ 270147883Sscottlvoid 271147883Sscottlpfsyncattach(int npfsync) 272164990Smjacob{ 273164990Smjacob struct ifnet *ifp; 274164990Smjacob 275147883Sscottl pfsync_sync_ok = 1; 276164990Smjacob bzero(&pfsyncif, sizeof(pfsyncif)); 277164990Smjacob pfsyncif.sc_mbuf = NULL; 278164990Smjacob pfsyncif.sc_mbuf_net = NULL; 279147883Sscottl pfsyncif.sc_statep.s = NULL; 280164998Smjacob pfsyncif.sc_statep_net.s = NULL; 281164998Smjacob pfsyncif.sc_maxupdates = 128; 282164998Smjacob pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 283164998Smjacob pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; 284164998Smjacob pfsyncif.sc_ureq_received = 0; 285186878Smarius pfsyncif.sc_ureq_sent = 0; 286186878Smarius ifp = &pfsyncif.sc_if; 287186878Smarius strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname); 288186878Smarius ifp->if_softc = &pfsyncif; 289186878Smarius ifp->if_ioctl = pfsyncioctl; 290186878Smarius ifp->if_output = pfsyncoutput; 291186878Smarius ifp->if_start = pfsyncstart; 292186878Smarius ifp->if_type = IFT_PFSYNC; 293186878Smarius ifp->if_snd.ifq_maxlen = ifqmaxlen; 294186878Smarius ifp->if_hdrlen = PFSYNC_HDRLEN; 295186878Smarius pfsync_setmtu(&pfsyncif, MCLBYTES); 296164998Smjacob timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif); 297186878Smarius timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif); 298164998Smjacob timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif); 299164998Smjacob if_attach(ifp); 300164990Smjacob if_alloc_sadl(ifp); 301164990Smjacob 302164990Smjacob#if NBPFILTER > 0 303164990Smjacob bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 304186878Smarius#endif 305186878Smarius} 306186878Smarius#endif 307186878Smarius 308186878Smarius/* 309186878Smarius * Start output on the pfsync interface. 310186878Smarius */ 311186878Smariusvoid 312186878Smariuspfsyncstart(struct ifnet *ifp) 313186878Smarius{ 314186878Smarius#ifdef __FreeBSD__ 315164990Smjacob IF_LOCK(&ifp->if_snd); 316186878Smarius _IF_DROP(&ifp->if_snd); 317186878Smarius _IF_DRAIN(&ifp->if_snd); 318164990Smjacob IF_UNLOCK(&ifp->if_snd); 319164990Smjacob#else 320164990Smjacob struct mbuf *m; 321147883Sscottl int s; 322147883Sscottl 323157354Smjacob for (;;) { 324157354Smjacob s = splimp(); 325157354Smjacob IF_DROP(&ifp->if_snd); 326157354Smjacob IF_DEQUEUE(&ifp->if_snd, m); 327157354Smjacob splx(s); 328157354Smjacob 329157354Smjacob if (m == NULL) 330157354Smjacob return; 331147883Sscottl else 332147883Sscottl m_freem(m); 333147883Sscottl } 334147883Sscottl#endif 335147883Sscottl} 336147883Sscottl 337147883Sscottlint 338147883Sscottlpfsync_insert_net_state(struct pfsync_state *sp) 339220945Smarius{ 340157662Smjacob struct pf_state *st = NULL; 341147883Sscottl struct pf_rule *r = NULL; 342147883Sscottl struct pfi_kif *kif; 343147883Sscottl 344147883Sscottl#ifdef __FreeBSD__ 345147883Sscottl PF_ASSERT(MA_OWNED); 346159312Smjacob#endif 347155521Smjacob if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 348169293Smjacob printf("pfsync_insert_net_state: invalid creator id:" 349147883Sscottl " %08x\n", ntohl(sp->creatorid)); 350147883Sscottl return (EINVAL); 351170252Sscottl } 352170252Sscottl 353170252Sscottl kif = pfi_lookup_create(sp->ifname); 354170252Sscottl if (kif == NULL) { 355170252Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 356170252Sscottl printf("pfsync_insert_net_state: " 357170252Sscottl "unknown interface: %s\n", sp->ifname); 358170252Sscottl /* skip this state */ 359170252Sscottl return (0); 360170252Sscottl } 361170252Sscottl 362157117Smjacob /* 363157117Smjacob * Just use the default rule until we have infrastructure to find the 364157117Smjacob * best matching rule. 365157117Smjacob */ 366157117Smjacob r = &pf_default_rule; 367157117Smjacob 368157117Smjacob if (!r->max_states || r->states < r->max_states) 369157117Smjacob st = pool_get(&pf_state_pl, PR_NOWAIT); 370160391Smjacob if (st == NULL) { 371160391Smjacob pfi_maybe_destroy(kif); 372160391Smjacob return (ENOMEM); 373157354Smjacob } 374157117Smjacob bzero(st, sizeof(*st)); 375157117Smjacob 376157354Smjacob st->rule.ptr = r; 377157117Smjacob /* XXX get pointers to nat_rule and anchor */ 378157117Smjacob 379157117Smjacob /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 380157117Smjacob r->states++; 381157117Smjacob 382157117Smjacob /* fill in the rest of the state entry */ 383157117Smjacob pf_state_host_ntoh(&sp->lan, &st->lan); 384157117Smjacob pf_state_host_ntoh(&sp->gwy, &st->gwy); 385157117Smjacob pf_state_host_ntoh(&sp->ext, &st->ext); 386157117Smjacob 387157117Smjacob pf_state_peer_ntoh(&sp->src, &st->src); 388157117Smjacob pf_state_peer_ntoh(&sp->dst, &st->dst); 389157117Smjacob 390157117Smjacob bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 391157117Smjacob st->creation = time_second - ntohl(sp->creation); 392157117Smjacob st->expire = ntohl(sp->expire) + time_second; 393157117Smjacob 394157117Smjacob st->af = sp->af; 395157117Smjacob st->proto = sp->proto; 396157117Smjacob st->direction = sp->direction; 397157354Smjacob st->log = sp->log; 398157117Smjacob st->timeout = sp->timeout; 399157117Smjacob st->allow_opts = sp->allow_opts; 400157117Smjacob 401157117Smjacob bcopy(sp->id, &st->id, sizeof(st->id)); 402157354Smjacob st->creatorid = sp->creatorid; 403157117Smjacob st->sync_flags = PFSTATE_FROMSYNC; 404157117Smjacob 405157117Smjacob 406157117Smjacob if (pf_insert_state(kif, st)) { 407157117Smjacob pfi_maybe_destroy(kif); 408157117Smjacob /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 409157117Smjacob r->states--; 410157117Smjacob pool_put(&pf_state_pl, st); 411157117Smjacob return (EINVAL); 412157117Smjacob } 413157117Smjacob 414157117Smjacob return (0); 415157662Smjacob} 416157117Smjacob 417147883Sscottlvoid 418101704Smjacob#ifdef __FreeBSD__ 419147883Sscottlpfsync_input(struct mbuf *m, __unused int off) 420147883Sscottl#else 421147883Sscottlpfsync_input(struct mbuf *m, ...) 422147883Sscottl#endif 423147883Sscottl{ 424147883Sscottl struct ip *ip = mtod(m, struct ip *); 425147883Sscottl struct pfsync_header *ph; 426147883Sscottl#ifdef __FreeBSD__ 427147883Sscottl struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 428147883Sscottl#else 429147883Sscottl struct pfsync_softc *sc = &pfsyncif; 430147883Sscottl#endif 431147883Sscottl struct pf_state *st, key; 432147883Sscottl struct pfsync_state *sp; 433147883Sscottl struct pfsync_state_upd *up; 434147883Sscottl struct pfsync_state_del *dp; 435147883Sscottl struct pfsync_state_clr *cp; 436147883Sscottl struct pfsync_state_upd_req *rup; 437101704Smjacob struct pfsync_state_bus *bus; 438157117Smjacob struct in_addr src; 439147883Sscottl struct mbuf *mp; 440147883Sscottl int iplen, action, error, i, s, count, offp, sfail, stale = 0; 441147883Sscottl 442147883Sscottl pfsyncstats.pfsyncs_ipackets++; 443157117Smjacob 444147883Sscottl /* verify that we have a sync interface configured */ 445147883Sscottl if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */ 446147883Sscottl goto done; 447101704Smjacob 448147883Sscottl /* verify that the packet came in on the right interface */ 449147883Sscottl if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 450147883Sscottl pfsyncstats.pfsyncs_badif++; 451147883Sscottl goto done; 452147883Sscottl } 453147883Sscottl 454101704Smjacob /* verify that the IP TTL is 255. */ 455147883Sscottl if (ip->ip_ttl != PFSYNC_DFLTTL) { 456147883Sscottl pfsyncstats.pfsyncs_badttl++; 457147883Sscottl goto done; 458147883Sscottl } 459101704Smjacob 460101704Smjacob iplen = ip->ip_hl << 2; 461147883Sscottl 462147883Sscottl if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 463147883Sscottl pfsyncstats.pfsyncs_hdrops++; 464147883Sscottl goto done; 465147883Sscottl } 466147883Sscottl 467147883Sscottl if (iplen + sizeof(*ph) > m->m_len) { 468147883Sscottl if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 469147883Sscottl pfsyncstats.pfsyncs_hdrops++; 470147883Sscottl goto done; 471147883Sscottl } 472147883Sscottl ip = mtod(m, struct ip *); 473147883Sscottl } 474147883Sscottl ph = (struct pfsync_header *)((char *)ip + iplen); 475147883Sscottl 476147883Sscottl /* verify the version */ 477147883Sscottl if (ph->version != PFSYNC_VERSION) { 478147883Sscottl pfsyncstats.pfsyncs_badver++; 479147883Sscottl goto done; 480147883Sscottl } 481147883Sscottl 482147883Sscottl action = ph->action; 483147883Sscottl count = ph->count; 484147883Sscottl 485147883Sscottl /* make sure it's a valid action code */ 486147883Sscottl if (action >= PFSYNC_ACT_MAX) { 487147883Sscottl pfsyncstats.pfsyncs_badact++; 488147883Sscottl goto done; 489147883Sscottl } 490147883Sscottl 491101704Smjacob /* Cheaper to grab this now than having to mess with mbufs later */ 492101704Smjacob src = ip->ip_src; 493147883Sscottl 494147883Sscottl switch (action) { 495147883Sscottl case PFSYNC_ACT_CLR: { 496147883Sscottl struct pf_state *nexts; 497147883Sscottl struct pfi_kif *kif; 498147883Sscottl u_int32_t creatorid; 499147883Sscottl if ((mp = m_pulldown(m, iplen + sizeof(*ph), 500147883Sscottl sizeof(*cp), &offp)) == NULL) { 501101704Smjacob pfsyncstats.pfsyncs_badlen++; 502147883Sscottl return; 503147883Sscottl } 504147883Sscottl cp = (struct pfsync_state_clr *)(mp->m_data + offp); 505147883Sscottl creatorid = cp->creatorid; 506158933Smjacob 507101704Smjacob s = splsoftnet(); 508101704Smjacob#ifdef __FreeBSD__ 509147883Sscottl PF_LOCK(); 510147883Sscottl#endif 511147883Sscottl if (cp->ifname[0] == '\0') { 512147883Sscottl for (st = RB_MIN(pf_state_tree_id, &tree_id); 513147883Sscottl st; st = nexts) { 514147883Sscottl nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 515147883Sscottl if (st->creatorid == creatorid) { 516147883Sscottl st->timeout = PFTM_PURGE; 517147883Sscottl pf_purge_expired_state(st); 518147883Sscottl } 519147883Sscottl } 520147883Sscottl } else { 521147883Sscottl kif = pfi_lookup_if(cp->ifname); 522147883Sscottl if (kif == NULL) { 523147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 524147883Sscottl printf("pfsync_input: PFSYNC_ACT_CLR " 525101704Smjacob "bad interface: %s\n", cp->ifname); 526101704Smjacob splx(s); 527147883Sscottl#ifdef __FreeBSD__ 528147883Sscottl PF_UNLOCK(); 529147883Sscottl#endif 530147883Sscottl goto done; 531147883Sscottl } 532101704Smjacob for (st = RB_MIN(pf_state_tree_lan_ext, 533147883Sscottl &kif->pfik_lan_ext); st; st = nexts) { 534101704Smjacob nexts = RB_NEXT(pf_state_tree_lan_ext, 535170252Sscottl &kif->pfik_lan_ext, st); 536170252Sscottl if (st->creatorid == creatorid) { 537170252Sscottl st->timeout = PFTM_PURGE; 538170252Sscottl pf_purge_expired_state(st); 539170252Sscottl } 540170252Sscottl } 541170252Sscottl } 542170252Sscottl#ifdef __FreeBSD__ 543170252Sscottl PF_UNLOCK(); 544170252Sscottl#endif 545170252Sscottl splx(s); 546170252Sscottl 547170252Sscottl break; 548170252Sscottl } 549170252Sscottl case PFSYNC_ACT_INS: 550170252Sscottl if ((mp = m_pulldown(m, iplen + sizeof(*ph), 551170252Sscottl count * sizeof(*sp), &offp)) == NULL) { 552170252Sscottl pfsyncstats.pfsyncs_badlen++; 553170252Sscottl return; 554170252Sscottl } 555170252Sscottl 556170252Sscottl s = splsoftnet(); 557170252Sscottl#ifdef __FreeBSD__ 558170252Sscottl PF_LOCK(); 559170252Sscottl#endif 560170252Sscottl for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 561170252Sscottl i < count; i++, sp++) { 562170252Sscottl /* check for invalid values */ 563170252Sscottl if (sp->timeout >= PFTM_MAX || 564170252Sscottl sp->src.state > PF_TCPS_PROXY_DST || 565147883Sscottl sp->dst.state > PF_TCPS_PROXY_DST || 566147883Sscottl sp->direction > PF_OUT || 567147883Sscottl (sp->af != AF_INET && sp->af != AF_INET6)) { 568157662Smjacob if (pf_status.debug >= PF_DEBUG_MISC) 569147883Sscottl printf("pfsync_insert: PFSYNC_ACT_INS: " 570160290Smjacob "invalid value\n"); 571231518Smarius pfsyncstats.pfsyncs_badstate++; 572157117Smjacob continue; 573165814Smjacob } 574164990Smjacob 575164416Smjacob if ((error = pfsync_insert_net_state(sp))) { 576157117Smjacob if (error == ENOMEM) { 577157117Smjacob splx(s); 578160290Smjacob#ifdef __FreeBSD__ 579158982Smjacob PF_UNLOCK(); 580147883Sscottl#endif 581147883Sscottl goto done; 582147883Sscottl } 583147883Sscottl continue; 584147883Sscottl } 585147883Sscottl } 586159178Smjacob#ifdef __FreeBSD__ 587157117Smjacob PF_UNLOCK(); 588231518Smarius#endif 589231518Smarius splx(s); 590101704Smjacob break; 591160290Smjacob case PFSYNC_ACT_UPD: 592160290Smjacob if ((mp = m_pulldown(m, iplen + sizeof(*ph), 593160290Smjacob count * sizeof(*sp), &offp)) == NULL) { 594147883Sscottl pfsyncstats.pfsyncs_badlen++; 595165814Smjacob return; 596165814Smjacob } 597165814Smjacob 598101704Smjacob s = splsoftnet(); 599147883Sscottl#ifdef __FreeBSD__ 600147883Sscottl PF_LOCK(); 601147883Sscottl#endif 602164990Smjacob for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 603101704Smjacob i < count; i++, sp++) { 604147883Sscottl int flags = PFSYNC_FLAG_STALE; 605147883Sscottl 606147883Sscottl /* check for invalid values */ 607164990Smjacob if (sp->timeout >= PFTM_MAX || 608164990Smjacob sp->src.state > PF_TCPS_PROXY_DST || 609102822Smjacob sp->dst.state > PF_TCPS_PROXY_DST) { 610147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 611147883Sscottl printf("pfsync_insert: PFSYNC_ACT_UPD: " 612147883Sscottl "invalid value\n"); 613147883Sscottl pfsyncstats.pfsyncs_badstate++; 614147883Sscottl continue; 615147883Sscottl } 616147883Sscottl 617147883Sscottl bcopy(sp->id, &key.id, sizeof(key.id)); 618147883Sscottl key.creatorid = sp->creatorid; 619147883Sscottl 620207287Smarius st = pf_find_state_byid(&key); 621147883Sscottl if (st == NULL) { 622147883Sscottl /* insert the update */ 623147883Sscottl if (pfsync_insert_net_state(sp)) 624147883Sscottl pfsyncstats.pfsyncs_badstate++; 625147883Sscottl continue; 626147883Sscottl } 627147883Sscottl sfail = 0; 628147883Sscottl if (st->proto == IPPROTO_TCP) { 629207287Smarius /* 630147883Sscottl * The state should never go backwards except 631147883Sscottl * for syn-proxy states. Neither should the 632147883Sscottl * sequence window slide backwards. 633157117Smjacob */ 634159919Smjacob if (st->src.state > sp->src.state && 635157117Smjacob (st->src.state < PF_TCPS_PROXY_SRC || 636159919Smjacob sp->src.state >= PF_TCPS_PROXY_SRC)) 637147883Sscottl sfail = 1; 638147883Sscottl else if (SEQ_GT(st->src.seqlo, 639160397Smjacob ntohl(sp->src.seqlo))) 640160397Smjacob sfail = 3; 641160397Smjacob else if (st->dst.state > sp->dst.state) { 642160397Smjacob /* There might still be useful 643160397Smjacob * information about the src state here, 644160397Smjacob * so import that part of the update, 645160397Smjacob * then "fail" so we send the updated 646160397Smjacob * state back to the peer who is missing 647160397Smjacob * our what we know. */ 648160397Smjacob pf_state_peer_ntoh(&sp->src, &st->src); 649160397Smjacob /* XXX do anything with timeouts? */ 650160397Smjacob sfail = 7; 651147883Sscottl flags = 0; 652158982Smjacob } else if (st->dst.state >= TCPS_SYN_SENT && 653147883Sscottl SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo))) 654147883Sscottl sfail = 4; 655147883Sscottl } else { 656147883Sscottl /* 657147883Sscottl * Non-TCP protocol state machine always go 658147883Sscottl * forwards 659147883Sscottl */ 660147883Sscottl if (st->src.state > sp->src.state) 661147883Sscottl sfail = 5; 662147883Sscottl else if ( st->dst.state > sp->dst.state) 663147883Sscottl sfail = 6; 664147883Sscottl } 665147883Sscottl if (sfail) { 666147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 667152444Skan printf("pfsync: %s stale update " 668147883Sscottl "(%d) id: %016llx " 669147883Sscottl "creatorid: %08x\n", 670147883Sscottl (sfail < 7 ? "ignoring" 671147883Sscottl : "partial"), sfail, 672147883Sscottl#ifdef __FreeBSD__ 673147883Sscottl (unsigned long long)be64toh(st->id), 674164305Sjhb#else 675147883Sscottl betoh64(st->id), 676220945Smarius#endif 677233403Smarius ntohl(st->creatorid)); 678147883Sscottl pfsyncstats.pfsyncs_badstate++; 679233403Smarius 680147883Sscottl if (!(sp->sync_flags & PFSTATE_STALE)) { 681147883Sscottl /* we have a better state, send it */ 682147883Sscottl if (sc->sc_mbuf != NULL && !stale) 683147883Sscottl pfsync_sendout(sc); 684147883Sscottl stale++; 685147883Sscottl if (!st->sync_flags) 686147883Sscottl pfsync_pack_state( 687147883Sscottl PFSYNC_ACT_UPD, st, flags); 688147883Sscottl } 689147883Sscottl continue; 690147883Sscottl } 691147883Sscottl pf_state_peer_ntoh(&sp->src, &st->src); 692147883Sscottl pf_state_peer_ntoh(&sp->dst, &st->dst); 693147883Sscottl st->expire = ntohl(sp->expire) + time_second; 694147883Sscottl st->timeout = sp->timeout; 695147883Sscottl } 696147883Sscottl if (stale && sc->sc_mbuf != NULL) 697147883Sscottl pfsync_sendout(sc); 698147883Sscottl#ifdef __FreeBSD__ 699147883Sscottl PF_UNLOCK(); 700147883Sscottl#endif 701147883Sscottl splx(s); 702157117Smjacob break; 703147883Sscottl /* 704155521Smjacob * It's not strictly necessary for us to support the "uncompressed" 705209599Sken * delete action, but it's relatively simple and maintains consistency. 706155521Smjacob */ 707155521Smjacob case PFSYNC_ACT_DEL: 708155521Smjacob if ((mp = m_pulldown(m, iplen + sizeof(*ph), 709155521Smjacob count * sizeof(*sp), &offp)) == NULL) { 710147883Sscottl pfsyncstats.pfsyncs_badlen++; 711147883Sscottl return; 712147883Sscottl } 713147883Sscottl 714147883Sscottl s = splsoftnet(); 715147883Sscottl#ifdef __FreeBSD__ 716147883Sscottl PF_LOCK(); 717147883Sscottl#endif 718147883Sscottl for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 719147883Sscottl i < count; i++, sp++) { 720147883Sscottl bcopy(sp->id, &key.id, sizeof(key.id)); 721147883Sscottl key.creatorid = sp->creatorid; 722147883Sscottl 723147883Sscottl st = pf_find_state_byid(&key); 724147883Sscottl if (st == NULL) { 725147883Sscottl pfsyncstats.pfsyncs_badstate++; 726147883Sscottl continue; 727147883Sscottl } 728147883Sscottl st->timeout = PFTM_PURGE; 729147883Sscottl st->sync_flags |= PFSTATE_FROMSYNC; 730157117Smjacob pf_purge_expired_state(st); 731157354Smjacob } 732157354Smjacob#ifdef __FreeBSD__ 733157354Smjacob PF_UNLOCK(); 734159312Smjacob#endif 735157354Smjacob splx(s); 736157117Smjacob break; 737157117Smjacob case PFSYNC_ACT_UPD_C: { 738157117Smjacob int update_requested = 0; 739157117Smjacob 740157662Smjacob if ((mp = m_pulldown(m, iplen + sizeof(*ph), 741147883Sscottl count * sizeof(*up), &offp)) == NULL) { 742157117Smjacob pfsyncstats.pfsyncs_badlen++; 743157117Smjacob return; 744157117Smjacob } 745157117Smjacob 746157117Smjacob s = splsoftnet(); 747160391Smjacob#ifdef __FreeBSD__ 748157117Smjacob PF_LOCK(); 749157117Smjacob#endif 750157662Smjacob for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 751157117Smjacob i < count; i++, up++) { 752157117Smjacob /* check for invalid values */ 753157117Smjacob if (up->timeout >= PFTM_MAX || 754157662Smjacob up->src.state > PF_TCPS_PROXY_DST || 755157662Smjacob up->dst.state > PF_TCPS_PROXY_DST) { 756157117Smjacob if (pf_status.debug >= PF_DEBUG_MISC) 757157117Smjacob printf("pfsync_insert: " 758159312Smjacob "PFSYNC_ACT_UPD_C: " 759147883Sscottl "invalid value\n"); 760147883Sscottl pfsyncstats.pfsyncs_badstate++; 761147883Sscottl continue; 762147883Sscottl } 763147883Sscottl 764147883Sscottl bcopy(up->id, &key.id, sizeof(key.id)); 765147883Sscottl key.creatorid = up->creatorid; 766159178Smjacob 767147883Sscottl st = pf_find_state_byid(&key); 768170252Sscottl if (st == NULL) { 769170252Sscottl /* We don't have this state. Ask for it. */ 770170252Sscottl error = pfsync_request_update(up, &src); 771147883Sscottl if (error == ENOMEM) { 772147883Sscottl splx(s); 773147883Sscottl goto done; 774178814Sjhb } 775178814Sjhb update_requested = 1; 776178814Sjhb pfsyncstats.pfsyncs_badstate++; 777147883Sscottl continue; 778147883Sscottl } 779147883Sscottl sfail = 0; 780157662Smjacob if (st->proto == IPPROTO_TCP) { 781157662Smjacob /* 782157662Smjacob * The state should never go backwards except 783157662Smjacob * for syn-proxy states. Neither should the 784157662Smjacob * sequence window slide backwards. 785157662Smjacob */ 786157662Smjacob if (st->src.state > up->src.state && 787157662Smjacob (st->src.state < PF_TCPS_PROXY_SRC || 788157662Smjacob up->src.state >= PF_TCPS_PROXY_SRC)) 789157662Smjacob sfail = 1; 790157117Smjacob else if (st->dst.state > up->dst.state) 791147883Sscottl sfail = 2; 792147883Sscottl else if (SEQ_GT(st->src.seqlo, 793147883Sscottl ntohl(up->src.seqlo))) 794147883Sscottl sfail = 3; 795147883Sscottl else if (st->dst.state >= TCPS_SYN_SENT && 796147883Sscottl SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo))) 797147883Sscottl sfail = 4; 798147883Sscottl } else { 799147883Sscottl /* 800147883Sscottl * Non-TCP protocol state machine always go 801147883Sscottl * forwards 802147883Sscottl */ 803157662Smjacob if (st->src.state > up->src.state) 804169293Smjacob sfail = 5; 805147883Sscottl else if (st->dst.state > up->dst.state) 806147883Sscottl sfail = 6; 807169293Smjacob } 808198262Skan if (sfail) { 809169293Smjacob if (pf_status.debug >= PF_DEBUG_MISC) 810169293Smjacob printf("pfsync: ignoring stale update " 811198262Skan "(%d) id: %016llx " 812198262Skan "creatorid: %08x\n", sfail, 813198262Skan#ifdef __FreeBSD__ 814198262Skan (unsigned long long)be64toh(st->id), 815157662Smjacob#else 816147883Sscottl betoh64(st->id), 817147883Sscottl#endif 818147883Sscottl ntohl(st->creatorid)); 819147883Sscottl pfsyncstats.pfsyncs_badstate++; 820147883Sscottl 821147883Sscottl /* we have a better state, send it out */ 822147883Sscottl if ((!stale || update_requested) && 823147883Sscottl sc->sc_mbuf != NULL) { 824147883Sscottl pfsync_sendout(sc); 825147883Sscottl update_requested = 0; 826147883Sscottl } 827147883Sscottl stale++; 828147883Sscottl if (!st->sync_flags) 829147883Sscottl pfsync_pack_state(PFSYNC_ACT_UPD, st, 830147883Sscottl PFSYNC_FLAG_STALE); 831147883Sscottl continue; 832147883Sscottl } 833147883Sscottl pf_state_peer_ntoh(&up->src, &st->src); 834147883Sscottl pf_state_peer_ntoh(&up->dst, &st->dst); 835147883Sscottl st->expire = ntohl(up->expire) + time_second; 836147883Sscottl st->timeout = up->timeout; 837147883Sscottl } 838147883Sscottl if ((update_requested || stale) && sc->sc_mbuf) 839147883Sscottl pfsync_sendout(sc); 840147883Sscottl#ifdef __FreeBSD__ 841147883Sscottl PF_UNLOCK(); 842231518Smarius#endif 843147883Sscottl splx(s); 844147883Sscottl break; 845147883Sscottl } 846147883Sscottl case PFSYNC_ACT_DEL_C: 847147883Sscottl if ((mp = m_pulldown(m, iplen + sizeof(*ph), 848147883Sscottl count * sizeof(*dp), &offp)) == NULL) { 849231518Smarius pfsyncstats.pfsyncs_badlen++; 850147883Sscottl return; 851147883Sscottl } 852147883Sscottl 853147883Sscottl s = splsoftnet(); 854155521Smjacob#ifdef __FreeBSD__ 855147883Sscottl PF_LOCK(); 856157117Smjacob#endif 857157117Smjacob for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 858157117Smjacob i < count; i++, dp++) { 859155521Smjacob bcopy(dp->id, &key.id, sizeof(key.id)); 860155521Smjacob key.creatorid = dp->creatorid; 861155521Smjacob 862147883Sscottl st = pf_find_state_byid(&key); 863147883Sscottl if (st == NULL) { 864157354Smjacob pfsyncstats.pfsyncs_badstate++; 865157117Smjacob continue; 866147883Sscottl } 867147883Sscottl st->timeout = PFTM_PURGE; 868147883Sscottl st->sync_flags |= PFSTATE_FROMSYNC; 869157354Smjacob pf_purge_expired_state(st); 870157117Smjacob } 871147883Sscottl#ifdef __FreeBSD__ 872147883Sscottl PF_UNLOCK(); 873147883Sscottl#endif 874147883Sscottl splx(s); 875147883Sscottl break; 876147883Sscottl case PFSYNC_ACT_INS_F: 877147883Sscottl case PFSYNC_ACT_DEL_F: 878147883Sscottl /* not implemented */ 879147883Sscottl break; 880147883Sscottl case PFSYNC_ACT_UREQ: 881147883Sscottl if ((mp = m_pulldown(m, iplen + sizeof(*ph), 882147883Sscottl count * sizeof(*rup), &offp)) == NULL) { 883147883Sscottl pfsyncstats.pfsyncs_badlen++; 884147883Sscottl return; 885158982Smjacob } 886147883Sscottl 887147883Sscottl s = splsoftnet(); 888147883Sscottl#ifdef __FreeBSD__ 889147883Sscottl PF_LOCK(); 890147883Sscottl#endif 891147883Sscottl if (sc->sc_mbuf != NULL) 892147883Sscottl pfsync_sendout(sc); 893147883Sscottl for (i = 0, 894147883Sscottl rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 895147883Sscottl i < count; i++, rup++) { 896147883Sscottl bcopy(rup->id, &key.id, sizeof(key.id)); 897147883Sscottl key.creatorid = rup->creatorid; 898147883Sscottl 899147883Sscottl if (key.id == 0 && key.creatorid == 0) { 900147883Sscottl sc->sc_ureq_received = time_uptime; 901147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 902147883Sscottl printf("pfsync: received " 903147883Sscottl "bulk update request\n"); 904147883Sscottl pfsync_send_bus(sc, PFSYNC_BUS_START); 905147883Sscottl#ifdef __FreeBSD__ 906147883Sscottl callout_reset(&sc->sc_bulk_tmo, 1 * hz, 907147883Sscottl pfsync_bulk_update, 908147883Sscottl LIST_FIRST(&pfsync_list)); 909157354Smjacob#else 910157354Smjacob timeout_add(&sc->sc_bulk_tmo, 1 * hz); 911157354Smjacob#endif 912220945Smarius } else { 913155521Smjacob st = pf_find_state_byid(&key); 914164990Smjacob if (st == NULL) { 915155521Smjacob pfsyncstats.pfsyncs_badstate++; 916155521Smjacob continue; 917155521Smjacob } 918155521Smjacob if (!st->sync_flags) 919155521Smjacob pfsync_pack_state(PFSYNC_ACT_UPD, 920155521Smjacob st, 0); 921155521Smjacob } 922147883Sscottl } 923155521Smjacob if (sc->sc_mbuf != NULL) 924155521Smjacob pfsync_sendout(sc); 925155521Smjacob#ifdef __FreeBSD__ 926155521Smjacob PF_UNLOCK(); 927155521Smjacob#endif 928147883Sscottl splx(s); 929155521Smjacob break; 930155521Smjacob case PFSYNC_ACT_BUS: 931155521Smjacob /* If we're not waiting for a bulk update, who cares. */ 932147883Sscottl if (sc->sc_ureq_sent == 0) 933147883Sscottl break; 934147883Sscottl 935147883Sscottl if ((mp = m_pulldown(m, iplen + sizeof(*ph), 936157117Smjacob sizeof(*bus), &offp)) == NULL) { 937160290Smjacob pfsyncstats.pfsyncs_badlen++; 938158933Smjacob return; 939158933Smjacob } 940147883Sscottl bus = (struct pfsync_state_bus *)(mp->m_data + offp); 941147883Sscottl switch (bus->status) { 942147883Sscottl case PFSYNC_BUS_START: 943147883Sscottl#ifdef __FreeBSD__ 944147883Sscottl callout_reset(&sc->sc_bulkfail_tmo, 945147883Sscottl pf_pool_limits[PF_LIMIT_STATES].limit / 946159049Smjacob (PFSYNC_BULKPACKETS * sc->sc_maxcount), 947147883Sscottl pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 948157117Smjacob#else 949157117Smjacob timeout_add(&sc->sc_bulkfail_tmo, 950157117Smjacob pf_pool_limits[PF_LIMIT_STATES].limit / 951155521Smjacob (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 952155521Smjacob#endif 953147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 954147883Sscottl printf("pfsync: received bulk " 955147883Sscottl "update start\n"); 956147883Sscottl break; 957147883Sscottl case PFSYNC_BUS_END: 958147883Sscottl if (time_uptime - ntohl(bus->endtime) >= 959147883Sscottl sc->sc_ureq_sent) { 960147883Sscottl /* that's it, we're happy */ 961224493Smarius sc->sc_ureq_sent = 0; 962215325Smarius sc->sc_bulk_tries = 0; 963215325Smarius#ifdef __FreeBSD__ 964215325Smarius callout_stop(&sc->sc_bulkfail_tmo); 965215325Smarius#else 966147883Sscottl timeout_del(&sc->sc_bulkfail_tmo); 967224493Smarius#endif 968241874Smarius#if NCARP > 0 /* XXX_IMPORT */ 969157117Smjacob if (!pfsync_sync_ok) 970157117Smjacob carp_suppress_preempt--; 971157117Smjacob#endif 972157117Smjacob pfsync_sync_ok = 1; 973147883Sscottl if (pf_status.debug >= PF_DEBUG_MISC) 974157117Smjacob printf("pfsync: received valid " 975157117Smjacob "bulk update end\n"); 976157117Smjacob } else { 977157117Smjacob if (pf_status.debug >= PF_DEBUG_MISC) 978157117Smjacob printf("pfsync: received invalid " 979157117Smjacob "bulk update end: bad timestamp\n"); 980157117Smjacob } 981157117Smjacob break; 982157117Smjacob } 983157117Smjacob break; 984157117Smjacob } 985157117Smjacob 986157117Smjacobdone: 987157117Smjacob if (m) 988157117Smjacob m_freem(m); 989157117Smjacob} 990157117Smjacob 991157117Smjacobint 992157117Smjacobpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 993157117Smjacob struct rtentry *rt) 994157117Smjacob{ 995157117Smjacob m_freem(m); 996157117Smjacob return (0); 997157354Smjacob} 998231228Smarius 999157117Smjacob/* ARGSUSED */ 1000157117Smjacobint 1001157117Smjacobpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1002157117Smjacob{ 1003213147Smarius#ifndef __FreeBSD__ 1004157662Smjacob struct proc *p = curproc; 1005157662Smjacob#endif 1006157662Smjacob struct pfsync_softc *sc = ifp->if_softc; 1007157662Smjacob struct ifreq *ifr = (struct ifreq *)data; 1008157662Smjacob struct ip_moptions *imo = &sc->sc_imo; 1009157662Smjacob struct pfsyncreq pfsyncr; 1010157662Smjacob struct ifnet *sifp; 1011157662Smjacob int s, error; 1012157662Smjacob 1013157662Smjacob switch (cmd) { 1014157662Smjacob case SIOCSIFADDR: 1015157662Smjacob case SIOCAIFADDR: 1016157662Smjacob case SIOCSIFDSTADDR: 1017157662Smjacob case SIOCSIFFLAGS: 1018157662Smjacob#ifdef __FreeBSD__ 1019157662Smjacob if (ifp->if_flags & IFF_UP) 1020157662Smjacob ifp->if_drv_flags |= IFF_DRV_RUNNING; 1021157662Smjacob else 1022157662Smjacob ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1023157662Smjacob#else 1024157662Smjacob if (ifp->if_flags & IFF_UP) 1025157662Smjacob ifp->if_flags |= IFF_RUNNING; 1026157662Smjacob else 1027157662Smjacob ifp->if_flags &= ~IFF_RUNNING; 1028157662Smjacob#endif 1029157662Smjacob break; 1030157662Smjacob case SIOCSIFMTU: 1031157662Smjacob if (ifr->ifr_mtu < PFSYNC_MINMTU) 1032157662Smjacob return (EINVAL); 1033157662Smjacob if (ifr->ifr_mtu > MCLBYTES) 1034157662Smjacob ifr->ifr_mtu = MCLBYTES; 1035157662Smjacob s = splnet(); 1036157662Smjacob#ifdef __FreeBSD__ 1037157662Smjacob PF_LOCK(); 1038157662Smjacob#endif 1039157662Smjacob if (ifr->ifr_mtu < ifp->if_mtu) { 1040157662Smjacob pfsync_sendout(sc); 1041157662Smjacob } 1042213147Smarius pfsync_setmtu(sc, ifr->ifr_mtu); 1043213147Smarius#ifdef __FreeBSD__ 1044213147Smarius PF_UNLOCK(); 1045213147Smarius#endif 1046213147Smarius splx(s); 1047213147Smarius break; 1048157662Smjacob case SIOCGETPFSYNC: 1049157662Smjacob#ifdef __FreeBSD__ 1050157662Smjacob /* XXX: read unlocked */ 1051157662Smjacob#endif 1052157662Smjacob bzero(&pfsyncr, sizeof(pfsyncr)); 1053157662Smjacob if (sc->sc_sync_ifp) 1054157662Smjacob strlcpy(pfsyncr.pfsyncr_syncdev, 1055157662Smjacob sc->sc_sync_ifp->if_xname, IFNAMSIZ); 1056157662Smjacob pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1057157662Smjacob pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1058157662Smjacob if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 1059157662Smjacob return (error); 1060157662Smjacob break; 1061157662Smjacob case SIOCSETPFSYNC: 1062157662Smjacob#ifdef __FreeBSD__ 1063157662Smjacob if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1064157662Smjacob#else 1065231228Smarius if ((error = suser(p, p->p_acflag)) != 0) 1066157662Smjacob#endif 1067157662Smjacob return (error); 1068157662Smjacob if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1069157662Smjacob return (error); 1070157662Smjacob 1071157662Smjacob if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1072157662Smjacob#ifdef __FreeBSD__ 1073157662Smjacob sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1074157662Smjacob#else 1075157662Smjacob sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1076157662Smjacob#endif 1077157662Smjacob else 1078157662Smjacob sc->sc_sync_peer.s_addr = 1079231228Smarius pfsyncr.pfsyncr_syncpeer.s_addr; 1080157662Smjacob 1081157662Smjacob if (pfsyncr.pfsyncr_maxupdates > 255) 1082157662Smjacob return (EINVAL); 1083157662Smjacob#ifdef __FreeBSD__ 1084157662Smjacob callout_drain(&sc->sc_send_tmo); 1085231228Smarius PF_LOCK(); 1086157662Smjacob#endif 1087157662Smjacob sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1088157662Smjacob 1089157662Smjacob if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1090157117Smjacob sc->sc_sync_ifp = NULL; 1091147883Sscottl if (sc->sc_mbuf_net != NULL) { 1092160391Smjacob /* Don't keep stale pfsync packets around. */ 1093160391Smjacob s = splnet(); 1094160391Smjacob m_freem(sc->sc_mbuf_net); 1095157117Smjacob sc->sc_mbuf_net = NULL; 1096157117Smjacob sc->sc_statep_net.s = NULL; 1097157117Smjacob splx(s); 1098157117Smjacob } 1099157117Smjacob if (imo->imo_num_memberships > 0) { 1100157117Smjacob in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1101157117Smjacob imo->imo_multicast_ifp = NULL; 1102157117Smjacob } 1103157117Smjacob#ifdef __FreeBSD__ 1104147883Sscottl PF_UNLOCK(); 1105147883Sscottl#endif 1106147883Sscottl break; 1107147883Sscottl } 1108147883Sscottl 1109147883Sscottl if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) { 1110147883Sscottl#ifdef __FreeBSD__ 1111147883Sscottl PF_UNLOCK(); 1112147883Sscottl#endif 1113147883Sscottl return (EINVAL); 1114147883Sscottl } 1115147883Sscottl 1116147883Sscottl s = splnet(); 1117147883Sscottl#ifdef __FreeBSD__ 1118147883Sscottl if (sifp->if_mtu < SCP2IFP(sc)->if_mtu || 1119147883Sscottl#else 1120147883Sscottl if (sifp->if_mtu < sc->sc_if.if_mtu || 1121147883Sscottl#endif 1122147883Sscottl (sc->sc_sync_ifp != NULL && 1123147883Sscottl sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 1124147883Sscottl sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1125147883Sscottl pfsync_sendout(sc); 1126170252Sscottl sc->sc_sync_ifp = sifp; 1127147883Sscottl 1128147883Sscottl#ifdef __FreeBSD__ 1129170252Sscottl pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu); 1130170252Sscottl#else 1131170252Sscottl pfsync_setmtu(sc, sc->sc_if.if_mtu); 1132170252Sscottl#endif 1133170252Sscottl 1134170252Sscottl if (imo->imo_num_memberships > 0) { 1135170252Sscottl in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1136170252Sscottl imo->imo_multicast_ifp = NULL; 1137170252Sscottl } 1138170252Sscottl 1139147883Sscottl if (sc->sc_sync_ifp && 1140147883Sscottl#ifdef __FreeBSD__ 1141147883Sscottl sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1142147883Sscottl#else 1143147883Sscottl sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1144147883Sscottl#endif 1145147883Sscottl struct in_addr addr; 1146147883Sscottl 1147147883Sscottl if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) { 1148147883Sscottl sc->sc_sync_ifp = NULL; 1149147883Sscottl#ifdef __FreeBSD__ 1150147883Sscottl PF_UNLOCK(); 1151147883Sscottl#endif 1152147883Sscottl splx(s); 1153147883Sscottl return (EADDRNOTAVAIL); 1154147883Sscottl } 1155147883Sscottl#ifdef __FreeBSD__ 1156147883Sscottl PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */ 1157147883Sscottl addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1158147883Sscottl#else 1159147883Sscottl addr.s_addr = INADDR_PFSYNC_GROUP; 1160147883Sscottl#endif 1161147883Sscottl 1162147883Sscottl if ((imo->imo_membership[0] = 1163147883Sscottl in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 1164147883Sscottl sc->sc_sync_ifp = NULL; 1165147883Sscottl splx(s); 1166147883Sscottl return (ENOBUFS); 1167147883Sscottl } 1168147883Sscottl imo->imo_num_memberships++; 1169147883Sscottl imo->imo_multicast_ifp = sc->sc_sync_ifp; 1170101704Smjacob imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1171101704Smjacob imo->imo_multicast_loop = 0; 1172147883Sscottl#ifdef __FreeBSD__ 1173101704Smjacob PF_LOCK(); 1174147883Sscottl#endif 1175147883Sscottl } 1176101704Smjacob 1177101704Smjacob if (sc->sc_sync_ifp || 1178155521Smjacob#ifdef __FreeBSD__ 1179101704Smjacob sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) { 1180#else 1181 sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) { 1182#endif 1183 /* Request a full state table update. */ 1184 sc->sc_ureq_sent = time_uptime; 1185#if NCARP > 0 1186 if (pfsync_sync_ok) 1187 carp_suppress_preempt++; 1188#endif 1189 pfsync_sync_ok = 0; 1190 if (pf_status.debug >= PF_DEBUG_MISC) 1191 printf("pfsync: requesting bulk update\n"); 1192#ifdef __FreeBSD__ 1193 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 1194 pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 1195#else 1196 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1197#endif 1198 error = pfsync_request_update(NULL, NULL); 1199 if (error == ENOMEM) { 1200#ifdef __FreeBSD__ 1201 PF_UNLOCK(); 1202#endif 1203 splx(s); 1204 return (ENOMEM); 1205 } 1206 pfsync_sendout(sc); 1207 } 1208#ifdef __FreeBSD__ 1209 PF_UNLOCK(); 1210#endif 1211 splx(s); 1212 1213 break; 1214 1215 default: 1216 return (ENOTTY); 1217 } 1218 1219 return (0); 1220} 1221 1222void 1223pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 1224{ 1225 int mtu; 1226 1227 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 1228 mtu = sc->sc_sync_ifp->if_mtu; 1229 else 1230 mtu = mtu_req; 1231 1232 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 1233 sizeof(struct pfsync_state); 1234 if (sc->sc_maxcount > 254) 1235 sc->sc_maxcount = 254; 1236#ifdef __FreeBSD__ 1237 SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) + 1238 sc->sc_maxcount * sizeof(struct pfsync_state); 1239#else 1240 sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 1241 sc->sc_maxcount * sizeof(struct pfsync_state); 1242#endif 1243} 1244 1245struct mbuf * 1246pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 1247{ 1248 struct pfsync_header *h; 1249 struct mbuf *m; 1250 int len; 1251 1252#ifdef __FreeBSD__ 1253 PF_ASSERT(MA_OWNED); 1254#endif 1255 MGETHDR(m, M_DONTWAIT, MT_DATA); 1256 if (m == NULL) { 1257#ifdef __FreeBSD__ 1258 SCP2IFP(sc)->if_oerrors++; 1259#else 1260 sc->sc_if.if_oerrors++; 1261#endif 1262 return (NULL); 1263 } 1264 1265 switch (action) { 1266 case PFSYNC_ACT_CLR: 1267 len = sizeof(struct pfsync_header) + 1268 sizeof(struct pfsync_state_clr); 1269 break; 1270 case PFSYNC_ACT_UPD_C: 1271 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 1272 sizeof(struct pfsync_header); 1273 break; 1274 case PFSYNC_ACT_DEL_C: 1275 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 1276 sizeof(struct pfsync_header); 1277 break; 1278 case PFSYNC_ACT_UREQ: 1279 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 1280 sizeof(struct pfsync_header); 1281 break; 1282 case PFSYNC_ACT_BUS: 1283 len = sizeof(struct pfsync_header) + 1284 sizeof(struct pfsync_state_bus); 1285 break; 1286 default: 1287 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 1288 sizeof(struct pfsync_header); 1289 break; 1290 } 1291 1292 if (len > MHLEN) { 1293 MCLGET(m, M_DONTWAIT); 1294 if ((m->m_flags & M_EXT) == 0) { 1295 m_free(m); 1296#ifdef __FreeBSD__ 1297 SCP2IFP(sc)->if_oerrors++; 1298#else 1299 sc->sc_if.if_oerrors++; 1300#endif 1301 return (NULL); 1302 } 1303 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 1304 } else 1305 MH_ALIGN(m, len); 1306 1307 m->m_pkthdr.rcvif = NULL; 1308 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 1309 h = mtod(m, struct pfsync_header *); 1310 h->version = PFSYNC_VERSION; 1311 h->af = 0; 1312 h->count = 0; 1313 h->action = action; 1314 1315 *sp = (void *)((char *)h + PFSYNC_HDRLEN); 1316#ifdef __FreeBSD__ 1317 callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 1318 LIST_FIRST(&pfsync_list)); 1319#else 1320 timeout_add(&sc->sc_tmo, hz); 1321#endif 1322 return (m); 1323} 1324 1325int 1326pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) 1327{ 1328#ifdef __FreeBSD__ 1329 struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1330#else 1331 struct ifnet *ifp = &pfsyncif.sc_if; 1332#endif 1333 struct pfsync_softc *sc = ifp->if_softc; 1334 struct pfsync_header *h, *h_net; 1335 struct pfsync_state *sp = NULL; 1336 struct pfsync_state_upd *up = NULL; 1337 struct pfsync_state_del *dp = NULL; 1338 struct pf_rule *r; 1339 u_long secs; 1340 int s, ret = 0; 1341 u_int8_t i = 255, newaction = 0; 1342 1343#ifdef __FreeBSD__ 1344 PF_ASSERT(MA_OWNED); 1345#endif 1346 /* 1347 * If a packet falls in the forest and there's nobody around to 1348 * hear, does it make a sound? 1349 */ 1350 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && 1351#ifdef __FreeBSD__ 1352 sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1353#else 1354 sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1355#endif 1356 /* Don't leave any stale pfsync packets hanging around. */ 1357 if (sc->sc_mbuf != NULL) { 1358 m_freem(sc->sc_mbuf); 1359 sc->sc_mbuf = NULL; 1360 sc->sc_statep.s = NULL; 1361 } 1362 return (0); 1363 } 1364 1365 if (action >= PFSYNC_ACT_MAX) 1366 return (EINVAL); 1367 1368 s = splnet(); 1369 if (sc->sc_mbuf == NULL) { 1370 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1371 (void *)&sc->sc_statep.s)) == NULL) { 1372 splx(s); 1373 return (ENOMEM); 1374 } 1375 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1376 } else { 1377 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1378 if (h->action != action) { 1379 pfsync_sendout(sc); 1380 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 1381 (void *)&sc->sc_statep.s)) == NULL) { 1382 splx(s); 1383 return (ENOMEM); 1384 } 1385 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1386 } else { 1387 /* 1388 * If it's an update, look in the packet to see if 1389 * we already have an update for the state. 1390 */ 1391 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 1392 struct pfsync_state *usp = 1393 (void *)((char *)h + PFSYNC_HDRLEN); 1394 1395 for (i = 0; i < h->count; i++) { 1396 if (!memcmp(usp->id, &st->id, 1397 PFSYNC_ID_LEN) && 1398 usp->creatorid == st->creatorid) { 1399 sp = usp; 1400 sp->updates++; 1401 break; 1402 } 1403 usp++; 1404 } 1405 } 1406 } 1407 } 1408 1409 secs = time_second; 1410 1411 st->pfsync_time = time_uptime; 1412 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 1413 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 1414 1415 if (sp == NULL) { 1416 /* not a "duplicate" update */ 1417 i = 255; 1418 sp = sc->sc_statep.s++; 1419 sc->sc_mbuf->m_pkthdr.len = 1420 sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 1421 h->count++; 1422 bzero(sp, sizeof(*sp)); 1423 1424 bcopy(&st->id, sp->id, sizeof(sp->id)); 1425 sp->creatorid = st->creatorid; 1426 1427 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 1428 pf_state_host_hton(&st->lan, &sp->lan); 1429 pf_state_host_hton(&st->gwy, &sp->gwy); 1430 pf_state_host_hton(&st->ext, &sp->ext); 1431 1432 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 1433 1434 sp->creation = htonl(secs - st->creation); 1435 sp->packets[0] = htonl(st->packets[0]); 1436 sp->packets[1] = htonl(st->packets[1]); 1437 sp->bytes[0] = htonl(st->bytes[0]); 1438 sp->bytes[1] = htonl(st->bytes[1]); 1439 if ((r = st->rule.ptr) == NULL) 1440 sp->rule = htonl(-1); 1441 else 1442 sp->rule = htonl(r->nr); 1443 if ((r = st->anchor.ptr) == NULL) 1444 sp->anchor = htonl(-1); 1445 else 1446 sp->anchor = htonl(r->nr); 1447 sp->af = st->af; 1448 sp->proto = st->proto; 1449 sp->direction = st->direction; 1450 sp->log = st->log; 1451 sp->allow_opts = st->allow_opts; 1452 sp->timeout = st->timeout; 1453 1454 if (flags & PFSYNC_FLAG_STALE) 1455 sp->sync_flags |= PFSTATE_STALE; 1456 } 1457 1458 pf_state_peer_hton(&st->src, &sp->src); 1459 pf_state_peer_hton(&st->dst, &sp->dst); 1460 1461 if (st->expire <= secs) 1462 sp->expire = htonl(0); 1463 else 1464 sp->expire = htonl(st->expire - secs); 1465 1466 /* do we need to build "compressed" actions for network transfer? */ 1467 if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { 1468 switch (action) { 1469 case PFSYNC_ACT_UPD: 1470 newaction = PFSYNC_ACT_UPD_C; 1471 break; 1472 case PFSYNC_ACT_DEL: 1473 newaction = PFSYNC_ACT_DEL_C; 1474 break; 1475 default: 1476 /* by default we just send the uncompressed states */ 1477 break; 1478 } 1479 } 1480 1481 if (newaction) { 1482 if (sc->sc_mbuf_net == NULL) { 1483 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 1484 (void *)&sc->sc_statep_net.s)) == NULL) { 1485 splx(s); 1486 return (ENOMEM); 1487 } 1488 } 1489 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 1490 1491 switch (newaction) { 1492 case PFSYNC_ACT_UPD_C: 1493 if (i != 255) { 1494 up = (void *)((char *)h_net + 1495 PFSYNC_HDRLEN + (i * sizeof(*up))); 1496 up->updates++; 1497 } else { 1498 h_net->count++; 1499 sc->sc_mbuf_net->m_pkthdr.len = 1500 sc->sc_mbuf_net->m_len += sizeof(*up); 1501 up = sc->sc_statep_net.u++; 1502 1503 bzero(up, sizeof(*up)); 1504 bcopy(&st->id, up->id, sizeof(up->id)); 1505 up->creatorid = st->creatorid; 1506 } 1507 up->timeout = st->timeout; 1508 up->expire = sp->expire; 1509 up->src = sp->src; 1510 up->dst = sp->dst; 1511 break; 1512 case PFSYNC_ACT_DEL_C: 1513 sc->sc_mbuf_net->m_pkthdr.len = 1514 sc->sc_mbuf_net->m_len += sizeof(*dp); 1515 dp = sc->sc_statep_net.d++; 1516 h_net->count++; 1517 1518 bzero(dp, sizeof(*dp)); 1519 bcopy(&st->id, dp->id, sizeof(dp->id)); 1520 dp->creatorid = st->creatorid; 1521 break; 1522 } 1523 } 1524 1525 if (h->count == sc->sc_maxcount || 1526 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 1527 ret = pfsync_sendout(sc); 1528 1529 splx(s); 1530 return (ret); 1531} 1532 1533/* This must be called in splnet() */ 1534int 1535pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 1536{ 1537#ifdef __FreeBSD__ 1538 struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1539#else 1540 struct ifnet *ifp = &pfsyncif.sc_if; 1541#endif 1542 struct pfsync_header *h; 1543 struct pfsync_softc *sc = ifp->if_softc; 1544 struct pfsync_state_upd_req *rup; 1545 int ret = 0; 1546 1547#ifdef __FreeBSD__ 1548 PF_ASSERT(MA_OWNED); 1549#endif 1550 if (sc->sc_mbuf == NULL) { 1551 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1552 (void *)&sc->sc_statep.s)) == NULL) 1553 return (ENOMEM); 1554 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1555 } else { 1556 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1557 if (h->action != PFSYNC_ACT_UREQ) { 1558 pfsync_sendout(sc); 1559 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1560 (void *)&sc->sc_statep.s)) == NULL) 1561 return (ENOMEM); 1562 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1563 } 1564 } 1565 1566 if (src != NULL) 1567 sc->sc_sendaddr = *src; 1568 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 1569 h->count++; 1570 rup = sc->sc_statep.r++; 1571 bzero(rup, sizeof(*rup)); 1572 if (up != NULL) { 1573 bcopy(up->id, rup->id, sizeof(rup->id)); 1574 rup->creatorid = up->creatorid; 1575 } 1576 1577 if (h->count == sc->sc_maxcount) 1578 ret = pfsync_sendout(sc); 1579 1580 return (ret); 1581} 1582 1583int 1584pfsync_clear_states(u_int32_t creatorid, char *ifname) 1585{ 1586#ifdef __FreeBSD__ 1587 struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list)); 1588#else 1589 struct ifnet *ifp = &pfsyncif.sc_if; 1590#endif 1591 struct pfsync_softc *sc = ifp->if_softc; 1592 struct pfsync_state_clr *cp; 1593 int s, ret; 1594 1595 s = splnet(); 1596#ifdef __FreeBSD__ 1597 PF_ASSERT(MA_OWNED); 1598#endif 1599 if (sc->sc_mbuf != NULL) 1600 pfsync_sendout(sc); 1601 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 1602 (void *)&sc->sc_statep.c)) == NULL) { 1603 splx(s); 1604 return (ENOMEM); 1605 } 1606 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 1607 cp = sc->sc_statep.c; 1608 cp->creatorid = creatorid; 1609 if (ifname != NULL) 1610 strlcpy(cp->ifname, ifname, IFNAMSIZ); 1611 1612 ret = (pfsync_sendout(sc)); 1613 splx(s); 1614 return (ret); 1615} 1616 1617void 1618pfsync_timeout(void *v) 1619{ 1620 struct pfsync_softc *sc = v; 1621 int s; 1622 1623 s = splnet(); 1624#ifdef __FreeBSD__ 1625 PF_LOCK(); 1626#endif 1627 pfsync_sendout(sc); 1628#ifdef __FreeBSD__ 1629 PF_UNLOCK(); 1630#endif 1631 splx(s); 1632} 1633 1634/* This must be called in splnet() */ 1635void 1636pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 1637{ 1638 struct pfsync_state_bus *bus; 1639 1640#ifdef __FreeBSD__ 1641 PF_ASSERT(MA_OWNED); 1642#endif 1643 if (sc->sc_mbuf != NULL) 1644 pfsync_sendout(sc); 1645 1646 if (pfsync_sync_ok && 1647 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 1648 (void *)&sc->sc_statep.b)) != NULL) { 1649 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 1650 bus = sc->sc_statep.b; 1651 bus->creatorid = pf_status.hostid; 1652 bus->status = status; 1653 bus->endtime = htonl(time_uptime - sc->sc_ureq_received); 1654 pfsync_sendout(sc); 1655 } 1656} 1657 1658void 1659pfsync_bulk_update(void *v) 1660{ 1661 struct pfsync_softc *sc = v; 1662 int s, i = 0; 1663 struct pf_state *state; 1664 1665#ifdef __FreeBSD__ 1666 PF_LOCK(); 1667#endif 1668 s = splnet(); 1669 if (sc->sc_mbuf != NULL) 1670 pfsync_sendout(sc); 1671 1672 /* 1673 * Grab at most PFSYNC_BULKPACKETS worth of states which have not 1674 * been sent since the latest request was made. 1675 */ 1676 while ((state = TAILQ_FIRST(&state_updates)) != NULL && 1677 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 1678 if (state->pfsync_time > sc->sc_ureq_received) { 1679 /* we're done */ 1680 pfsync_send_bus(sc, PFSYNC_BUS_END); 1681 sc->sc_ureq_received = 0; 1682#ifdef __FreeBSD__ 1683 callout_stop(&sc->sc_bulk_tmo); 1684#else 1685 timeout_del(&sc->sc_bulk_tmo); 1686#endif 1687 if (pf_status.debug >= PF_DEBUG_MISC) 1688 printf("pfsync: bulk update complete\n"); 1689 break; 1690 } else { 1691 /* send an update and move to end of list */ 1692 if (!state->sync_flags) 1693 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 1694 state->pfsync_time = time_uptime; 1695 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 1696 TAILQ_INSERT_TAIL(&state_updates, state, 1697 u.s.entry_updates); 1698 1699 /* look again for more in a bit */ 1700#ifdef __FreeBSD__ 1701 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 1702 LIST_FIRST(&pfsync_list)); 1703#else 1704 timeout_add(&sc->sc_bulk_tmo, 1); 1705#endif 1706 } 1707 } 1708 if (sc->sc_mbuf != NULL) 1709 pfsync_sendout(sc); 1710 splx(s); 1711#ifdef __FreeBSD__ 1712 PF_UNLOCK(); 1713#endif 1714} 1715 1716void 1717pfsync_bulkfail(void *v) 1718{ 1719 struct pfsync_softc *sc = v; 1720 int s, error; 1721 1722#ifdef __FreeBSD__ 1723 PF_LOCK(); 1724#endif 1725 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1726 /* Try again in a bit */ 1727#ifdef __FreeBSD__ 1728 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1729 LIST_FIRST(&pfsync_list)); 1730#else 1731 timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); 1732#endif 1733 s = splnet(); 1734 error = pfsync_request_update(NULL, NULL); 1735 if (error == ENOMEM) { 1736 if (pf_status.debug >= PF_DEBUG_MISC) 1737 printf("pfsync: cannot allocate mbufs for " 1738 "bulk update\n"); 1739 } else 1740 pfsync_sendout(sc); 1741 splx(s); 1742 } else { 1743 /* Pretend like the transfer was ok */ 1744 sc->sc_ureq_sent = 0; 1745 sc->sc_bulk_tries = 0; 1746#if NCARP > 0 1747 if (!pfsync_sync_ok) 1748 carp_suppress_preempt--; 1749#endif 1750 pfsync_sync_ok = 1; 1751 if (pf_status.debug >= PF_DEBUG_MISC) 1752 printf("pfsync: failed to receive " 1753 "bulk update status\n"); 1754#ifdef __FreeBSD__ 1755 callout_stop(&sc->sc_bulkfail_tmo); 1756#else 1757 timeout_del(&sc->sc_bulkfail_tmo); 1758#endif 1759 } 1760#ifdef __FreeBSD__ 1761 PF_UNLOCK(); 1762#endif 1763} 1764 1765/* This must be called in splnet() */ 1766int 1767pfsync_sendout(sc) 1768 struct pfsync_softc *sc; 1769{ 1770#if NBPFILTER > 0 1771# ifdef __FreeBSD__ 1772 struct ifnet *ifp = SCP2IFP(sc); 1773# else 1774 struct ifnet *ifp = &sc->if_sc; 1775# endif 1776#endif 1777 struct mbuf *m; 1778 1779#ifdef __FreeBSD__ 1780 PF_ASSERT(MA_OWNED); 1781 callout_stop(&sc->sc_tmo); 1782#else 1783 timeout_del(&sc->sc_tmo); 1784#endif 1785 1786 if (sc->sc_mbuf == NULL) 1787 return (0); 1788 m = sc->sc_mbuf; 1789 sc->sc_mbuf = NULL; 1790 sc->sc_statep.s = NULL; 1791 1792#ifdef __FreeBSD__ 1793 KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1794#endif 1795#if NBPFILTER > 0 1796#ifdef __FreeBSD__ 1797 BPF_MTAP(ifp, m); 1798#else 1799 if (ifp->if_bpf) 1800 bpf_mtap(ifp->if_bpf, m); 1801#endif 1802#endif 1803 1804 if (sc->sc_mbuf_net) { 1805 m_freem(m); 1806 m = sc->sc_mbuf_net; 1807 sc->sc_mbuf_net = NULL; 1808 sc->sc_statep_net.s = NULL; 1809 } 1810 1811#ifdef __FreeBSD__ 1812 if (sc->sc_sync_ifp || 1813 sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) { 1814#else 1815 if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { 1816#endif 1817 struct ip *ip; 1818 struct sockaddr sa; 1819 1820 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 1821 if (m == NULL) { 1822 pfsyncstats.pfsyncs_onomem++; 1823 return (0); 1824 } 1825 ip = mtod(m, struct ip *); 1826 ip->ip_v = IPVERSION; 1827 ip->ip_hl = sizeof(*ip) >> 2; 1828 ip->ip_tos = IPTOS_LOWDELAY; 1829#ifdef __FreeBSD__ 1830 ip->ip_len = m->m_pkthdr.len; 1831#else 1832 ip->ip_len = htons(m->m_pkthdr.len); 1833#endif 1834 ip->ip_id = htons(ip_randomid()); 1835#ifdef __FreeBSD__ 1836 ip->ip_off = IP_DF; 1837#else 1838 ip->ip_off = htons(IP_DF); 1839#endif 1840 ip->ip_ttl = PFSYNC_DFLTTL; 1841 ip->ip_p = IPPROTO_PFSYNC; 1842 ip->ip_sum = 0; 1843 1844 bzero(&sa, sizeof(sa)); 1845 ip->ip_src.s_addr = INADDR_ANY; 1846 1847#ifdef __FreeBSD__ 1848 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1849#else 1850 if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) 1851#endif 1852 m->m_flags |= M_MCAST; 1853 ip->ip_dst = sc->sc_sendaddr; 1854 sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr; 1855 1856 pfsyncstats.pfsyncs_opackets++; 1857#ifdef __FreeBSD__ 1858 if (!IF_HANDOFF(&sc->sc_ifq, m, NULL)) 1859 pfsyncstats.pfsyncs_oerrors++; 1860 callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc); 1861#else 1862 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1863 pfsyncstats.pfsyncs_oerrors++; 1864#endif 1865 } else 1866 m_freem(m); 1867 1868 return (0); 1869} 1870 1871#ifdef __FreeBSD__ 1872static void 1873pfsync_senddef(void *arg) 1874{ 1875 struct pfsync_softc *sc = (struct pfsync_softc *)arg; 1876 struct mbuf *m; 1877 1878 for(;;) { 1879 IF_DEQUEUE(&sc->sc_ifq, m); 1880 if (m == NULL) 1881 break; 1882 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1883 pfsyncstats.pfsyncs_oerrors++; 1884 } 1885} 1886 1887static int 1888pfsync_modevent(module_t mod, int type, void *data) 1889{ 1890 int error = 0; 1891 1892 switch (type) { 1893 case MOD_LOAD: 1894 LIST_INIT(&pfsync_list); 1895 if_clone_attach(&pfsync_cloner); 1896 break; 1897 1898 case MOD_UNLOAD: 1899 if_clone_detach(&pfsync_cloner); 1900 break; 1901 1902 default: 1903 error = EINVAL; 1904 break; 1905 } 1906 1907 return error; 1908} 1909 1910static moduledata_t pfsync_mod = { 1911 "pfsync", 1912 pfsync_modevent, 1913 0 1914}; 1915 1916#define PFSYNC_MODVER 1 1917 1918DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 1919MODULE_VERSION(pfsync, PFSYNC_MODVER); 1920#endif /* __FreeBSD__ */ 1921