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