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