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