fetch.9: Minor fixes.
[dragonfly.git] / sys / net / pf / if_pfsync.c
blobfd78d23ae043f785b44de0737d82877cdcefdd79
1 /* $FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.11 2004/08/14 15:32:40 dwmalone Exp $ */
2 /* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */
3 /* $DragonFly: src/sys/net/pf/if_pfsync.c,v 1.8 2008/04/12 17:39:41 dillon Exp $ */
5 /*
6 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
8 * Copyright (c) 2002 Michael Shalayeff
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
33 #include "opt_inet.h"
34 #include "opt_inet6.h"
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 #include <sys/priv.h>
39 #include <sys/systm.h>
40 #include <sys/time.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/module.h>
46 #include <sys/sockio.h>
47 #include <sys/thread2.h>
48 #include <vm/vm_zone.h>
50 #include <machine/inttypes.h>
52 #include <net/if.h>
53 #include <net/if_types.h>
54 #include <net/route.h>
55 #include <net/bpf.h>
57 #ifdef INET
58 #include <netinet/in.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in_var.h>
61 #include <netinet/ip.h>
62 #include <netinet/ip_var.h>
63 #endif
65 #ifdef INET6
66 #ifndef INET
67 #include <netinet/in.h>
68 #endif
69 #include <netinet6/nd6.h>
70 #endif /* INET6 */
72 #include <net/pf/pfvar.h>
73 #include <net/pf/if_pfsync.h>
75 #define PFSYNCNAME "pfsync"
77 #define PFSYNC_MINMTU \
78 (sizeof(struct pfsync_header) + sizeof(struct pf_state))
80 #ifdef PFSYNCDEBUG
81 #define DPRINTF(x) do { if (pfsyncdebug) kprintf x ; } while (0)
82 int pfsyncdebug;
83 #else
84 #define DPRINTF(x)
85 #endif
87 int pfsync_sync_ok;
88 struct pfsyncstats pfsyncstats;
90 static void pfsync_clone_destroy(struct ifnet *);
91 static int pfsync_clone_create(struct if_clone *, int);
92 void pfsync_setmtu(struct pfsync_softc *, int);
93 int pfsync_insert_net_state(struct pfsync_state *);
94 int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
95 struct rtentry *);
96 int pfsyncioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
97 void pfsyncstart(struct ifnet *);
99 struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
100 int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
101 int pfsync_sendout(struct pfsync_softc *);
102 void pfsync_timeout(void *);
103 void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
104 void pfsync_bulk_update(void *);
105 void pfsync_bulkfail(void *);
107 static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
108 static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
109 struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create,
110 pfsync_clone_destroy, 1, 1);
112 static void
113 pfsync_clone_destroy(struct ifnet *ifp)
115 struct pfsync_softc *sc;
117 sc = ifp->if_softc;
118 callout_stop(&sc->sc_tmo);
119 callout_stop(&sc->sc_bulk_tmo);
120 callout_stop(&sc->sc_bulkfail_tmo);
122 bpfdetach(ifp);
123 if_detach(ifp);
124 LIST_REMOVE(sc, sc_next);
125 kfree(sc, M_PFSYNC);
128 static int
129 pfsync_clone_create(struct if_clone *ifc, int unit)
131 struct pfsync_softc *sc;
132 struct ifnet *ifp;
134 MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
135 M_WAITOK|M_ZERO);
137 pfsync_sync_ok = 1;
138 sc->sc_mbuf = NULL;
139 sc->sc_mbuf_net = NULL;
140 sc->sc_statep.s = NULL;
141 sc->sc_statep_net.s = NULL;
142 sc->sc_maxupdates = 128;
143 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
144 sc->sc_ureq_received = 0;
145 sc->sc_ureq_sent = 0;
147 ifp = &sc->sc_if;
148 if_initname(ifp, ifc->ifc_name, unit);
149 ifp->if_ioctl = pfsyncioctl;
150 ifp->if_output = pfsyncoutput;
151 ifp->if_start = pfsyncstart;
152 ifp->if_type = IFT_PFSYNC;
153 ifp->if_snd.ifq_maxlen = ifqmaxlen;
154 ifp->if_hdrlen = PFSYNC_HDRLEN;
155 ifp->if_baudrate = IF_Mbps(100);
156 ifp->if_softc = sc;
157 pfsync_setmtu(sc, MCLBYTES);
158 callout_init(&sc->sc_tmo);
159 callout_init(&sc->sc_bulk_tmo);
160 callout_init(&sc->sc_bulkfail_tmo);
161 if_attach(&sc->sc_if, NULL);
163 LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
164 bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
166 return (0);
170 * Start output on the pfsync interface.
172 void
173 pfsyncstart(struct ifnet *ifp)
175 crit_enter();
176 IF_DROP(&ifp->if_snd);
177 IF_DRAIN(&ifp->if_snd);
178 crit_exit();
182 pfsync_insert_net_state(struct pfsync_state *sp)
184 struct pf_state *st = NULL;
185 struct pf_rule *r = NULL;
186 struct pfi_kif *kif;
188 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
189 kprintf("pfsync_insert_net_state: invalid creator id:"
190 " %08" PRIx32 "\n", ntohl(sp->creatorid));
191 return (EINVAL);
194 kif = pfi_lookup_create(sp->ifname);
195 if (kif == NULL) {
196 if (pf_status.debug >= PF_DEBUG_MISC)
197 kprintf("pfsync_insert_net_state: "
198 "unknown interface: %s\n", sp->ifname);
199 /* skip this state */
200 return (0);
204 * Just use the default rule until we have infrastructure to find the
205 * best matching rule.
207 r = &pf_default_rule;
209 if (!r->max_states || r->states < r->max_states)
210 st = pool_get(&pf_state_pl, PR_NOWAIT);
211 if (st == NULL) {
212 pfi_maybe_destroy(kif);
213 return (ENOMEM);
215 bzero(st, sizeof(*st));
217 st->rule.ptr = r;
218 /* XXX get pointers to nat_rule and anchor */
220 /* fill in the rest of the state entry */
221 pf_state_host_ntoh(&sp->lan, &st->lan);
222 pf_state_host_ntoh(&sp->gwy, &st->gwy);
223 pf_state_host_ntoh(&sp->ext, &st->ext);
225 pf_state_peer_ntoh(&sp->src, &st->src);
226 pf_state_peer_ntoh(&sp->dst, &st->dst);
228 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
229 st->hash = pf_state_hash(st);
230 st->creation = ntohl(sp->creation) + time_second;
231 st->expire = ntohl(sp->expire) + time_second;
233 st->af = sp->af;
234 st->proto = sp->proto;
235 st->direction = sp->direction;
236 st->log = sp->log;
237 st->timeout = sp->timeout;
238 st->allow_opts = sp->allow_opts;
240 bcopy(sp->id, &st->id, sizeof(st->id));
241 st->creatorid = sp->creatorid;
242 st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC;
245 if (pf_insert_state(kif, st)) {
246 pfi_maybe_destroy(kif);
247 pool_put(&pf_state_pl, st);
248 return (EINVAL);
251 return (0);
254 void
255 pfsync_input(struct mbuf *m, ...)
257 struct ip *ip = mtod(m, struct ip *);
258 struct pfsync_header *ph;
259 struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
260 struct pf_state *st, key;
261 struct pfsync_state *sp;
262 struct pfsync_state_upd *up;
263 struct pfsync_state_del *dp;
264 struct pfsync_state_clr *cp;
265 struct pfsync_state_upd_req *rup;
266 struct pfsync_state_bus *bus;
267 struct in_addr src;
268 struct mbuf *mp;
269 int iplen, action, error, i, count, offp;
271 pfsyncstats.pfsyncs_ipackets++;
273 /* verify that we have a sync interface configured */
274 if (!sc->sc_sync_ifp || !pf_status.running)
275 goto done;
277 /* verify that the packet came in on the right interface */
278 if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
279 pfsyncstats.pfsyncs_badif++;
280 goto done;
283 /* verify that the IP TTL is 255. */
284 if (ip->ip_ttl != PFSYNC_DFLTTL) {
285 pfsyncstats.pfsyncs_badttl++;
286 goto done;
289 iplen = ip->ip_hl << 2;
291 if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
292 pfsyncstats.pfsyncs_hdrops++;
293 goto done;
296 if (iplen + sizeof(*ph) > m->m_len) {
297 if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
298 pfsyncstats.pfsyncs_hdrops++;
299 goto done;
301 ip = mtod(m, struct ip *);
303 ph = (struct pfsync_header *)((char *)ip + iplen);
305 /* verify the version */
306 if (ph->version != PFSYNC_VERSION) {
307 pfsyncstats.pfsyncs_badver++;
308 goto done;
311 action = ph->action;
312 count = ph->count;
314 /* make sure it's a valid action code */
315 if (action >= PFSYNC_ACT_MAX) {
316 pfsyncstats.pfsyncs_badact++;
317 goto done;
320 /* Cheaper to grab this now than having to mess with mbufs later */
321 src = ip->ip_src;
323 switch (action) {
324 case PFSYNC_ACT_CLR: {
325 struct pfi_kif *kif;
326 u_int32_t creatorid;
327 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
328 sizeof(*cp), &offp)) == NULL) {
329 pfsyncstats.pfsyncs_badlen++;
330 return;
332 cp = (struct pfsync_state_clr *)(mp->m_data + offp);
333 creatorid = cp->creatorid;
335 crit_enter();
336 if (cp->ifname[0] == '\0') {
337 RB_FOREACH(st, pf_state_tree_id, &tree_id) {
338 if (st->creatorid == creatorid)
339 st->timeout = PFTM_PURGE;
341 } else {
342 kif = pfi_lookup_if(cp->ifname);
343 if (kif == NULL) {
344 if (pf_status.debug >= PF_DEBUG_MISC)
345 kprintf("pfsync_input: PFSYNC_ACT_CLR "
346 "bad interface: %s\n", cp->ifname);
347 crit_exit();
348 goto done;
350 RB_FOREACH(st, pf_state_tree_lan_ext,
351 &kif->pfik_lan_ext) {
352 if (st->creatorid == creatorid)
353 st->timeout = PFTM_PURGE;
356 pf_purge_expired_states();
357 crit_exit();
359 break;
361 case PFSYNC_ACT_INS:
362 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
363 count * sizeof(*sp), &offp)) == NULL) {
364 pfsyncstats.pfsyncs_badlen++;
365 return;
368 crit_enter();
369 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
370 i < count; i++, sp++) {
371 /* check for invalid values */
372 if (sp->timeout >= PFTM_MAX ||
373 sp->src.state > PF_TCPS_PROXY_DST ||
374 sp->dst.state > PF_TCPS_PROXY_DST ||
375 sp->direction > PF_OUT ||
376 (sp->af != AF_INET && sp->af != AF_INET6)) {
377 if (pf_status.debug >= PF_DEBUG_MISC)
378 kprintf("pfsync_insert: PFSYNC_ACT_INS: "
379 "invalid value\n");
380 pfsyncstats.pfsyncs_badstate++;
381 continue;
384 if ((error = pfsync_insert_net_state(sp))) {
385 if (error == ENOMEM) {
386 crit_exit();
387 goto done;
389 continue;
392 crit_exit();
393 break;
394 case PFSYNC_ACT_UPD:
395 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
396 count * sizeof(*sp), &offp)) == NULL) {
397 pfsyncstats.pfsyncs_badlen++;
398 return;
401 crit_enter();
402 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
403 i < count; i++, sp++) {
404 /* check for invalid values */
405 if (sp->timeout >= PFTM_MAX ||
406 sp->src.state > PF_TCPS_PROXY_DST ||
407 sp->dst.state > PF_TCPS_PROXY_DST) {
408 if (pf_status.debug >= PF_DEBUG_MISC)
409 kprintf("pfsync_insert: PFSYNC_ACT_UPD: "
410 "invalid value\n");
411 pfsyncstats.pfsyncs_badstate++;
412 continue;
415 bcopy(sp->id, &key.id, sizeof(key.id));
416 key.creatorid = sp->creatorid;
418 st = pf_find_state_byid(&key);
419 if (st == NULL) {
420 /* insert the update */
421 if (pfsync_insert_net_state(sp))
422 pfsyncstats.pfsyncs_badstate++;
423 continue;
425 pf_state_peer_ntoh(&sp->src, &st->src);
426 pf_state_peer_ntoh(&sp->dst, &st->dst);
427 st->expire = ntohl(sp->expire) + time_second;
428 st->timeout = sp->timeout;
431 crit_exit();
432 break;
434 * It's not strictly necessary for us to support the "uncompressed"
435 * delete action, but it's relatively simple and maintains consistency.
437 case PFSYNC_ACT_DEL:
438 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
439 count * sizeof(*sp), &offp)) == NULL) {
440 pfsyncstats.pfsyncs_badlen++;
441 return;
444 crit_enter();
445 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
446 i < count; i++, sp++) {
447 bcopy(sp->id, &key.id, sizeof(key.id));
448 key.creatorid = sp->creatorid;
450 st = pf_find_state_byid(&key);
451 if (st == NULL) {
452 pfsyncstats.pfsyncs_badstate++;
453 continue;
456 * XXX
457 * pf_purge_expired_states() is expensive,
458 * we really want to purge the state directly.
460 st->timeout = PFTM_PURGE;
461 st->sync_flags |= PFSTATE_FROMSYNC;
463 pf_purge_expired_states();
464 crit_exit();
465 break;
466 case PFSYNC_ACT_UPD_C: {
467 int update_requested = 0;
469 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
470 count * sizeof(*up), &offp)) == NULL) {
471 pfsyncstats.pfsyncs_badlen++;
472 return;
475 crit_enter();
476 for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
477 i < count; i++, up++) {
478 /* check for invalid values */
479 if (up->timeout >= PFTM_MAX ||
480 up->src.state > PF_TCPS_PROXY_DST ||
481 up->dst.state > PF_TCPS_PROXY_DST) {
482 if (pf_status.debug >= PF_DEBUG_MISC)
483 kprintf("pfsync_insert: "
484 "PFSYNC_ACT_UPD_C: "
485 "invalid value\n");
486 pfsyncstats.pfsyncs_badstate++;
487 continue;
490 bcopy(up->id, &key.id, sizeof(key.id));
491 key.creatorid = up->creatorid;
493 st = pf_find_state_byid(&key);
494 if (st == NULL) {
495 /* We don't have this state. Ask for it. */
496 pfsync_request_update(up, &src);
497 update_requested = 1;
498 pfsyncstats.pfsyncs_badstate++;
499 continue;
501 pf_state_peer_ntoh(&up->src, &st->src);
502 pf_state_peer_ntoh(&up->dst, &st->dst);
503 st->expire = ntohl(up->expire) + time_second;
504 st->timeout = up->timeout;
506 if (update_requested)
507 pfsync_sendout(sc);
508 crit_exit();
509 break;
511 case PFSYNC_ACT_DEL_C:
512 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
513 count * sizeof(*dp), &offp)) == NULL) {
514 pfsyncstats.pfsyncs_badlen++;
515 return;
518 crit_enter();
519 for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
520 i < count; i++, dp++) {
521 bcopy(dp->id, &key.id, sizeof(key.id));
522 key.creatorid = dp->creatorid;
524 st = pf_find_state_byid(&key);
525 if (st == NULL) {
526 pfsyncstats.pfsyncs_badstate++;
527 continue;
530 * XXX
531 * pf_purge_expired_states() is expensive,
532 * we really want to purge the state directly.
534 st->timeout = PFTM_PURGE;
535 st->sync_flags |= PFSTATE_FROMSYNC;
537 pf_purge_expired_states();
538 crit_exit();
539 break;
540 case PFSYNC_ACT_INS_F:
541 case PFSYNC_ACT_DEL_F:
542 /* not implemented */
543 break;
544 case PFSYNC_ACT_UREQ:
545 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
546 count * sizeof(*rup), &offp)) == NULL) {
547 pfsyncstats.pfsyncs_badlen++;
548 return;
551 crit_enter();
552 /* XXX send existing. pfsync_pack_state should handle this. */
553 if (sc->sc_mbuf != NULL)
554 pfsync_sendout(sc);
555 for (i = 0,
556 rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
557 i < count; i++, rup++) {
558 bcopy(rup->id, &key.id, sizeof(key.id));
559 key.creatorid = rup->creatorid;
561 if (key.id == 0 && key.creatorid == 0) {
562 sc->sc_ureq_received = mycpu->gd_time_seconds;
563 if (pf_status.debug >= PF_DEBUG_MISC)
564 kprintf("pfsync: received "
565 "bulk update request\n");
566 pfsync_send_bus(sc, PFSYNC_BUS_START);
567 callout_reset(&sc->sc_bulk_tmo, 1 * hz,
568 pfsync_bulk_update,
569 LIST_FIRST(&pfsync_list));
570 } else {
571 st = pf_find_state_byid(&key);
572 if (st == NULL) {
573 pfsyncstats.pfsyncs_badstate++;
574 continue;
576 pfsync_pack_state(PFSYNC_ACT_UPD, st, 0);
579 if (sc->sc_mbuf != NULL)
580 pfsync_sendout(sc);
581 crit_exit();
582 break;
583 case PFSYNC_ACT_BUS:
584 /* If we're not waiting for a bulk update, who cares. */
585 if (sc->sc_ureq_sent == 0)
586 break;
588 if ((mp = m_pulldown(m, iplen + sizeof(*ph),
589 sizeof(*bus), &offp)) == NULL) {
590 pfsyncstats.pfsyncs_badlen++;
591 return;
593 bus = (struct pfsync_state_bus *)(mp->m_data + offp);
594 switch (bus->status) {
595 case PFSYNC_BUS_START:
596 callout_reset(&sc->sc_bulkfail_tmo,
597 pf_pool_limits[PF_LIMIT_STATES].limit /
598 (PFSYNC_BULKPACKETS * sc->sc_maxcount),
599 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
600 if (pf_status.debug >= PF_DEBUG_MISC)
601 kprintf("pfsync: received bulk "
602 "update start\n");
603 break;
604 case PFSYNC_BUS_END:
605 if (mycpu->gd_time_seconds - ntohl(bus->endtime) >=
606 sc->sc_ureq_sent) {
607 /* that's it, we're happy */
608 sc->sc_ureq_sent = 0;
609 sc->sc_bulk_tries = 0;
610 callout_stop(&sc->sc_bulkfail_tmo);
611 pfsync_sync_ok = 1;
612 if (pf_status.debug >= PF_DEBUG_MISC)
613 kprintf("pfsync: received valid "
614 "bulk update end\n");
615 } else {
616 if (pf_status.debug >= PF_DEBUG_MISC)
617 kprintf("pfsync: received invalid "
618 "bulk update end: bad timestamp\n");
620 break;
622 break;
625 done:
626 if (m)
627 m_freem(m);
631 pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
632 struct rtentry *rt)
634 m_freem(m);
635 return (0);
638 /* ARGSUSED */
640 pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
642 struct pfsync_softc *sc = ifp->if_softc;
643 struct ifreq *ifr = (struct ifreq *)data;
644 struct ip_moptions *imo = &sc->sc_imo;
645 struct pfsyncreq pfsyncr;
646 struct ifnet *sifp;
647 int error;
649 switch (cmd) {
650 case SIOCSIFADDR:
651 case SIOCAIFADDR:
652 case SIOCSIFDSTADDR:
653 case SIOCSIFFLAGS:
654 if (ifp->if_flags & IFF_UP)
655 ifp->if_flags |= IFF_RUNNING;
656 else
657 ifp->if_flags &= ~IFF_RUNNING;
658 break;
659 case SIOCSIFMTU:
660 if (ifr->ifr_mtu < PFSYNC_MINMTU)
661 return (EINVAL);
662 if (ifr->ifr_mtu > MCLBYTES)
663 ifr->ifr_mtu = MCLBYTES;
664 crit_enter();
665 if (ifr->ifr_mtu < ifp->if_mtu)
666 pfsync_sendout(sc);
667 pfsync_setmtu(sc, ifr->ifr_mtu);
668 crit_exit();
669 break;
670 case SIOCGETPFSYNC:
671 bzero(&pfsyncr, sizeof(pfsyncr));
672 if (sc->sc_sync_ifp)
673 strlcpy(pfsyncr.pfsyncr_syncif,
674 sc->sc_sync_ifp->if_xname, IFNAMSIZ);
675 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
676 if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
677 return (error);
678 break;
679 case SIOCSETPFSYNC:
680 if ((error = priv_check_cred(cr, PRIV_ROOT, NULL_CRED_OKAY)) != 0)
681 return (error);
682 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
683 return (error);
685 if (pfsyncr.pfsyncr_maxupdates > 255)
686 return (EINVAL);
687 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
689 if (pfsyncr.pfsyncr_syncif[0] == 0) {
690 sc->sc_sync_ifp = NULL;
691 if (sc->sc_mbuf_net != NULL) {
692 /* Don't keep stale pfsync packets around. */
693 crit_enter();
694 m_freem(sc->sc_mbuf_net);
695 sc->sc_mbuf_net = NULL;
696 sc->sc_statep_net.s = NULL;
697 crit_exit();
699 break;
701 if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL)
702 return (EINVAL);
703 else if (sifp == sc->sc_sync_ifp)
704 break;
706 crit_enter();
707 if (sifp->if_mtu < sc->sc_if.if_mtu ||
708 (sc->sc_sync_ifp != NULL &&
709 sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
710 sifp->if_mtu < MCLBYTES - sizeof(struct ip))
711 pfsync_sendout(sc);
712 sc->sc_sync_ifp = sifp;
714 pfsync_setmtu(sc, sc->sc_if.if_mtu);
716 if (imo->imo_num_memberships > 0) {
717 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
718 imo->imo_multicast_ifp = NULL;
721 if (sc->sc_sync_ifp) {
722 struct in_addr addr;
724 addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
725 /* XXX do we only use one group? Also see above */
726 if ((imo->imo_membership[0] =
727 in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
728 crit_exit();
729 return (ENOBUFS);
731 imo->imo_num_memberships++;
732 imo->imo_multicast_ifp = sc->sc_sync_ifp;
733 imo->imo_multicast_ttl = PFSYNC_DFLTTL;
734 imo->imo_multicast_loop = 0;
736 /* Request a full state table update. */
737 sc->sc_ureq_sent = mycpu->gd_time_seconds;
738 pfsync_sync_ok = 0;
739 if (pf_status.debug >= PF_DEBUG_MISC)
740 kprintf("pfsync: requesting bulk update\n");
741 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
742 pfsync_bulkfail, LIST_FIRST(&pfsync_list));
743 pfsync_request_update(NULL, NULL);
744 pfsync_sendout(sc);
746 crit_exit();
748 break;
750 default:
751 return (ENOTTY);
754 return (0);
757 void
758 pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
760 int mtu;
762 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
763 mtu = sc->sc_sync_ifp->if_mtu;
764 else
765 mtu = mtu_req;
767 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
768 sizeof(struct pfsync_state);
769 if (sc->sc_maxcount > 254)
770 sc->sc_maxcount = 254;
771 sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
772 sc->sc_maxcount * sizeof(struct pfsync_state);
775 struct mbuf *
776 pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
778 struct pfsync_header *h;
779 struct mbuf *m;
780 int len;
782 MGETHDR(m, MB_DONTWAIT, MT_DATA);
783 if (m == NULL) {
784 sc->sc_if.if_oerrors++;
785 return (NULL);
788 switch (action) {
789 case PFSYNC_ACT_CLR:
790 len = sizeof(struct pfsync_header) +
791 sizeof(struct pfsync_state_clr);
792 break;
793 case PFSYNC_ACT_UPD_C:
794 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
795 sizeof(struct pfsync_header);
796 break;
797 case PFSYNC_ACT_DEL_C:
798 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
799 sizeof(struct pfsync_header);
800 break;
801 case PFSYNC_ACT_UREQ:
802 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
803 sizeof(struct pfsync_header);
804 break;
805 case PFSYNC_ACT_BUS:
806 len = sizeof(struct pfsync_header) +
807 sizeof(struct pfsync_state_bus);
808 break;
809 default:
810 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
811 sizeof(struct pfsync_header);
812 break;
815 if (len > MHLEN) {
816 MCLGET(m, MB_DONTWAIT);
817 if ((m->m_flags & M_EXT) == 0) {
818 m_free(m);
819 sc->sc_if.if_oerrors++;
820 return (NULL);
822 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
823 } else
824 MH_ALIGN(m, len);
826 m->m_pkthdr.rcvif = NULL;
827 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
828 h = mtod(m, struct pfsync_header *);
829 h->version = PFSYNC_VERSION;
830 h->af = 0;
831 h->count = 0;
832 h->action = action;
834 *sp = (void *)((char *)h + PFSYNC_HDRLEN);
835 callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
836 LIST_FIRST(&pfsync_list));
837 return (m);
841 pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
843 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
844 struct pfsync_softc *sc = ifp->if_softc;
845 struct pfsync_header *h, *h_net;
846 struct pfsync_state *sp = NULL;
847 struct pfsync_state_upd *up = NULL;
848 struct pfsync_state_del *dp = NULL;
849 struct pf_rule *r;
850 u_long secs;
851 int ret = 0;
852 u_int8_t i = 255, newaction = 0;
855 * If a packet falls in the forest and there's nobody around to
856 * hear, does it make a sound?
858 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) {
859 /* Don't leave any stale pfsync packets hanging around. */
860 if (sc->sc_mbuf != NULL) {
861 m_freem(sc->sc_mbuf);
862 sc->sc_mbuf = NULL;
863 sc->sc_statep.s = NULL;
865 return (0);
868 if (action >= PFSYNC_ACT_MAX)
869 return (EINVAL);
871 crit_enter();
872 if (sc->sc_mbuf == NULL) {
873 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
874 (void *)&sc->sc_statep.s)) == NULL) {
875 crit_exit();
876 return (ENOMEM);
878 h = mtod(sc->sc_mbuf, struct pfsync_header *);
879 } else {
880 h = mtod(sc->sc_mbuf, struct pfsync_header *);
881 if (h->action != action) {
882 pfsync_sendout(sc);
883 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
884 (void *)&sc->sc_statep.s)) == NULL) {
885 crit_exit();
886 return (ENOMEM);
888 h = mtod(sc->sc_mbuf, struct pfsync_header *);
889 } else {
891 * If it's an update, look in the packet to see if
892 * we already have an update for the state.
894 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
895 struct pfsync_state *usp =
896 (void *)((char *)h + PFSYNC_HDRLEN);
898 for (i = 0; i < h->count; i++) {
899 if (!memcmp(usp->id, &st->id,
900 PFSYNC_ID_LEN) &&
901 usp->creatorid == st->creatorid) {
902 sp = usp;
903 sp->updates++;
904 break;
906 usp++;
912 secs = time_second;
914 st->pfsync_time = mycpu->gd_time_seconds;
915 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
916 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
918 if (sp == NULL) {
919 /* not a "duplicate" update */
920 i = 255;
921 sp = sc->sc_statep.s++;
922 sc->sc_mbuf->m_pkthdr.len =
923 sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
924 h->count++;
925 bzero(sp, sizeof(*sp));
927 bcopy(&st->id, sp->id, sizeof(sp->id));
928 sp->creatorid = st->creatorid;
930 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
931 pf_state_host_hton(&st->lan, &sp->lan);
932 pf_state_host_hton(&st->gwy, &sp->gwy);
933 pf_state_host_hton(&st->ext, &sp->ext);
935 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
937 sp->creation = htonl(secs - st->creation);
938 sp->packets[0] = htonl(st->packets[0]);
939 sp->packets[1] = htonl(st->packets[1]);
940 sp->bytes[0] = htonl(st->bytes[0]);
941 sp->bytes[1] = htonl(st->bytes[1]);
942 if ((r = st->rule.ptr) == NULL)
943 sp->rule = htonl(-1);
944 else
945 sp->rule = htonl(r->nr);
946 if ((r = st->anchor.ptr) == NULL)
947 sp->anchor = htonl(-1);
948 else
949 sp->anchor = htonl(r->nr);
950 sp->af = st->af;
951 sp->proto = st->proto;
952 sp->direction = st->direction;
953 sp->log = st->log;
954 sp->allow_opts = st->allow_opts;
955 sp->timeout = st->timeout;
957 sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC;
960 pf_state_peer_hton(&st->src, &sp->src);
961 pf_state_peer_hton(&st->dst, &sp->dst);
963 if (st->expire <= secs)
964 sp->expire = htonl(0);
965 else
966 sp->expire = htonl(st->expire - secs);
968 /* do we need to build "compressed" actions for network transfer? */
969 if (sc->sc_sync_ifp && compress) {
970 switch (action) {
971 case PFSYNC_ACT_UPD:
972 newaction = PFSYNC_ACT_UPD_C;
973 break;
974 case PFSYNC_ACT_DEL:
975 newaction = PFSYNC_ACT_DEL_C;
976 break;
977 default:
978 /* by default we just send the uncompressed states */
979 break;
983 if (newaction) {
984 if (sc->sc_mbuf_net == NULL) {
985 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
986 (void *)&sc->sc_statep_net.s)) == NULL) {
987 crit_exit();
988 return (ENOMEM);
991 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
993 switch (newaction) {
994 case PFSYNC_ACT_UPD_C:
995 if (i != 255) {
996 up = (void *)((char *)h_net +
997 PFSYNC_HDRLEN + (i * sizeof(*up)));
998 up->updates++;
999 } else {
1000 h_net->count++;
1001 sc->sc_mbuf_net->m_pkthdr.len =
1002 sc->sc_mbuf_net->m_len += sizeof(*up);
1003 up = sc->sc_statep_net.u++;
1005 bzero(up, sizeof(*up));
1006 bcopy(&st->id, up->id, sizeof(up->id));
1007 up->creatorid = st->creatorid;
1009 up->timeout = st->timeout;
1010 up->expire = sp->expire;
1011 up->src = sp->src;
1012 up->dst = sp->dst;
1013 break;
1014 case PFSYNC_ACT_DEL_C:
1015 sc->sc_mbuf_net->m_pkthdr.len =
1016 sc->sc_mbuf_net->m_len += sizeof(*dp);
1017 dp = sc->sc_statep_net.d++;
1018 h_net->count++;
1020 bzero(dp, sizeof(*dp));
1021 bcopy(&st->id, dp->id, sizeof(dp->id));
1022 dp->creatorid = st->creatorid;
1023 break;
1027 if (h->count == sc->sc_maxcount ||
1028 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1029 ret = pfsync_sendout(sc);
1031 crit_exit();
1032 return (ret);
1035 /* This must be called in splnet() */
1037 pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1039 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1040 struct pfsync_header *h;
1041 struct pfsync_softc *sc = ifp->if_softc;
1042 struct pfsync_state_upd_req *rup;
1043 int ret = 0;
1045 if (sc->sc_mbuf == NULL) {
1046 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1047 (void *)&sc->sc_statep.s)) == NULL) {
1048 return (ENOMEM);
1050 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1051 } else {
1052 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1053 if (h->action != PFSYNC_ACT_UREQ) {
1054 pfsync_sendout(sc);
1055 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1056 (void *)&sc->sc_statep.s)) == NULL) {
1057 return (ENOMEM);
1059 h = mtod(sc->sc_mbuf, struct pfsync_header *);
1063 if (src != NULL)
1064 sc->sc_sendaddr = *src;
1065 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1066 h->count++;
1067 rup = sc->sc_statep.r++;
1068 bzero(rup, sizeof(*rup));
1069 if (up != NULL) {
1070 bcopy(up->id, rup->id, sizeof(rup->id));
1071 rup->creatorid = up->creatorid;
1074 if (h->count == sc->sc_maxcount)
1075 ret = pfsync_sendout(sc);
1077 return (ret);
1081 pfsync_clear_states(u_int32_t creatorid, char *ifname)
1083 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if;
1084 struct pfsync_softc *sc = ifp->if_softc;
1085 struct pfsync_state_clr *cp;
1086 int ret;
1088 crit_enter();
1089 if (sc->sc_mbuf != NULL)
1090 pfsync_sendout(sc);
1091 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1092 (void *)&sc->sc_statep.c)) == NULL) {
1093 crit_exit();
1094 return (ENOMEM);
1096 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1097 cp = sc->sc_statep.c;
1098 cp->creatorid = creatorid;
1099 if (ifname != NULL)
1100 strlcpy(cp->ifname, ifname, IFNAMSIZ);
1102 ret = (pfsync_sendout(sc));
1103 crit_exit();
1104 return (ret);
1107 void
1108 pfsync_timeout(void *v)
1110 struct pfsync_softc *sc = v;
1112 crit_enter();
1113 pfsync_sendout(sc);
1114 crit_exit();
1117 void
1118 pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1120 struct pfsync_state_bus *bus;
1122 if (sc->sc_mbuf != NULL)
1123 pfsync_sendout(sc);
1125 if (pfsync_sync_ok &&
1126 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1127 (void *)&sc->sc_statep.b)) != NULL) {
1128 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1129 bus = sc->sc_statep.b;
1130 bus->creatorid = pf_status.hostid;
1131 bus->status = status;
1132 bus->endtime = htonl(mycpu->gd_time_seconds - sc->sc_ureq_received);
1133 pfsync_sendout(sc);
1137 void
1138 pfsync_bulk_update(void *v)
1140 struct pfsync_softc *sc = v;
1141 int i = 0;
1142 struct pf_state *state;
1144 crit_enter();
1145 if (sc->sc_mbuf != NULL)
1146 pfsync_sendout(sc);
1149 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1150 * been sent since the latest request was made.
1152 while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1153 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1154 if (state->pfsync_time > sc->sc_ureq_received) {
1155 /* we're done */
1156 pfsync_send_bus(sc, PFSYNC_BUS_END);
1157 sc->sc_ureq_received = 0;
1158 callout_stop(&sc->sc_bulk_tmo);
1159 if (pf_status.debug >= PF_DEBUG_MISC)
1160 kprintf("pfsync: bulk update complete\n");
1161 break;
1162 } else {
1163 /* send an update and move to end of list */
1164 if (!state->sync_flags)
1165 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1166 state->pfsync_time = mycpu->gd_time_seconds;
1167 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1168 TAILQ_INSERT_TAIL(&state_updates, state,
1169 u.s.entry_updates);
1171 /* look again for more in a bit */
1172 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1173 LIST_FIRST(&pfsync_list));
1176 if (sc->sc_mbuf != NULL)
1177 pfsync_sendout(sc);
1178 crit_exit();
1181 void
1182 pfsync_bulkfail(void *v)
1184 struct pfsync_softc *sc = v;
1186 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1187 /* Try again in a bit */
1188 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1189 LIST_FIRST(&pfsync_list));
1190 pfsync_request_update(NULL, NULL);
1191 pfsync_sendout(sc);
1192 } else {
1193 /* Pretend like the transfer was ok */
1194 sc->sc_ureq_sent = 0;
1195 sc->sc_bulk_tries = 0;
1196 pfsync_sync_ok = 1;
1197 if (pf_status.debug >= PF_DEBUG_MISC)
1198 kprintf("pfsync: failed to receive "
1199 "bulk update status\n");
1200 callout_stop(&sc->sc_bulkfail_tmo);
1205 pfsync_sendout(struct pfsync_softc *sc)
1207 struct ifnet *ifp = &sc->sc_if;
1208 struct mbuf *m;
1210 callout_stop(&sc->sc_tmo);
1212 if (sc->sc_mbuf == NULL)
1213 return (0);
1214 m = sc->sc_mbuf;
1215 sc->sc_mbuf = NULL;
1216 sc->sc_statep.s = NULL;
1218 KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1219 BPF_MTAP(ifp, m);
1221 if (sc->sc_mbuf_net) {
1222 m_freem(m);
1223 m = sc->sc_mbuf_net;
1224 sc->sc_mbuf_net = NULL;
1225 sc->sc_statep_net.s = NULL;
1228 if (sc->sc_sync_ifp) {
1229 struct ip *ip;
1230 struct ifaddr *ifa;
1231 struct sockaddr sa;
1233 M_PREPEND(m, sizeof(struct ip), MB_DONTWAIT);
1234 if (m == NULL) {
1235 pfsyncstats.pfsyncs_onomem++;
1236 return (0);
1238 ip = mtod(m, struct ip *);
1239 ip->ip_v = IPVERSION;
1240 ip->ip_hl = sizeof(*ip) >> 2;
1241 ip->ip_tos = IPTOS_LOWDELAY;
1242 ip->ip_len = m->m_pkthdr.len;
1243 #ifdef RANDOM_IP_ID
1244 ip->ip_id = ip_randomid();
1245 #else
1246 ip->ip_id = ntohs(ip_id++);
1247 #endif
1248 ip->ip_off = IP_DF;
1249 ip->ip_ttl = PFSYNC_DFLTTL;
1250 ip->ip_p = IPPROTO_PFSYNC;
1251 ip->ip_sum = 0;
1253 bzero(&sa, sizeof(sa));
1254 sa.sa_family = AF_INET;
1255 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp);
1256 if (ifa == NULL)
1257 return (0);
1258 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
1260 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1261 m->m_flags |= M_MCAST;
1262 ip->ip_dst = sc->sc_sendaddr;
1263 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1265 pfsyncstats.pfsyncs_opackets++;
1267 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1268 pfsyncstats.pfsyncs_oerrors++;
1269 } else
1270 m_freem(m);
1272 return (0);
1275 static int
1276 pfsync_modevent(module_t mod, int type, void *data)
1278 int error = 0;
1280 switch (type) {
1281 case MOD_LOAD:
1282 LIST_INIT(&pfsync_list);
1283 if_clone_attach(&pfsync_cloner);
1284 break;
1286 case MOD_UNLOAD:
1287 if_clone_detach(&pfsync_cloner);
1288 while (!LIST_EMPTY(&pfsync_list))
1289 pfsync_clone_destroy(
1290 &LIST_FIRST(&pfsync_list)->sc_if);
1291 break;
1293 default:
1294 error = EINVAL;
1295 break;
1298 return error;
1301 static moduledata_t pfsync_mod = {
1302 "pfsync",
1303 pfsync_modevent,
1307 #define PFSYNC_MODVER 1
1309 DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1310 MODULE_VERSION(pfsync, PFSYNC_MODVER);