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