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