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