2011-06-28 11:57:25 +00:00
|
|
|
/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2002 Michael Shalayeff
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
|
|
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2009 David Gwynne <dlg@openbsd.org>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2011-12-22 18:56:27 +00:00
|
|
|
/*
|
|
|
|
* Revisions picked from OpenBSD after revision 1.110 import:
|
|
|
|
* 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates
|
2011-12-22 19:05:58 +00:00
|
|
|
* 1.120, 1.175 - use monotonic time_uptime
|
2011-12-22 19:09:55 +00:00
|
|
|
* 1.122 - reduce number of updates for non-TCP sessions
|
2012-01-11 14:11:10 +00:00
|
|
|
* 1.128 - cleanups
|
2012-03-08 09:20:00 +00:00
|
|
|
* 1.146 - bzero() mbuf before sparsely filling it with data
|
2012-01-07 14:39:45 +00:00
|
|
|
* 1.170 - SIOCSIFMTU checks
|
2011-12-22 18:56:27 +00:00
|
|
|
*/
|
|
|
|
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2004-02-26 02:34:12 +00:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_inet6.h"
|
|
|
|
#include "opt_pf.h"
|
2005-12-05 11:58:35 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2011-12-22 18:31:47 +00:00
|
|
|
#define NBPFILTER 1
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif /* __FreeBSD__ */
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
2011-06-28 11:57:25 +00:00
|
|
|
#include <sys/kernel.h>
|
2006-11-06 13:42:10 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/interrupt.h>
|
2006-11-06 13:42:10 +00:00
|
|
|
#include <sys/priv.h>
|
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
#include <sys/proc.h>
|
2004-02-26 02:04:28 +00:00
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/socket.h>
|
2005-05-03 16:43:32 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <sys/endian.h>
|
2004-02-26 02:34:12 +00:00
|
|
|
#include <sys/malloc.h>
|
2004-05-31 22:48:19 +00:00
|
|
|
#include <sys/module.h>
|
2004-02-26 02:34:12 +00:00
|
|
|
#include <sys/sockio.h>
|
2007-07-03 12:16:07 +00:00
|
|
|
#include <sys/taskqueue.h>
|
2004-06-16 23:24:02 +00:00
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
2012-01-09 08:50:22 +00:00
|
|
|
#include <sys/protosw.h>
|
2004-02-26 02:34:12 +00:00
|
|
|
#else
|
2004-02-26 02:04:28 +00:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/timeout.h>
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#ifndef __FreeBSD__
|
|
|
|
#include <sys/pool.h>
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
#include <net/if.h>
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
Major overhaul of pseudo-interface cloning. Highlights include:
- Split the code out into if_clone.[ch].
- Locked struct if_clone. [1]
- Add a per-cloner match function rather then simply matching names of
the form <name><unit> and <name>.
- Use the match function to allow creation of <interface>.<tag>
vlan interfaces. The old way is preserved unchanged!
- Also the match function to allow creation of stf(4) interfaces named
stf0, stf, or 6to4. This is the only major user visible change in
that "ifconfig stf" creates the interface stf rather then stf0 and
does not print "stf0" to stdout.
- Allow destroy functions to fail so they can refuse to delete
interfaces. Currently, we forbid the deletion of interfaces which
were created in the init function, particularly lo0, pflog0, and
pfsync0. In the case of lo0 this was a panic implementation so it
does not count as a user visiable change. :-)
- Since most interfaces do not need the new functionality, an family of
wrapper functions, ifc_simple_*(), were created to wrap old style
cloner functions.
- The IF_CLONE_INITIALIZER macro is replaced with a new incompatible
IFC_CLONE_INITIALIZER and ifc_simple consumers use IFC_SIMPLE_DECLARE
instead.
Submitted by: Maurycy Pawlowski-Wieronski <maurycy at fouk.org> [1]
Reviewed by: andre, mlaier
Discussed on: net
2004-06-22 20:13:25 +00:00
|
|
|
#include <net/if_clone.h>
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <net/bpf.h>
|
2011-06-28 11:57:25 +00:00
|
|
|
#include <net/netisr.h>
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <net/vnet.h>
|
|
|
|
#endif
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/if_ether.h>
|
2005-05-03 16:43:32 +00:00
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/tcp_seq.h>
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
#ifdef INET
|
2004-06-16 23:24:02 +00:00
|
|
|
#include <netinet/in_systm.h>
|
2004-02-26 02:04:28 +00:00
|
|
|
#include <netinet/in_var.h>
|
2004-06-16 23:24:02 +00:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_var.h>
|
2004-02-26 02:04:28 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet6/nd6.h>
|
|
|
|
#endif /* INET6 */
|
|
|
|
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <netinet/ip_carp.h>
|
|
|
|
#else
|
2005-05-03 16:43:32 +00:00
|
|
|
#include "carp.h"
|
|
|
|
#if NCARP > 0
|
2007-07-03 12:16:07 +00:00
|
|
|
#include <netinet/ip_carp.h>
|
2005-05-03 16:43:32 +00:00
|
|
|
#endif
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#endif
|
2005-05-03 16:43:32 +00:00
|
|
|
|
2004-02-26 02:04:28 +00:00
|
|
|
#include <net/pfvar.h>
|
|
|
|
#include <net/if_pfsync.h>
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifndef __FreeBSD__
|
|
|
|
#include "bpfilter.h"
|
|
|
|
#include "pfsync.h"
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#define PFSYNC_MINPKT ( \
|
|
|
|
sizeof(struct ip) + \
|
|
|
|
sizeof(struct pfsync_header) + \
|
|
|
|
sizeof(struct pfsync_subheader) + \
|
|
|
|
sizeof(struct pfsync_eof))
|
|
|
|
|
|
|
|
struct pfsync_pkt {
|
|
|
|
struct ip *ip;
|
|
|
|
struct in_addr src;
|
|
|
|
u_int8_t flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
int pfsync_input_hmac(struct mbuf *, int);
|
|
|
|
|
|
|
|
int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *,
|
|
|
|
struct pfsync_state_peer *);
|
|
|
|
|
|
|
|
int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
|
|
|
|
int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int);
|
|
|
|
|
|
|
|
int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = {
|
|
|
|
pfsync_in_clr, /* PFSYNC_ACT_CLR */
|
|
|
|
pfsync_in_ins, /* PFSYNC_ACT_INS */
|
|
|
|
pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */
|
|
|
|
pfsync_in_upd, /* PFSYNC_ACT_UPD */
|
|
|
|
pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */
|
|
|
|
pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */
|
|
|
|
pfsync_in_del, /* PFSYNC_ACT_DEL */
|
|
|
|
pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */
|
|
|
|
pfsync_in_error, /* PFSYNC_ACT_INS_F */
|
|
|
|
pfsync_in_error, /* PFSYNC_ACT_DEL_F */
|
|
|
|
pfsync_in_bus, /* PFSYNC_ACT_BUS */
|
|
|
|
pfsync_in_tdb, /* PFSYNC_ACT_TDB */
|
|
|
|
pfsync_in_eof /* PFSYNC_ACT_EOF */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pfsync_q {
|
|
|
|
int (*write)(struct pf_state *, struct mbuf *, int);
|
|
|
|
size_t len;
|
|
|
|
u_int8_t action;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* we have one of these for every PFSYNC_S_ */
|
|
|
|
int pfsync_out_state(struct pf_state *, struct mbuf *, int);
|
|
|
|
int pfsync_out_iack(struct pf_state *, struct mbuf *, int);
|
|
|
|
int pfsync_out_upd_c(struct pf_state *, struct mbuf *, int);
|
|
|
|
int pfsync_out_del(struct pf_state *, struct mbuf *, int);
|
|
|
|
|
|
|
|
struct pfsync_q pfsync_qs[] = {
|
|
|
|
{ pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS },
|
|
|
|
{ pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
|
|
|
|
{ pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD },
|
|
|
|
{ pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C },
|
|
|
|
{ pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C }
|
|
|
|
};
|
|
|
|
|
|
|
|
void pfsync_q_ins(struct pf_state *, int);
|
|
|
|
void pfsync_q_del(struct pf_state *);
|
|
|
|
|
|
|
|
struct pfsync_upd_req_item {
|
|
|
|
TAILQ_ENTRY(pfsync_upd_req_item) ur_entry;
|
|
|
|
struct pfsync_upd_req ur_msg;
|
|
|
|
};
|
|
|
|
TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item);
|
|
|
|
|
|
|
|
struct pfsync_deferral {
|
|
|
|
TAILQ_ENTRY(pfsync_deferral) pd_entry;
|
|
|
|
struct pf_state *pd_st;
|
|
|
|
struct mbuf *pd_m;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct callout pd_tmo;
|
|
|
|
#else
|
|
|
|
struct timeout pd_tmo;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
TAILQ_HEAD(pfsync_deferrals, pfsync_deferral);
|
|
|
|
|
|
|
|
#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \
|
|
|
|
sizeof(struct pfsync_deferral))
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
int pfsync_out_tdb(struct tdb *, struct mbuf *, int);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct pfsync_softc {
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct ifnet *sc_ifp;
|
|
|
|
#else
|
|
|
|
struct ifnet sc_if;
|
|
|
|
#endif
|
|
|
|
struct ifnet *sc_sync_if;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
uma_zone_t sc_pool;
|
|
|
|
#else
|
|
|
|
struct pool sc_pool;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct ip_moptions sc_imo;
|
|
|
|
|
|
|
|
struct in_addr sc_sync_peer;
|
|
|
|
u_int8_t sc_maxupdates;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
int pfsync_sync_ok;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct ip sc_template;
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pf_state_queue sc_qs[PFSYNC_S_COUNT];
|
|
|
|
size_t sc_len;
|
|
|
|
|
|
|
|
struct pfsync_upd_reqs sc_upd_req_list;
|
|
|
|
|
|
|
|
struct pfsync_deferrals sc_deferrals;
|
|
|
|
u_int sc_deferred;
|
|
|
|
|
|
|
|
void *sc_plus;
|
|
|
|
size_t sc_pluslen;
|
|
|
|
|
|
|
|
u_int32_t sc_ureq_sent;
|
|
|
|
int sc_bulk_tries;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct callout sc_bulkfail_tmo;
|
|
|
|
#else
|
|
|
|
struct timeout sc_bulkfail_tmo;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
u_int32_t sc_ureq_received;
|
|
|
|
struct pf_state *sc_bulk_next;
|
|
|
|
struct pf_state *sc_bulk_last;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct callout sc_bulk_tmo;
|
|
|
|
#else
|
|
|
|
struct timeout sc_bulk_tmo;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TAILQ_HEAD(, tdb) sc_tdb_q;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct callout sc_tmo;
|
2004-02-26 02:04:28 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct timeout sc_tmo;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
static MALLOC_DEFINE(M_PFSYNC, "pfsync", "pfsync data");
|
2011-06-28 11:57:25 +00:00
|
|
|
static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL;
|
|
|
|
#define V_pfsyncif VNET(pfsyncif)
|
2012-01-09 08:50:22 +00:00
|
|
|
static VNET_DEFINE(void *, pfsync_swi_cookie) = NULL;
|
|
|
|
#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie)
|
2011-06-28 11:57:25 +00:00
|
|
|
static VNET_DEFINE(struct pfsyncstats, pfsyncstats);
|
|
|
|
#define V_pfsyncstats VNET(pfsyncstats)
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
static VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW;
|
|
|
|
#define V_pfsync_carp_adj VNET(pfsync_carp_adj)
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
static void pfsyncintr(void *);
|
|
|
|
static int pfsync_multicast_setup(struct pfsync_softc *);
|
|
|
|
static void pfsync_multicast_cleanup(struct pfsync_softc *);
|
|
|
|
static int pfsync_init(void);
|
|
|
|
static void pfsync_uninit(void);
|
2012-01-11 18:34:57 +00:00
|
|
|
static void pfsync_sendout1(int);
|
|
|
|
|
|
|
|
#define schednetisr(NETISR_PFSYNC) swi_sched(V_pfsync_swi_cookie, 0)
|
2012-01-09 08:50:22 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC");
|
|
|
|
SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW,
|
|
|
|
&VNET_NAME(pfsyncstats), pfsyncstats,
|
|
|
|
"PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
SYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW,
|
|
|
|
&VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment");
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
2007-07-03 12:16:07 +00:00
|
|
|
struct pfsync_softc *pfsyncif = NULL;
|
|
|
|
struct pfsyncstats pfsyncstats;
|
2011-06-28 11:57:25 +00:00
|
|
|
#define V_pfsyncstats pfsyncstats
|
|
|
|
#endif
|
|
|
|
|
2004-02-26 02:04:28 +00:00
|
|
|
void pfsyncattach(int);
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
int pfsync_clone_create(struct if_clone *, int, caddr_t);
|
|
|
|
void pfsync_clone_destroy(struct ifnet *);
|
|
|
|
#else
|
|
|
|
int pfsync_clone_create(struct if_clone *, int);
|
|
|
|
int pfsync_clone_destroy(struct ifnet *);
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
int pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
|
|
|
|
struct pf_state_peer *);
|
|
|
|
void pfsync_update_net_tdb(struct pfsync_tdb *);
|
2004-02-26 02:04:28 +00:00
|
|
|
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
2009-04-16 20:30:28 +00:00
|
|
|
struct route *);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
struct rtentry *);
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
int pfsyncioctl(struct ifnet *, u_long, caddr_t);
|
|
|
|
void pfsyncstart(struct ifnet *);
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
struct mbuf *pfsync_if_dequeue(struct ifnet *);
|
|
|
|
|
|
|
|
void pfsync_deferred(struct pf_state *, int);
|
|
|
|
void pfsync_undefer(struct pfsync_deferral *, int);
|
|
|
|
void pfsync_defer_tmo(void *);
|
|
|
|
|
|
|
|
void pfsync_request_update(u_int32_t, u_int64_t);
|
|
|
|
void pfsync_update_state_req(struct pf_state *);
|
|
|
|
|
|
|
|
void pfsync_drop(struct pfsync_softc *);
|
|
|
|
void pfsync_sendout(void);
|
|
|
|
void pfsync_send_plus(void *, size_t);
|
2004-06-16 23:24:02 +00:00
|
|
|
void pfsync_timeout(void *);
|
2007-07-03 12:16:07 +00:00
|
|
|
void pfsync_tdb_timeout(void *);
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
void pfsync_bulk_start(void);
|
|
|
|
void pfsync_bulk_status(u_int8_t);
|
2004-06-16 23:24:02 +00:00
|
|
|
void pfsync_bulk_update(void *);
|
2011-06-28 11:57:25 +00:00
|
|
|
void pfsync_bulk_fail(void *);
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2007-03-19 17:52:15 +00:00
|
|
|
#ifdef __FreeBSD__
|
2007-07-03 12:16:07 +00:00
|
|
|
/* XXX: ugly */
|
|
|
|
#define betoh64 (unsigned long long)be64toh
|
|
|
|
#define timeout_del callout_stop
|
2007-03-19 17:52:15 +00:00
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#define PFSYNC_MAX_BULKTRIES 12
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifndef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
int pfsync_sync_ok;
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
|
|
|
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
VNET_DEFINE(struct ifc_simple_data, pfsync_cloner_data);
|
|
|
|
VNET_DEFINE(struct if_clone, pfsync_cloner);
|
|
|
|
#define V_pfsync_cloner_data VNET(pfsync_cloner_data)
|
|
|
|
#define V_pfsync_cloner VNET(pfsync_cloner)
|
Major overhaul of pseudo-interface cloning. Highlights include:
- Split the code out into if_clone.[ch].
- Locked struct if_clone. [1]
- Add a per-cloner match function rather then simply matching names of
the form <name><unit> and <name>.
- Use the match function to allow creation of <interface>.<tag>
vlan interfaces. The old way is preserved unchanged!
- Also the match function to allow creation of stf(4) interfaces named
stf0, stf, or 6to4. This is the only major user visible change in
that "ifconfig stf" creates the interface stf rather then stf0 and
does not print "stf0" to stdout.
- Allow destroy functions to fail so they can refuse to delete
interfaces. Currently, we forbid the deletion of interfaces which
were created in the init function, particularly lo0, pflog0, and
pfsync0. In the case of lo0 this was a panic implementation so it
does not count as a user visiable change. :-)
- Since most interfaces do not need the new functionality, an family of
wrapper functions, ifc_simple_*(), were created to wrap old style
cloner functions.
- The IF_CLONE_INITIALIZER macro is replaced with a new incompatible
IFC_CLONE_INITIALIZER and ifc_simple consumers use IFC_SIMPLE_DECLARE
instead.
Submitted by: Maurycy Pawlowski-Wieronski <maurycy at fouk.org> [1]
Reviewed by: andre, mlaier
Discussed on: net
2004-06-22 20:13:25 +00:00
|
|
|
IFC_SIMPLE_DECLARE(pfsync, 1);
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
|
|
|
struct if_clone pfsync_cloner =
|
|
|
|
IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
|
2007-03-19 17:52:15 +00:00
|
|
|
#endif
|
2005-06-10 17:23:49 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
void
|
|
|
|
pfsyncattach(int npfsync)
|
|
|
|
{
|
|
|
|
if_clone_attach(&pfsync_cloner);
|
2004-02-26 02:34:12 +00:00
|
|
|
}
|
2007-07-03 12:16:07 +00:00
|
|
|
int
|
2006-07-09 06:04:01 +00:00
|
|
|
#ifdef __FreeBSD__
|
2007-07-03 12:16:07 +00:00
|
|
|
pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param)
|
2006-07-09 06:04:01 +00:00
|
|
|
#else
|
2004-02-26 02:34:12 +00:00
|
|
|
pfsync_clone_create(struct if_clone *ifc, int unit)
|
2006-07-09 06:04:01 +00:00
|
|
|
#endif
|
2004-02-26 02:34:12 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc;
|
2004-06-16 23:24:02 +00:00
|
|
|
struct ifnet *ifp;
|
2011-06-28 11:57:25 +00:00
|
|
|
int q;
|
2004-02-26 02:34:12 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
if (unit != 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO);
|
|
|
|
sc->pfsync_sync_ok = 1;
|
|
|
|
#else
|
2007-07-03 12:16:07 +00:00
|
|
|
pfsync_sync_ok = 1;
|
2012-01-09 08:50:22 +00:00
|
|
|
sc = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT | M_ZERO);
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (q = 0; q < PFSYNC_S_COUNT; q++)
|
|
|
|
TAILQ_INIT(&sc->sc_qs[q]);
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, NULL, NULL, NULL,
|
|
|
|
NULL, UMA_ALIGN_PTR, 0);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL);
|
|
|
|
#endif
|
|
|
|
TAILQ_INIT(&sc->sc_upd_req_list);
|
|
|
|
TAILQ_INIT(&sc->sc_deferrals);
|
|
|
|
sc->sc_deferred = 0;
|
|
|
|
|
|
|
|
TAILQ_INIT(&sc->sc_tdb_q);
|
|
|
|
|
|
|
|
sc->sc_len = PFSYNC_MINPKT;
|
|
|
|
sc->sc_maxupdates = 128;
|
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
#ifndef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_imo.imo_membership = (struct in_multi **)malloc(
|
|
|
|
(sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
|
|
|
|
M_WAITOK | M_ZERO);
|
|
|
|
sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
|
2005-06-10 16:49:24 +00:00
|
|
|
if (ifp == NULL) {
|
2011-06-28 11:57:25 +00:00
|
|
|
uma_zdestroy(sc->sc_pool);
|
2012-01-09 08:50:22 +00:00
|
|
|
free(sc, M_PFSYNC);
|
2005-06-10 16:49:24 +00:00
|
|
|
return (ENOSPC);
|
|
|
|
}
|
2007-07-03 12:16:07 +00:00
|
|
|
if_initname(ifp, ifc->ifc_name, unit);
|
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
ifp = &sc->sc_if;
|
2007-07-03 12:16:07 +00:00
|
|
|
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
|
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
ifp->if_softc = sc;
|
2004-06-16 23:24:02 +00:00
|
|
|
ifp->if_ioctl = pfsyncioctl;
|
|
|
|
ifp->if_output = pfsyncoutput;
|
|
|
|
ifp->if_start = pfsyncstart;
|
2007-07-03 12:16:07 +00:00
|
|
|
ifp->if_type = IFT_PFSYNC;
|
2004-06-16 23:24:02 +00:00
|
|
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
2011-06-28 11:57:25 +00:00
|
|
|
ifp->if_hdrlen = sizeof(struct pfsync_header);
|
2012-01-07 14:39:45 +00:00
|
|
|
ifp->if_mtu = ETHERMTU;
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
callout_init(&sc->sc_tmo, CALLOUT_MPSAFE);
|
2011-10-23 15:08:18 +00:00
|
|
|
callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0);
|
2011-06-28 11:57:25 +00:00
|
|
|
callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE);
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
timeout_set(&sc->sc_tmo, pfsync_timeout, sc);
|
|
|
|
timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc);
|
|
|
|
timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2005-02-09 19:29:13 +00:00
|
|
|
if_attach(ifp);
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifndef __FreeBSD__
|
|
|
|
if_alloc_sadl(ifp);
|
|
|
|
|
|
|
|
#if NCARP > 0
|
|
|
|
if_addgroup(ifp, "carp");
|
|
|
|
#endif
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#endif
|
2004-02-26 02:34:12 +00:00
|
|
|
|
|
|
|
#if NBPFILTER > 0
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2005-02-09 19:29:13 +00:00
|
|
|
bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
V_pfsyncif = sc;
|
|
|
|
#else
|
|
|
|
pfsyncif = sc;
|
|
|
|
#endif
|
|
|
|
|
2004-02-26 02:34:12 +00:00
|
|
|
return (0);
|
|
|
|
}
|
2007-07-03 12:16:07 +00:00
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2004-02-26 02:04:28 +00:00
|
|
|
void
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
|
|
|
int
|
|
|
|
#endif
|
|
|
|
pfsync_clone_destroy(struct ifnet *ifp)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = ifp->if_softc;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-12-20 12:34:16 +00:00
|
|
|
PF_LOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2011-12-22 18:56:27 +00:00
|
|
|
timeout_del(&sc->sc_bulkfail_tmo);
|
2011-12-20 12:34:16 +00:00
|
|
|
timeout_del(&sc->sc_bulk_tmo);
|
2011-06-28 11:57:25 +00:00
|
|
|
timeout_del(&sc->sc_tmo);
|
2011-12-20 12:34:16 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
if (!sc->pfsync_sync_ok && carp_demote_adj_p)
|
|
|
|
(*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy");
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#if NCARP > 0
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!pfsync_sync_ok)
|
|
|
|
carp_group_demote_adj(&sc->sc_if, -1);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
#if NBPFILTER > 0
|
2007-07-03 12:16:07 +00:00
|
|
|
bpfdetach(ifp);
|
2004-02-26 02:04:28 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
if_detach(ifp);
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
pfsync_drop(sc);
|
|
|
|
|
|
|
|
while (sc->sc_deferred > 0)
|
|
|
|
pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
UMA_DESTROY(sc->sc_pool);
|
|
|
|
#else
|
|
|
|
pool_destroy(&sc->sc_pool);
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if_free(ifp);
|
2012-01-09 08:50:22 +00:00
|
|
|
if (sc->sc_imo.imo_membership)
|
|
|
|
pfsync_multicast_cleanup(sc);
|
|
|
|
free(sc, M_PFSYNC);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
free(sc->sc_imo.imo_membership, M_IPMOPTS);
|
|
|
|
free(sc, M_DEVBUF);
|
2012-01-09 08:50:22 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
V_pfsyncif = NULL;
|
|
|
|
#else
|
2007-07-03 12:16:07 +00:00
|
|
|
pfsyncif = NULL;
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifndef __FreeBSD__
|
|
|
|
return (0);
|
|
|
|
#endif
|
|
|
|
}
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
struct mbuf *
|
|
|
|
pfsync_if_dequeue(struct ifnet *ifp)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
|
|
|
struct mbuf *m;
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifndef __FreeBSD__
|
2004-02-26 02:04:28 +00:00
|
|
|
int s;
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
IF_LOCK(&ifp->if_snd);
|
|
|
|
_IF_DROP(&ifp->if_snd);
|
|
|
|
_IF_DEQUEUE(&ifp->if_snd, m);
|
|
|
|
IF_UNLOCK(&ifp->if_snd);
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splnet();
|
|
|
|
IF_DEQUEUE(&ifp->if_snd, m);
|
|
|
|
splx(s);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
return (m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start output on the pfsync interface.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pfsyncstart(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct mbuf *m;
|
|
|
|
|
|
|
|
while ((m = pfsync_if_dequeue(ifp)) != NULL) {
|
|
|
|
#ifndef __FreeBSD__
|
|
|
|
IF_DROP(&ifp->if_snd);
|
|
|
|
#endif
|
|
|
|
m_freem(m);
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-07-03 12:16:07 +00:00
|
|
|
pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
|
|
|
|
struct pf_state_peer *d)
|
|
|
|
{
|
|
|
|
if (s->scrub.scrub_flag && d->scrub == NULL) {
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
|
|
|
|
#else
|
|
|
|
d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
if (d->scrub == NULL)
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifndef __FreeBSD__
|
|
|
|
void
|
|
|
|
pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
|
|
|
|
{
|
|
|
|
bzero(sp, sizeof(struct pfsync_state));
|
|
|
|
|
|
|
|
/* copy from state key */
|
|
|
|
sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
|
|
|
|
sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
|
|
|
|
sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
|
|
|
|
sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
|
|
|
|
sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
|
|
|
|
sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
|
|
|
|
sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
|
|
|
|
sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
|
|
|
|
sp->proto = st->key[PF_SK_WIRE]->proto;
|
|
|
|
sp->af = st->key[PF_SK_WIRE]->af;
|
|
|
|
|
|
|
|
/* copy from state */
|
|
|
|
strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
|
|
|
|
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
|
2011-12-22 19:05:58 +00:00
|
|
|
sp->creation = htonl(time_uptime - st->creation);
|
2011-06-28 11:57:25 +00:00
|
|
|
sp->expire = pf_state_expires(st);
|
|
|
|
if (sp->expire <= time_second)
|
|
|
|
sp->expire = htonl(0);
|
|
|
|
else
|
|
|
|
sp->expire = htonl(sp->expire - time_second);
|
|
|
|
|
|
|
|
sp->direction = st->direction;
|
|
|
|
sp->log = st->log;
|
|
|
|
sp->timeout = st->timeout;
|
|
|
|
sp->state_flags = st->state_flags;
|
|
|
|
if (st->src_node)
|
|
|
|
sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
|
|
|
|
if (st->nat_src_node)
|
|
|
|
sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
|
|
|
|
|
|
|
|
bcopy(&st->id, &sp->id, sizeof(sp->id));
|
|
|
|
sp->creatorid = st->creatorid;
|
|
|
|
pf_state_peer_hton(&st->src, &sp->src);
|
|
|
|
pf_state_peer_hton(&st->dst, &sp->dst);
|
|
|
|
|
|
|
|
if (st->rule.ptr == NULL)
|
|
|
|
sp->rule = htonl(-1);
|
|
|
|
else
|
|
|
|
sp->rule = htonl(st->rule.ptr->nr);
|
|
|
|
if (st->anchor.ptr == NULL)
|
|
|
|
sp->anchor = htonl(-1);
|
|
|
|
else
|
|
|
|
sp->anchor = htonl(st->anchor.ptr->nr);
|
|
|
|
if (st->nat_rule.ptr == NULL)
|
|
|
|
sp->nat_rule = htonl(-1);
|
|
|
|
else
|
|
|
|
sp->nat_rule = htonl(st->nat_rule.ptr->nr);
|
|
|
|
|
|
|
|
pf_state_counter_hton(st->packets[0], sp->packets[0]);
|
|
|
|
pf_state_counter_hton(st->packets[1], sp->packets[1]);
|
|
|
|
pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
|
|
|
|
pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
int
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
|
2004-06-16 23:24:02 +00:00
|
|
|
{
|
|
|
|
struct pf_state *st = NULL;
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pf_state_key *skw = NULL, *sks = NULL;
|
2004-06-16 23:24:02 +00:00
|
|
|
struct pf_rule *r = NULL;
|
|
|
|
struct pfi_kif *kif;
|
2011-06-28 11:57:25 +00:00
|
|
|
int pool_flags;
|
|
|
|
int error;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2012-01-11 14:13:42 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) {
|
|
|
|
#else
|
2004-06-16 23:24:02 +00:00
|
|
|
if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
printf("pfsync_state_import: invalid creator id:"
|
2004-06-16 23:24:02 +00:00
|
|
|
" %08x\n", ntohl(sp->creatorid));
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
2004-06-16 23:24:02 +00:00
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
printf("pfsync_state_import: "
|
2004-06-16 23:24:02 +00:00
|
|
|
"unknown interface: %s\n", sp->ifname);
|
2011-06-28 11:57:25 +00:00
|
|
|
if (flags & PFSYNC_SI_IOCTL)
|
|
|
|
return (EINVAL);
|
|
|
|
return (0); /* skip this state */
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-06-28 11:57:25 +00:00
|
|
|
* If the ruleset checksums match or the state is coming from the ioctl,
|
|
|
|
* it's safe to associate the state with the rule of that number.
|
2004-06-16 23:24:02 +00:00
|
|
|
*/
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
|
|
|
|
(flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
|
|
|
|
pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
|
2007-07-03 12:16:07 +00:00
|
|
|
r = pf_main_ruleset.rules[
|
|
|
|
PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
|
|
|
|
else
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
r = &V_pf_default_rule;
|
|
|
|
#else
|
2007-07-03 12:16:07 +00:00
|
|
|
r = &pf_default_rule;
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if ((r->max_states && r->states_cur >= r->max_states))
|
|
|
|
goto cleanup;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (flags & PFSYNC_SI_IOCTL)
|
|
|
|
pool_flags = PR_WAITOK | PR_ZERO;
|
|
|
|
else
|
2011-10-23 10:13:20 +00:00
|
|
|
pool_flags = PR_NOWAIT | PR_ZERO;
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
#else
|
|
|
|
if (flags & PFSYNC_SI_IOCTL)
|
|
|
|
pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO;
|
|
|
|
else
|
|
|
|
pool_flags = PR_LIMITFAIL | PR_ZERO;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
#endif
|
2005-05-03 16:43:32 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if ((skw = pf_alloc_state_key(pool_flags)) == NULL)
|
|
|
|
goto cleanup;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0],
|
|
|
|
&sp->key[PF_SK_STACK].addr[0], sp->af) ||
|
|
|
|
PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1],
|
|
|
|
&sp->key[PF_SK_STACK].addr[1], sp->af) ||
|
|
|
|
sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] ||
|
|
|
|
sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) {
|
|
|
|
if ((sks = pf_alloc_state_key(pool_flags)) == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
} else
|
|
|
|
sks = skw;
|
|
|
|
|
|
|
|
/* allocate memory for scrub info */
|
|
|
|
if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
|
|
|
|
pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* copy to state key(s) */
|
|
|
|
skw->addr[0] = sp->key[PF_SK_WIRE].addr[0];
|
|
|
|
skw->addr[1] = sp->key[PF_SK_WIRE].addr[1];
|
|
|
|
skw->port[0] = sp->key[PF_SK_WIRE].port[0];
|
|
|
|
skw->port[1] = sp->key[PF_SK_WIRE].port[1];
|
|
|
|
skw->proto = sp->proto;
|
|
|
|
skw->af = sp->af;
|
|
|
|
if (sks != skw) {
|
|
|
|
sks->addr[0] = sp->key[PF_SK_STACK].addr[0];
|
|
|
|
sks->addr[1] = sp->key[PF_SK_STACK].addr[1];
|
|
|
|
sks->port[0] = sp->key[PF_SK_STACK].port[0];
|
|
|
|
sks->port[1] = sp->key[PF_SK_STACK].port[1];
|
|
|
|
sks->proto = sp->proto;
|
|
|
|
sks->af = sp->af;
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/* copy to state */
|
2004-06-16 23:24:02 +00:00
|
|
|
bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
|
2011-12-22 19:05:58 +00:00
|
|
|
st->creation = time_uptime - ntohl(sp->creation);
|
2011-06-28 11:57:25 +00:00
|
|
|
st->expire = time_second;
|
|
|
|
if (sp->expire) {
|
|
|
|
/* XXX No adaptive scaling. */
|
|
|
|
st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire);
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
st->expire = ntohl(sp->expire) + time_second;
|
2004-06-16 23:24:02 +00:00
|
|
|
st->direction = sp->direction;
|
|
|
|
st->log = sp->log;
|
|
|
|
st->timeout = sp->timeout;
|
2009-12-24 00:43:44 +00:00
|
|
|
st->state_flags = sp->state_flags;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
bcopy(sp->id, &st->id, sizeof(st->id));
|
|
|
|
st->creatorid = sp->creatorid;
|
2011-06-28 11:57:25 +00:00
|
|
|
pf_state_peer_ntoh(&sp->src, &st->src);
|
|
|
|
pf_state_peer_ntoh(&sp->dst, &st->dst);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
st->rule.ptr = r;
|
|
|
|
st->nat_rule.ptr = NULL;
|
|
|
|
st->anchor.ptr = NULL;
|
|
|
|
st->rt_kif = NULL;
|
|
|
|
|
2011-12-22 19:05:58 +00:00
|
|
|
st->pfsync_time = time_uptime;
|
2011-06-28 11:57:25 +00:00
|
|
|
st->sync_state = PFSYNC_S_NONE;
|
|
|
|
|
|
|
|
/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
|
|
|
|
r->states_cur++;
|
|
|
|
r->states_tot++;
|
|
|
|
|
|
|
|
if (!ISSET(flags, PFSYNC_SI_IOCTL))
|
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
|
|
|
|
if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
|
2005-05-03 16:43:32 +00:00
|
|
|
/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
|
2011-06-28 11:57:25 +00:00
|
|
|
r->states_cur--;
|
|
|
|
goto cleanup_state;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!ISSET(flags, PFSYNC_SI_IOCTL)) {
|
|
|
|
CLR(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK)) {
|
|
|
|
pfsync_q_ins(st, PFSYNC_S_IACK);
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CLR(st->state_flags, PFSTATE_ACK);
|
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
return (0);
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
cleanup:
|
|
|
|
error = ENOMEM;
|
|
|
|
if (skw == sks)
|
|
|
|
sks = NULL;
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (skw != NULL)
|
|
|
|
pool_put(&V_pf_state_key_pl, skw);
|
|
|
|
if (sks != NULL)
|
|
|
|
pool_put(&V_pf_state_key_pl, sks);
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (skw != NULL)
|
|
|
|
pool_put(&pf_state_key_pl, skw);
|
|
|
|
if (sks != NULL)
|
|
|
|
pool_put(&pf_state_key_pl, sks);
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
cleanup_state: /* pf_state_insert frees the state keys */
|
|
|
|
if (st) {
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (st->dst.scrub)
|
|
|
|
pool_put(&V_pf_state_scrub_pl, st->dst.scrub);
|
|
|
|
if (st->src.scrub)
|
|
|
|
pool_put(&V_pf_state_scrub_pl, st->src.scrub);
|
|
|
|
pool_put(&V_pf_state_pl, st);
|
|
|
|
#else
|
|
|
|
if (st->dst.scrub)
|
|
|
|
pool_put(&pf_state_scrub_pl, st->dst.scrub);
|
|
|
|
if (st->src.scrub)
|
|
|
|
pool_put(&pf_state_scrub_pl, st->src.scrub);
|
|
|
|
pool_put(&pf_state_pl, st);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
pfsync_input(struct mbuf *m, __unused int off)
|
|
|
|
#else
|
|
|
|
pfsync_input(struct mbuf *m, ...)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
struct pfsync_pkt pkt;
|
|
|
|
struct ip *ip = mtod(m, struct ip *);
|
|
|
|
struct pfsync_header *ph;
|
|
|
|
struct pfsync_subheader subh;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
int offset;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
V_pfsyncstats.pfsyncs_ipackets++;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
/* verify that we have a sync interface configured */
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (!sc || !sc->sc_sync_if || !V_pf_status.running)
|
|
|
|
#else
|
|
|
|
if (!sc || !sc->sc_sync_if || !pf_status.running)
|
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* verify that the packet came in on the right interface */
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_sync_if != m->m_pkthdr.rcvif) {
|
|
|
|
V_pfsyncstats.pfsyncs_badif++;
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
sc->sc_ifp->if_ipackets++;
|
|
|
|
sc->sc_ifp->if_ibytes += m->m_pkthdr.len;
|
|
|
|
#else
|
|
|
|
sc->sc_if.if_ipackets++;
|
|
|
|
sc->sc_if.if_ibytes += m->m_pkthdr.len;
|
|
|
|
#endif
|
|
|
|
/* verify that the IP TTL is 255. */
|
2004-06-16 23:24:02 +00:00
|
|
|
if (ip->ip_ttl != PFSYNC_DFLTTL) {
|
2011-06-28 11:57:25 +00:00
|
|
|
V_pfsyncstats.pfsyncs_badttl++;
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
offset = ip->ip_hl << 2;
|
|
|
|
if (m->m_pkthdr.len < offset + sizeof(*ph)) {
|
|
|
|
V_pfsyncstats.pfsyncs_hdrops++;
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (offset + sizeof(*ph) > m->m_len) {
|
|
|
|
if (m_pullup(m, offset + sizeof(*ph)) == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_hdrops++;
|
|
|
|
return;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
ph = (struct pfsync_header *)((char *)ip + offset);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
/* verify the version */
|
|
|
|
if (ph->version != PFSYNC_VERSION) {
|
2011-06-28 11:57:25 +00:00
|
|
|
V_pfsyncstats.pfsyncs_badver++;
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#if 0
|
|
|
|
if (pfsync_input_hmac(m, offset) != 0) {
|
|
|
|
/* XXX stats */
|
2004-06-16 23:24:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
/* Cheaper to grab this now than having to mess with mbufs later */
|
2011-06-28 11:57:25 +00:00
|
|
|
pkt.ip = ip;
|
|
|
|
pkt.src = ip->ip_src;
|
|
|
|
pkt.flags = 0;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
|
|
|
|
#else
|
|
|
|
if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
|
|
|
|
#endif
|
|
|
|
pkt.flags |= PFSYNC_SI_CKSUM;
|
|
|
|
|
|
|
|
offset += sizeof(*ph);
|
|
|
|
for (;;) {
|
|
|
|
m_copydata(m, offset, sizeof(subh), (caddr_t)&subh);
|
|
|
|
offset += sizeof(subh);
|
|
|
|
|
|
|
|
if (subh.action >= PFSYNC_ACT_MAX) {
|
|
|
|
V_pfsyncstats.pfsyncs_badact++;
|
|
|
|
goto done;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
rv = (*pfsync_acts[subh.action])(&pkt, m, offset,
|
|
|
|
ntohs(subh.count));
|
|
|
|
if (rv == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
offset += rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
m_freem(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct pfsync_clr *clr;
|
|
|
|
struct mbuf *mp;
|
|
|
|
int len = sizeof(*clr) * count;
|
|
|
|
int i, offp;
|
|
|
|
|
|
|
|
struct pf_state *st, *nexts;
|
|
|
|
struct pf_state_key *sk, *nextsk;
|
|
|
|
struct pf_state_item *si;
|
|
|
|
u_int32_t creatorid;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
clr = (struct pfsync_clr *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
creatorid = clr[i].creatorid;
|
|
|
|
|
|
|
|
if (clr[i].ifname[0] == '\0') {
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
for (st = RB_MIN(pf_state_tree_id, &V_tree_id);
|
|
|
|
st; st = nexts) {
|
|
|
|
nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st);
|
|
|
|
#else
|
2005-05-03 16:43:32 +00:00
|
|
|
for (st = RB_MIN(pf_state_tree_id, &tree_id);
|
|
|
|
st; st = nexts) {
|
2007-07-03 12:16:07 +00:00
|
|
|
nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2005-05-03 16:43:32 +00:00
|
|
|
if (st->creatorid == creatorid) {
|
2011-06-28 11:57:25 +00:00
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
2007-07-03 12:16:07 +00:00
|
|
|
pf_unlink_state(st);
|
2005-05-03 16:43:32 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-06-28 11:57:25 +00:00
|
|
|
if (pfi_kif_get(clr[i].ifname) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* XXX correct? */
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl);
|
|
|
|
#else
|
|
|
|
for (sk = RB_MIN(pf_state_tree, &pf_statetbl);
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
sk; sk = nextsk) {
|
|
|
|
nextsk = RB_NEXT(pf_state_tree,
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
&V_pf_statetbl, sk);
|
|
|
|
#else
|
|
|
|
&pf_statetbl, sk);
|
|
|
|
#endif
|
|
|
|
TAILQ_FOREACH(si, &sk->states, entry) {
|
|
|
|
if (si->s->creatorid == creatorid) {
|
|
|
|
SET(si->s->state_flags,
|
|
|
|
PFSTATE_NOSYNC);
|
|
|
|
pf_unlink_state(si->s);
|
|
|
|
}
|
2005-05-03 16:43:32 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct mbuf *mp;
|
|
|
|
struct pfsync_state *sa, *sp;
|
|
|
|
int len = sizeof(*sp) * count;
|
|
|
|
int i, offp;
|
|
|
|
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
sa = (struct pfsync_state *)(mp->m_data + offp);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splsoftnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
sp = &sa[i];
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/* check for invalid values */
|
|
|
|
if (sp->timeout >= PFTM_MAX ||
|
|
|
|
sp->src.state > PF_TCPS_PROXY_DST ||
|
|
|
|
sp->dst.state > PF_TCPS_PROXY_DST ||
|
|
|
|
sp->direction > PF_OUT ||
|
|
|
|
(sp->af != AF_INET && sp->af != AF_INET6)) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync_input: PFSYNC5_ACT_INS: "
|
|
|
|
"invalid value\n");
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
V_pfsyncstats.pfsyncs_badval++;
|
|
|
|
continue;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
if (pfsync_state_import(sp, pkt->flags) == ENOMEM) {
|
|
|
|
/* drop out, but process the rest of the actions */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct pfsync_ins_ack *ia, *iaa;
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state *st;
|
|
|
|
|
|
|
|
struct mbuf *mp;
|
|
|
|
int len = count * sizeof(*ia);
|
|
|
|
int offp, i;
|
|
|
|
int s;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
iaa = (struct pfsync_ins_ack *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
ia = &iaa[i];
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bcopy(&ia->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = ia->creatorid;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
pfsync_deferred(st, 0);
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
2004-06-16 23:24:02 +00:00
|
|
|
/*
|
2011-06-28 11:57:25 +00:00
|
|
|
* XXX this is not yet implemented, but we know the size of the
|
|
|
|
* message so we can skip it.
|
2004-06-16 23:24:02 +00:00
|
|
|
*/
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
return (count * sizeof(struct pfsync_ins_ack));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src,
|
|
|
|
struct pfsync_state_peer *dst)
|
|
|
|
{
|
|
|
|
int sfail = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The state should never go backwards except
|
|
|
|
* for syn-proxy states. Neither should the
|
|
|
|
* sequence window slide backwards.
|
|
|
|
*/
|
|
|
|
if (st->src.state > src->state &&
|
|
|
|
(st->src.state < PF_TCPS_PROXY_SRC ||
|
|
|
|
src->state >= PF_TCPS_PROXY_SRC))
|
|
|
|
sfail = 1;
|
|
|
|
else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))
|
|
|
|
sfail = 3;
|
|
|
|
else if (st->dst.state > dst->state) {
|
|
|
|
/* There might still be useful
|
|
|
|
* information about the src state here,
|
|
|
|
* so import that part of the update,
|
|
|
|
* then "fail" so we send the updated
|
|
|
|
* state back to the peer who is missing
|
|
|
|
* our what we know. */
|
|
|
|
pf_state_peer_ntoh(src, &st->src);
|
|
|
|
/* XXX do anything with timeouts? */
|
|
|
|
sfail = 7;
|
|
|
|
} else if (st->dst.state >= TCPS_SYN_SENT &&
|
|
|
|
SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))
|
|
|
|
sfail = 4;
|
|
|
|
|
|
|
|
return (sfail);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct pfsync_state *sa, *sp;
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state_key *sk;
|
|
|
|
struct pf_state *st;
|
|
|
|
int sfail;
|
|
|
|
|
|
|
|
struct mbuf *mp;
|
|
|
|
int len = count * sizeof(*sp);
|
|
|
|
int offp, i;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
sa = (struct pfsync_state *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
sp = &sa[i];
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/* check for invalid values */
|
|
|
|
if (sp->timeout >= PFTM_MAX ||
|
|
|
|
sp->src.state > PF_TCPS_PROXY_DST ||
|
|
|
|
sp->dst.state > PF_TCPS_PROXY_DST) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync_input: PFSYNC_ACT_UPD: "
|
|
|
|
"invalid value\n");
|
|
|
|
}
|
|
|
|
V_pfsyncstats.pfsyncs_badval++;
|
|
|
|
continue;
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bcopy(sp->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = sp->creatorid;
|
|
|
|
|
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL) {
|
|
|
|
/* insert the update */
|
|
|
|
if (pfsync_state_import(sp, 0))
|
|
|
|
V_pfsyncstats.pfsyncs_badstate++;
|
|
|
|
continue;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
pfsync_deferred(st, 1);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
sk = st->key[PF_SK_WIRE]; /* XXX right one? */
|
|
|
|
sfail = 0;
|
|
|
|
if (sk->proto == IPPROTO_TCP)
|
|
|
|
sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst);
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Non-TCP protocol state machine always go
|
|
|
|
* forwards
|
|
|
|
*/
|
|
|
|
if (st->src.state > sp->src.state)
|
|
|
|
sfail = 5;
|
|
|
|
else if (st->dst.state > sp->dst.state)
|
|
|
|
sfail = 6;
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sfail) {
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC) {
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync: %s stale update (%d)"
|
|
|
|
" id: %016llx creatorid: %08x\n",
|
|
|
|
(sfail < 7 ? "ignoring" : "partial"),
|
|
|
|
sfail, betoh64(st->id),
|
|
|
|
ntohl(st->creatorid));
|
2005-05-03 16:43:32 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
V_pfsyncstats.pfsyncs_stale++;
|
|
|
|
|
|
|
|
pfsync_update_state(st);
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
continue;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
|
|
|
|
pf_state_peer_ntoh(&sp->src, &st->src);
|
|
|
|
pf_state_peer_ntoh(&sp->dst, &st->dst);
|
|
|
|
st->expire = ntohl(sp->expire) + time_second;
|
|
|
|
st->timeout = sp->timeout;
|
2011-12-22 19:05:58 +00:00
|
|
|
st->pfsync_time = time_uptime;
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct pfsync_upd_c *ua, *up;
|
|
|
|
struct pf_state_key *sk;
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state *st;
|
|
|
|
|
|
|
|
int len = count * sizeof(*up);
|
|
|
|
int sfail;
|
|
|
|
|
|
|
|
struct mbuf *mp;
|
|
|
|
int offp, i;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
ua = (struct pfsync_upd_c *)(mp->m_data + offp);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splsoftnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
up = &ua[i];
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/* check for invalid values */
|
|
|
|
if (up->timeout >= PFTM_MAX ||
|
|
|
|
up->src.state > PF_TCPS_PROXY_DST ||
|
|
|
|
up->dst.state > PF_TCPS_PROXY_DST) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync_input: "
|
|
|
|
"PFSYNC_ACT_UPD_C: "
|
|
|
|
"invalid value\n");
|
|
|
|
}
|
|
|
|
V_pfsyncstats.pfsyncs_badval++;
|
|
|
|
continue;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bcopy(&up->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = up->creatorid;
|
|
|
|
|
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL) {
|
|
|
|
/* We don't have this state. Ask for it. */
|
|
|
|
pfsync_request_update(id_key.creatorid, id_key.id);
|
|
|
|
continue;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
pfsync_deferred(st, 1);
|
|
|
|
|
|
|
|
sk = st->key[PF_SK_WIRE]; /* XXX right one? */
|
|
|
|
sfail = 0;
|
|
|
|
if (sk->proto == IPPROTO_TCP)
|
|
|
|
sfail = pfsync_upd_tcp(st, &up->src, &up->dst);
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Non-TCP protocol state machine always go forwards
|
|
|
|
*/
|
|
|
|
if (st->src.state > up->src.state)
|
|
|
|
sfail = 5;
|
|
|
|
else if (st->dst.state > up->dst.state)
|
|
|
|
sfail = 6;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
if (sfail) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC) {
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync: ignoring stale update "
|
|
|
|
"(%d) id: %016llx "
|
|
|
|
"creatorid: %08x\n", sfail,
|
|
|
|
betoh64(st->id),
|
|
|
|
ntohl(st->creatorid));
|
|
|
|
}
|
|
|
|
V_pfsyncstats.pfsyncs_stale++;
|
|
|
|
|
|
|
|
pfsync_update_state(st);
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pfsync_alloc_scrub_memory(&up->dst, &st->dst);
|
|
|
|
pf_state_peer_ntoh(&up->src, &st->src);
|
|
|
|
pf_state_peer_ntoh(&up->dst, &st->dst);
|
|
|
|
st->expire = ntohl(up->expire) + time_second;
|
|
|
|
st->timeout = up->timeout;
|
2011-12-22 19:05:58 +00:00
|
|
|
st->pfsync_time = time_uptime;
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct pfsync_upd_req *ur, *ura;
|
|
|
|
struct mbuf *mp;
|
|
|
|
int len = count * sizeof(*ur);
|
|
|
|
int i, offp;
|
|
|
|
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state *st;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
ura = (struct pfsync_upd_req *)(mp->m_data + offp);
|
|
|
|
|
2012-01-11 14:19:04 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
ur = &ura[i];
|
|
|
|
|
|
|
|
bcopy(&ur->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = ur->creatorid;
|
|
|
|
|
|
|
|
if (id_key.id == 0 && id_key.creatorid == 0)
|
|
|
|
pfsync_bulk_start();
|
|
|
|
else {
|
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badstate++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_NOSYNC))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pfsync_update_state_req(st);
|
|
|
|
}
|
|
|
|
}
|
2012-01-11 14:19:04 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct mbuf *mp;
|
|
|
|
struct pfsync_state *sa, *sp;
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state *st;
|
|
|
|
int len = count * sizeof(*sp);
|
|
|
|
int offp, i;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
sa = (struct pfsync_state *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
sp = &sa[i];
|
|
|
|
|
|
|
|
bcopy(sp->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = sp->creatorid;
|
|
|
|
|
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badstate++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
pf_unlink_state(st);
|
|
|
|
}
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
struct mbuf *mp;
|
|
|
|
struct pfsync_del_c *sa, *sp;
|
|
|
|
struct pf_state_cmp id_key;
|
|
|
|
struct pf_state *st;
|
|
|
|
int len = count * sizeof(*sp);
|
|
|
|
int offp, i;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
sa = (struct pfsync_del_c *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
sp = &sa[i];
|
|
|
|
|
|
|
|
bcopy(&sp->id, &id_key.id, sizeof(id_key.id));
|
|
|
|
id_key.creatorid = sp->creatorid;
|
|
|
|
|
|
|
|
st = pf_find_state_byid(&id_key);
|
|
|
|
if (st == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badstate++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
pf_unlink_state(st);
|
|
|
|
}
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 09:34:40 +00:00
|
|
|
PF_UNLOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
struct pfsync_bus *bus;
|
|
|
|
struct mbuf *mp;
|
|
|
|
int len = count * sizeof(*bus);
|
|
|
|
int offp;
|
|
|
|
|
|
|
|
/* If we're not waiting for a bulk update, who cares. */
|
|
|
|
if (sc->sc_ureq_sent == 0)
|
|
|
|
return (len);
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
bus = (struct pfsync_bus *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
switch (bus->status) {
|
|
|
|
case PFSYNC_BUS_START:
|
|
|
|
#ifdef __FreeBSD__
|
2011-12-22 18:56:27 +00:00
|
|
|
callout_reset(&sc->sc_bulkfail_tmo, 4 * hz +
|
2011-12-24 00:23:27 +00:00
|
|
|
V_pf_pool_limits[PF_LIMIT_STATES].limit /
|
2012-01-07 14:39:45 +00:00
|
|
|
((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) /
|
2011-12-22 18:56:27 +00:00
|
|
|
sizeof(struct pfsync_state)),
|
|
|
|
pfsync_bulk_fail, V_pfsyncif);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
2011-12-22 18:56:27 +00:00
|
|
|
timeout_add(&sc->sc_bulkfail_tmo, 4 * hz +
|
2011-06-28 11:57:25 +00:00
|
|
|
pf_pool_limits[PF_LIMIT_STATES].limit /
|
2011-12-22 18:56:27 +00:00
|
|
|
((sc->sc_if.if_mtu - PFSYNC_MINPKT) /
|
|
|
|
sizeof(struct pfsync_state)));
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#endif
|
|
|
|
printf("pfsync: received bulk update start\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PFSYNC_BUS_END:
|
|
|
|
if (time_uptime - ntohl(bus->endtime) >=
|
|
|
|
sc->sc_ureq_sent) {
|
|
|
|
/* that's it, we're happy */
|
|
|
|
sc->sc_ureq_sent = 0;
|
|
|
|
sc->sc_bulk_tries = 0;
|
|
|
|
timeout_del(&sc->sc_bulkfail_tmo);
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
if (!sc->pfsync_sync_ok && carp_demote_adj_p)
|
|
|
|
(*carp_demote_adj_p)(-V_pfsync_carp_adj,
|
|
|
|
"pfsync bulk done");
|
|
|
|
sc->pfsync_sync_ok = 1;
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#if NCARP > 0
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!pfsync_sync_ok)
|
|
|
|
carp_group_demote_adj(&sc->sc_if, -1);
|
|
|
|
#endif
|
|
|
|
pfsync_sync_ok = 1;
|
2005-05-03 16:43:32 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync: received valid "
|
|
|
|
"bulk update end\n");
|
|
|
|
} else {
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#endif
|
|
|
|
printf("pfsync: received invalid "
|
|
|
|
"bulk update end: bad timestamp\n");
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
int len = count * sizeof(struct pfsync_tdb);
|
|
|
|
|
|
|
|
#if defined(IPSEC)
|
|
|
|
struct pfsync_tdb *tp;
|
|
|
|
struct mbuf *mp;
|
|
|
|
int offp;
|
|
|
|
int i;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
mp = m_pulldown(m, offset, len, &offp);
|
|
|
|
if (mp == NULL) {
|
|
|
|
V_pfsyncstats.pfsyncs_badlen++;
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
tp = (struct pfsync_tdb *)(mp->m_data + offp);
|
|
|
|
|
|
|
|
s = splsoftnet();
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
pfsync_update_net_tdb(&tp[i]);
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(IPSEC)
|
|
|
|
/* Update an in-kernel tdb. Silently fail if no tdb is found. */
|
|
|
|
void
|
|
|
|
pfsync_update_net_tdb(struct pfsync_tdb *pt)
|
|
|
|
{
|
|
|
|
struct tdb *tdb;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
/* check for invalid values */
|
|
|
|
if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
|
|
|
|
(pt->dst.sa.sa_family != AF_INET &&
|
|
|
|
pt->dst.sa.sa_family != AF_INET6))
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
s = spltdb();
|
|
|
|
tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
|
|
|
|
if (tdb) {
|
|
|
|
pt->rpl = ntohl(pt->rpl);
|
|
|
|
pt->cur_bytes = betoh64(pt->cur_bytes);
|
|
|
|
|
|
|
|
/* Neither replay nor byte counter should ever decrease. */
|
|
|
|
if (pt->rpl < tdb->tdb_rpl ||
|
|
|
|
pt->cur_bytes < tdb->tdb_cur_bytes) {
|
|
|
|
splx(s);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
tdb->tdb_rpl = pt->rpl;
|
|
|
|
tdb->tdb_cur_bytes = pt->cur_bytes;
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
|
|
|
return;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bad:
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#endif
|
|
|
|
printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
|
|
|
|
"invalid value\n");
|
|
|
|
V_pfsyncstats.pfsyncs_badstate++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
/* check if we are at the right place in the packet */
|
|
|
|
if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof))
|
|
|
|
V_pfsyncstats.pfsyncs_badact++;
|
|
|
|
|
|
|
|
/* we're done. free and let the caller return */
|
|
|
|
m_freem(m);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
|
|
|
|
{
|
|
|
|
V_pfsyncstats.pfsyncs_badact++;
|
|
|
|
|
|
|
|
m_freem(m);
|
|
|
|
return (-1);
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct route *rt)
|
|
|
|
#else
|
|
|
|
struct rtentry *rt)
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
|
|
|
m_freem(m);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
|
|
pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|
|
|
{
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifndef __FreeBSD__
|
|
|
|
struct proc *p = curproc;
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
struct pfsync_softc *sc = ifp->if_softc;
|
|
|
|
struct ifreq *ifr = (struct ifreq *)data;
|
2004-06-16 23:24:02 +00:00
|
|
|
struct ip_moptions *imo = &sc->sc_imo;
|
|
|
|
struct pfsyncreq pfsyncr;
|
|
|
|
struct ifnet *sifp;
|
2011-06-28 11:57:25 +00:00
|
|
|
struct ip *ip;
|
2004-06-16 23:24:02 +00:00
|
|
|
int s, error;
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
2011-06-28 11:57:25 +00:00
|
|
|
#if 0
|
2004-02-26 02:04:28 +00:00
|
|
|
case SIOCSIFADDR:
|
|
|
|
case SIOCAIFADDR:
|
|
|
|
case SIOCSIFDSTADDR:
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
case SIOCSIFFLAGS:
|
2005-08-09 11:59:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2004-02-26 02:04:28 +00:00
|
|
|
if (ifp->if_flags & IFF_UP)
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
2004-02-26 02:04:28 +00:00
|
|
|
else
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
2005-08-09 11:59:02 +00:00
|
|
|
#else
|
|
|
|
if (ifp->if_flags & IFF_UP)
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
else
|
|
|
|
ifp->if_flags &= ~IFF_RUNNING;
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
break;
|
|
|
|
case SIOCSIFMTU:
|
2012-01-07 14:39:45 +00:00
|
|
|
if (!sc->sc_sync_if ||
|
|
|
|
ifr->ifr_mtu <= PFSYNC_MINPKT ||
|
|
|
|
ifr->ifr_mtu > sc->sc_sync_if->if_mtu)
|
2004-02-26 02:04:28 +00:00
|
|
|
return (EINVAL);
|
2011-06-28 11:57:25 +00:00
|
|
|
if (ifr->ifr_mtu < ifp->if_mtu) {
|
|
|
|
s = splnet();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_LOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_sendout();
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
ifp->if_mtu = ifr->ifr_mtu;
|
2004-02-26 02:04:28 +00:00
|
|
|
break;
|
2004-06-16 23:24:02 +00:00
|
|
|
case SIOCGETPFSYNC:
|
|
|
|
bzero(&pfsyncr, sizeof(pfsyncr));
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_sync_if) {
|
2005-05-03 16:43:32 +00:00
|
|
|
strlcpy(pfsyncr.pfsyncr_syncdev,
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_sync_if->if_xname, IFNAMSIZ);
|
|
|
|
}
|
2005-05-03 16:43:32 +00:00
|
|
|
pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
|
2004-06-16 23:24:02 +00:00
|
|
|
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
|
2011-06-28 11:57:25 +00:00
|
|
|
return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)));
|
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
case SIOCSETPFSYNC:
|
|
|
|
#ifdef __FreeBSD__
|
2006-11-06 13:42:10 +00:00
|
|
|
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
|
|
|
if ((error = suser(p, p->p_acflag)) != 0)
|
|
|
|
#endif
|
|
|
|
return (error);
|
|
|
|
if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
|
|
|
|
return (error);
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
2005-05-03 16:43:32 +00:00
|
|
|
if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
|
2006-06-14 11:11:54 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
|
|
|
|
#else
|
2005-05-03 16:43:32 +00:00
|
|
|
sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
|
2006-06-14 11:11:54 +00:00
|
|
|
#endif
|
2005-05-03 16:43:32 +00:00
|
|
|
else
|
|
|
|
sc->sc_sync_peer.s_addr =
|
|
|
|
pfsyncr.pfsyncr_syncpeer.s_addr;
|
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
if (pfsyncr.pfsyncr_maxupdates > 255)
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
{
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
return (EINVAL);
|
|
|
|
#ifdef __FreeBSD__
|
2007-07-03 12:16:07 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
|
|
|
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
|
|
|
|
|
2005-05-03 16:43:32 +00:00
|
|
|
if (pfsyncr.pfsyncr_syncdev[0] == 0) {
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_sync_if = NULL;
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
2012-01-09 08:50:22 +00:00
|
|
|
if (imo->imo_membership)
|
|
|
|
pfsync_multicast_cleanup(sc);
|
|
|
|
#else
|
2005-05-03 16:43:32 +00:00
|
|
|
if (imo->imo_num_memberships > 0) {
|
2011-06-28 11:57:25 +00:00
|
|
|
in_delmulti(imo->imo_membership[
|
|
|
|
--imo->imo_num_memberships]);
|
2005-05-03 16:43:32 +00:00
|
|
|
imo->imo_multicast_ifp = NULL;
|
|
|
|
}
|
2012-01-09 08:50:22 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-05-03 16:43:32 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2007-07-03 12:16:07 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
|
2004-06-16 23:24:02 +00:00
|
|
|
return (EINVAL);
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
s = splnet();
|
2005-02-09 19:29:13 +00:00
|
|
|
#ifdef __FreeBSD__
|
2007-07-03 12:16:07 +00:00
|
|
|
if (sifp->if_mtu < sc->sc_ifp->if_mtu ||
|
2005-02-09 19:29:13 +00:00
|
|
|
#else
|
2004-06-16 23:24:02 +00:00
|
|
|
if (sifp->if_mtu < sc->sc_if.if_mtu ||
|
2005-02-09 19:29:13 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
(sc->sc_sync_if != NULL &&
|
|
|
|
sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
|
2004-06-16 23:24:02 +00:00
|
|
|
sifp->if_mtu < MCLBYTES - sizeof(struct ip))
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_sendout();
|
|
|
|
sc->sc_sync_if = sifp;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
if (imo->imo_membership) {
|
2007-07-03 12:16:07 +00:00
|
|
|
PF_UNLOCK();
|
2012-01-09 08:50:22 +00:00
|
|
|
pfsync_multicast_cleanup(sc);
|
2007-07-03 12:16:07 +00:00
|
|
|
PF_LOCK();
|
2012-01-09 08:50:22 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (imo->imo_num_memberships > 0) {
|
|
|
|
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
|
2004-06-16 23:24:02 +00:00
|
|
|
imo->imo_multicast_ifp = NULL;
|
|
|
|
}
|
2012-01-09 08:50:22 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2006-06-14 11:11:54 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
if (sc->sc_sync_if &&
|
2006-06-14 11:11:54 +00:00
|
|
|
sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
|
2012-01-09 08:50:22 +00:00
|
|
|
PF_UNLOCK();
|
|
|
|
error = pfsync_multicast_setup(sc);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
PF_LOCK();
|
|
|
|
}
|
2006-06-14 11:11:54 +00:00
|
|
|
#else
|
2012-01-09 08:50:22 +00:00
|
|
|
if (sc->sc_sync_if &&
|
2005-05-03 16:43:32 +00:00
|
|
|
sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
|
2004-06-16 23:24:02 +00:00
|
|
|
struct in_addr addr;
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) {
|
|
|
|
sc->sc_sync_if = NULL;
|
2005-05-03 16:43:32 +00:00
|
|
|
splx(s);
|
|
|
|
return (EADDRNOTAVAIL);
|
|
|
|
}
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
addr.s_addr = INADDR_PFSYNC_GROUP;
|
2005-05-03 16:43:32 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
if ((imo->imo_membership[0] =
|
2011-06-28 11:57:25 +00:00
|
|
|
in_addmulti(&addr, sc->sc_sync_if)) == NULL) {
|
|
|
|
sc->sc_sync_if = NULL;
|
2004-06-16 23:24:02 +00:00
|
|
|
splx(s);
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
imo->imo_num_memberships++;
|
2011-06-28 11:57:25 +00:00
|
|
|
imo->imo_multicast_ifp = sc->sc_sync_if;
|
2004-06-16 23:24:02 +00:00
|
|
|
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
|
|
|
|
imo->imo_multicast_loop = 0;
|
2005-05-03 16:43:32 +00:00
|
|
|
}
|
2012-01-09 08:50:22 +00:00
|
|
|
#endif /* !__FreeBSD__ */
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
ip = &sc->sc_template;
|
|
|
|
bzero(ip, sizeof(*ip));
|
|
|
|
ip->ip_v = IPVERSION;
|
|
|
|
ip->ip_hl = sizeof(sc->sc_template) >> 2;
|
|
|
|
ip->ip_tos = IPTOS_LOWDELAY;
|
|
|
|
/* len and id are set later */
|
2011-10-21 11:11:18 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
ip->ip_off = IP_DF;
|
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
ip->ip_off = htons(IP_DF);
|
2011-10-21 11:11:18 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
ip->ip_ttl = PFSYNC_DFLTTL;
|
|
|
|
ip->ip_p = IPPROTO_PFSYNC;
|
|
|
|
ip->ip_src.s_addr = INADDR_ANY;
|
|
|
|
ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
|
|
|
|
|
|
|
|
if (sc->sc_sync_if) {
|
2004-06-16 23:24:02 +00:00
|
|
|
/* Request a full state table update. */
|
|
|
|
sc->sc_ureq_sent = time_uptime;
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
if (sc->pfsync_sync_ok && carp_demote_adj_p)
|
|
|
|
(*carp_demote_adj_p)(V_pfsync_carp_adj,
|
|
|
|
"pfsync bulk start");
|
|
|
|
sc->pfsync_sync_ok = 0;
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#if NCARP > 0
|
2005-05-03 16:43:32 +00:00
|
|
|
if (pfsync_sync_ok)
|
2011-06-28 11:57:25 +00:00
|
|
|
carp_group_demote_adj(&sc->sc_if, 1);
|
|
|
|
#endif
|
|
|
|
pfsync_sync_ok = 0;
|
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#endif
|
|
|
|
printf("pfsync: requesting bulk update\n");
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-23 15:10:15 +00:00
|
|
|
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
|
|
|
|
pfsync_bulk_fail, V_pfsyncif);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
|
|
|
|
#endif
|
|
|
|
pfsync_request_update(0, 0);
|
|
|
|
}
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (ENOTTY);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_out_state(struct pf_state *st, struct mbuf *m, int offset)
|
|
|
|
{
|
|
|
|
struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset);
|
|
|
|
|
|
|
|
pfsync_state_export(sp, st);
|
|
|
|
|
|
|
|
return (sizeof(*sp));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset)
|
|
|
|
{
|
|
|
|
struct pfsync_ins_ack *iack =
|
|
|
|
(struct pfsync_ins_ack *)(m->m_data + offset);
|
|
|
|
|
|
|
|
iack->id = st->id;
|
|
|
|
iack->creatorid = st->creatorid;
|
|
|
|
|
|
|
|
return (sizeof(*iack));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset)
|
|
|
|
{
|
|
|
|
struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset);
|
|
|
|
|
2012-03-08 09:20:00 +00:00
|
|
|
bzero(up, sizeof(*up));
|
2011-06-28 11:57:25 +00:00
|
|
|
up->id = st->id;
|
|
|
|
pf_state_peer_hton(&st->src, &up->src);
|
|
|
|
pf_state_peer_hton(&st->dst, &up->dst);
|
|
|
|
up->creatorid = st->creatorid;
|
|
|
|
|
|
|
|
up->expire = pf_state_expires(st);
|
|
|
|
if (up->expire <= time_second)
|
|
|
|
up->expire = htonl(0);
|
|
|
|
else
|
|
|
|
up->expire = htonl(up->expire - time_second);
|
|
|
|
up->timeout = st->timeout;
|
|
|
|
|
|
|
|
return (sizeof(*up));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_out_del(struct pf_state *st, struct mbuf *m, int offset)
|
|
|
|
{
|
|
|
|
struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset);
|
|
|
|
|
|
|
|
dp->id = st->id;
|
|
|
|
dp->creatorid = st->creatorid;
|
|
|
|
|
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
|
|
|
|
return (sizeof(*dp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_drop(struct pfsync_softc *sc)
|
|
|
|
{
|
|
|
|
struct pf_state *st;
|
|
|
|
struct pfsync_upd_req_item *ur;
|
|
|
|
#ifdef notyet
|
|
|
|
struct tdb *t;
|
|
|
|
#endif
|
|
|
|
int q;
|
|
|
|
|
|
|
|
for (q = 0; q < PFSYNC_S_COUNT; q++) {
|
|
|
|
if (TAILQ_EMPTY(&sc->sc_qs[q]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
|
|
|
|
#ifdef PFSYNC_DEBUG
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
KASSERT(st->sync_state == q,
|
2012-01-11 14:24:03 +00:00
|
|
|
("%s: st->sync_state == q",
|
2011-06-28 11:57:25 +00:00
|
|
|
__FUNCTION__));
|
|
|
|
#else
|
|
|
|
KASSERT(st->sync_state == q);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
st->sync_state = PFSYNC_S_NONE;
|
|
|
|
}
|
|
|
|
TAILQ_INIT(&sc->sc_qs[q]);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
|
|
|
|
TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
|
|
|
|
pool_put(&sc->sc_pool, ur);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->sc_plus = NULL;
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
|
|
|
|
TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry)
|
|
|
|
CLR(t->tdb_flags, TDBF_PFSYNC);
|
|
|
|
|
|
|
|
TAILQ_INIT(&sc->sc_tdb_q);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sc->sc_len = PFSYNC_MINPKT;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2012-01-11 18:34:57 +00:00
|
|
|
void pfsync_sendout()
|
|
|
|
{
|
|
|
|
pfsync_sendout1(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pfsync_sendout1(int schedswi)
|
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
2012-01-11 18:34:57 +00:00
|
|
|
void
|
|
|
|
pfsync_sendout(void)
|
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
#if NBPFILTER > 0
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
#else
|
|
|
|
struct ifnet *ifp = &sc->sc_if;
|
|
|
|
#endif
|
|
|
|
#endif
|
2011-08-17 13:02:50 +00:00
|
|
|
struct mbuf *m;
|
2011-06-28 11:57:25 +00:00
|
|
|
struct ip *ip;
|
|
|
|
struct pfsync_header *ph;
|
|
|
|
struct pfsync_subheader *subh;
|
|
|
|
struct pf_state *st;
|
|
|
|
struct pfsync_upd_req_item *ur;
|
|
|
|
#ifdef notyet
|
|
|
|
struct tdb *t;
|
|
|
|
#endif
|
|
|
|
int offset;
|
|
|
|
int q, count = 0;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_NET);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (sc == NULL || sc->sc_len == PFSYNC_MINPKT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#if NBPFILTER > 0
|
|
|
|
if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) {
|
|
|
|
#else
|
|
|
|
if (sc->sc_sync_if == NULL) {
|
|
|
|
#endif
|
|
|
|
pfsync_drop(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2012-01-17 12:14:26 +00:00
|
|
|
m = m_get2(M_NOWAIT, MT_DATA, M_PKTHDR, max_linkhdr + sc->sc_len);
|
|
|
|
if (m == NULL) {
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_ifp->if_oerrors++;
|
2012-01-17 12:14:26 +00:00
|
|
|
V_pfsyncstats.pfsyncs_onomem++;
|
|
|
|
return;
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
2012-01-17 12:14:26 +00:00
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (m == NULL) {
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_if.if_oerrors++;
|
2012-01-17 12:14:26 +00:00
|
|
|
pfsyncstats.pfsyncs_onomem++;
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_drop(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_linkhdr + sc->sc_len > MHLEN) {
|
|
|
|
MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len);
|
|
|
|
if (!ISSET(m->m_flags, M_EXT)) {
|
|
|
|
m_free(m);
|
|
|
|
sc->sc_if.if_oerrors++;
|
2012-01-17 12:14:26 +00:00
|
|
|
pfsyncstats.pfsyncs_onomem++;
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_drop(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-01-17 12:14:26 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
m->m_data += max_linkhdr;
|
|
|
|
m->m_len = m->m_pkthdr.len = sc->sc_len;
|
|
|
|
|
|
|
|
/* build the ip header */
|
|
|
|
ip = (struct ip *)m->m_data;
|
|
|
|
bcopy(&sc->sc_template, ip, sizeof(*ip));
|
|
|
|
offset = sizeof(*ip);
|
|
|
|
|
2011-10-21 11:11:18 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
ip->ip_len = m->m_pkthdr.len;
|
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
ip->ip_len = htons(m->m_pkthdr.len);
|
2011-10-21 11:11:18 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
ip->ip_id = htons(ip_randomid());
|
|
|
|
|
|
|
|
/* build the pfsync header */
|
|
|
|
ph = (struct pfsync_header *)(m->m_data + offset);
|
|
|
|
bzero(ph, sizeof(*ph));
|
|
|
|
offset += sizeof(*ph);
|
|
|
|
|
|
|
|
ph->version = PFSYNC_VERSION;
|
|
|
|
ph->len = htons(sc->sc_len - sizeof(*ip));
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
|
|
|
|
#else
|
|
|
|
bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* walk the queues */
|
|
|
|
for (q = 0; q < PFSYNC_S_COUNT; q++) {
|
|
|
|
if (TAILQ_EMPTY(&sc->sc_qs[q]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
subh = (struct pfsync_subheader *)(m->m_data + offset);
|
|
|
|
offset += sizeof(*subh);
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
|
|
|
|
#ifdef PFSYNC_DEBUG
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
KASSERT(st->sync_state == q,
|
|
|
|
("%s: st->sync_state == q",
|
|
|
|
__FUNCTION__));
|
|
|
|
#else
|
|
|
|
KASSERT(st->sync_state == q);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
offset += pfsync_qs[q].write(st, m, offset);
|
|
|
|
st->sync_state = PFSYNC_S_NONE;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
TAILQ_INIT(&sc->sc_qs[q]);
|
|
|
|
|
|
|
|
bzero(subh, sizeof(*subh));
|
|
|
|
subh->action = pfsync_qs[q].action;
|
|
|
|
subh->count = htons(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) {
|
|
|
|
subh = (struct pfsync_subheader *)(m->m_data + offset);
|
|
|
|
offset += sizeof(*subh);
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
|
|
|
|
TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
|
|
|
|
|
|
|
|
bcopy(&ur->ur_msg, m->m_data + offset,
|
|
|
|
sizeof(ur->ur_msg));
|
|
|
|
offset += sizeof(ur->ur_msg);
|
|
|
|
|
|
|
|
pool_put(&sc->sc_pool, ur);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
bzero(subh, sizeof(*subh));
|
|
|
|
subh->action = PFSYNC_ACT_UPD_REQ;
|
|
|
|
subh->count = htons(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* has someone built a custom region for us to add? */
|
|
|
|
if (sc->sc_plus != NULL) {
|
|
|
|
bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen);
|
|
|
|
offset += sc->sc_pluslen;
|
|
|
|
|
|
|
|
sc->sc_plus = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
|
|
|
|
subh = (struct pfsync_subheader *)(m->m_data + offset);
|
|
|
|
offset += sizeof(*subh);
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) {
|
|
|
|
offset += pfsync_out_tdb(t, m, offset);
|
|
|
|
CLR(t->tdb_flags, TDBF_PFSYNC);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
TAILQ_INIT(&sc->sc_tdb_q);
|
|
|
|
|
|
|
|
bzero(subh, sizeof(*subh));
|
|
|
|
subh->action = PFSYNC_ACT_TDB;
|
|
|
|
subh->count = htons(count);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
subh = (struct pfsync_subheader *)(m->m_data + offset);
|
|
|
|
offset += sizeof(*subh);
|
|
|
|
|
|
|
|
bzero(subh, sizeof(*subh));
|
|
|
|
subh->action = PFSYNC_ACT_EOF;
|
|
|
|
subh->count = htons(1);
|
|
|
|
|
|
|
|
/* XXX write checksum in EOF here */
|
|
|
|
|
|
|
|
/* we're done, let's put it on the wire */
|
|
|
|
#if NBPFILTER > 0
|
|
|
|
if (ifp->if_bpf) {
|
|
|
|
m->m_data += sizeof(*ip);
|
|
|
|
m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip);
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
BPF_MTAP(ifp, m);
|
|
|
|
#else
|
|
|
|
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
|
|
|
|
#endif
|
|
|
|
m->m_data -= sizeof(*ip);
|
|
|
|
m->m_len = m->m_pkthdr.len = sc->sc_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_sync_if == NULL) {
|
|
|
|
sc->sc_len = PFSYNC_MINPKT;
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
sc->sc_ifp->if_opackets++;
|
|
|
|
sc->sc_ifp->if_obytes += m->m_pkthdr.len;
|
2011-10-23 14:59:54 +00:00
|
|
|
sc->sc_len = PFSYNC_MINPKT;
|
|
|
|
|
2012-01-11 18:34:57 +00:00
|
|
|
if (!_IF_QFULL(&sc->sc_ifp->if_snd))
|
|
|
|
_IF_ENQUEUE(&sc->sc_ifp->if_snd, m);
|
|
|
|
else {
|
|
|
|
m_freem(m);
|
|
|
|
sc->sc_ifp->if_snd.ifq_drops++;
|
|
|
|
}
|
|
|
|
if (schedswi)
|
|
|
|
swi_sched(V_pfsync_swi_cookie, 0);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
sc->sc_if.if_opackets++;
|
|
|
|
sc->sc_if.if_obytes += m->m_pkthdr.len;
|
|
|
|
|
|
|
|
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0)
|
2011-10-23 14:59:54 +00:00
|
|
|
pfsyncstats.pfsyncs_opackets++;
|
2011-06-28 11:57:25 +00:00
|
|
|
else
|
2011-10-23 14:59:54 +00:00
|
|
|
pfsyncstats.pfsyncs_oerrors++;
|
|
|
|
|
|
|
|
/* start again */
|
|
|
|
sc->sc_len = PFSYNC_MINPKT;
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_insert_state(struct pf_state *st)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_SOFTNET);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) ||
|
|
|
|
st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) {
|
|
|
|
SET(st->state_flags, PFSTATE_NOSYNC);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef PFSYNC_DEBUG
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
KASSERT(st->sync_state == PFSYNC_S_NONE,
|
|
|
|
("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
|
|
|
|
#else
|
|
|
|
KASSERT(st->sync_state == PFSYNC_S_NONE);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (sc->sc_len == PFSYNC_MINPKT)
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
|
|
|
|
V_pfsyncif);
|
|
|
|
#else
|
|
|
|
timeout_add_sec(&sc->sc_tmo, 1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pfsync_q_ins(st, PFSYNC_S_INS);
|
|
|
|
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
else
|
|
|
|
st->sync_updates = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int defer = 10;
|
|
|
|
|
|
|
|
int
|
|
|
|
pfsync_defer(struct pf_state *st, struct mbuf *m)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
struct pfsync_deferral *pd;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_SOFTNET);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (sc->sc_deferred >= 128)
|
|
|
|
pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
|
|
|
|
|
|
|
|
pd = pool_get(&sc->sc_pool, M_NOWAIT);
|
|
|
|
if (pd == NULL)
|
|
|
|
return (0);
|
|
|
|
sc->sc_deferred++;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
m->m_flags |= M_SKIP_FIREWALL;
|
|
|
|
#else
|
|
|
|
m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
|
|
|
|
#endif
|
|
|
|
SET(st->state_flags, PFSTATE_ACK);
|
|
|
|
|
|
|
|
pd->pd_st = st;
|
|
|
|
pd->pd_m = m;
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry);
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
callout_init(&pd->pd_tmo, CALLOUT_MPSAFE);
|
|
|
|
callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo,
|
|
|
|
pd);
|
|
|
|
#else
|
|
|
|
timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd);
|
|
|
|
timeout_add(&pd->pd_tmo, defer);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_undefer(struct pfsync_deferral *pd, int drop)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
int s;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_SOFTNET);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry);
|
|
|
|
sc->sc_deferred--;
|
|
|
|
|
|
|
|
CLR(pd->pd_st->state_flags, PFSTATE_ACK);
|
|
|
|
timeout_del(&pd->pd_tmo); /* bah */
|
|
|
|
if (drop)
|
|
|
|
m_freem(pd->pd_m);
|
|
|
|
else {
|
|
|
|
s = splnet();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
/* XXX: use pf_defered?! */
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
|
|
|
ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0,
|
|
|
|
(void *)NULL, (void *)NULL);
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
pool_put(&sc->sc_pool, pd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_defer_tmo(void *arg)
|
|
|
|
{
|
|
|
|
#if defined(__FreeBSD__) && defined(VIMAGE)
|
|
|
|
struct pfsync_deferral *pd = arg;
|
|
|
|
#endif
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splsoftnet();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
|
|
|
pfsync_undefer(arg, 0);
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
#endif
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_deferred(struct pf_state *st, int drop)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
struct pfsync_deferral *pd;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) {
|
|
|
|
if (pd->pd_st == st) {
|
|
|
|
pfsync_undefer(pd, drop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic("pfsync_send_deferred: unable to find deferred state");
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int pfsync_upds = 0;
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_update_state(struct pf_state *st)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
int sync = 0;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_SOFTNET);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (sc == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
pfsync_deferred(st, 0);
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
|
|
|
|
if (st->sync_state != PFSYNC_S_NONE)
|
|
|
|
pfsync_q_del(st);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_len == PFSYNC_MINPKT)
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
|
|
|
|
V_pfsyncif);
|
|
|
|
#else
|
|
|
|
timeout_add_sec(&sc->sc_tmo, 1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (st->sync_state) {
|
|
|
|
case PFSYNC_S_UPD_C:
|
|
|
|
case PFSYNC_S_UPD:
|
|
|
|
case PFSYNC_S_INS:
|
|
|
|
/* we're already handling it */
|
|
|
|
|
2011-12-22 19:09:55 +00:00
|
|
|
if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) {
|
|
|
|
st->sync_updates++;
|
|
|
|
if (st->sync_updates >= sc->sc_maxupdates)
|
|
|
|
sync = 1;
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PFSYNC_S_IACK:
|
|
|
|
pfsync_q_del(st);
|
|
|
|
case PFSYNC_S_NONE:
|
|
|
|
pfsync_q_ins(st, PFSYNC_S_UPD_C);
|
|
|
|
st->sync_updates = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic("pfsync_update_state: unexpected sync state %d",
|
|
|
|
st->sync_state);
|
|
|
|
}
|
|
|
|
|
2011-12-22 19:05:58 +00:00
|
|
|
if (sync || (time_uptime - st->pfsync_time) < 2) {
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_upds++;
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_request_update(u_int32_t creatorid, u_int64_t id)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
|
|
|
struct pfsync_upd_req_item *item;
|
|
|
|
size_t nlen = sizeof(struct pfsync_upd_req);
|
|
|
|
int s;
|
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/*
|
|
|
|
* this code does nothing to prevent multiple update requests for the
|
|
|
|
* same state being generated.
|
|
|
|
*/
|
|
|
|
|
|
|
|
item = pool_get(&sc->sc_pool, PR_NOWAIT);
|
|
|
|
if (item == NULL) {
|
|
|
|
/* XXX stats */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->ur_msg.id = id;
|
|
|
|
item->ur_msg.creatorid = creatorid;
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&sc->sc_upd_req_list))
|
|
|
|
nlen += sizeof(struct pfsync_subheader);
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2012-01-07 14:39:45 +00:00
|
|
|
if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) {
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
|
|
|
|
#endif
|
|
|
|
s = splnet();
|
|
|
|
pfsync_sendout();
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
nlen = sizeof(struct pfsync_subheader) +
|
|
|
|
sizeof(struct pfsync_upd_req);
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry);
|
|
|
|
sc->sc_len += nlen;
|
|
|
|
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_update_state_req(struct pf_state *st)
|
|
|
|
{
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL)
|
|
|
|
panic("pfsync_update_state_req: nonexistant instance");
|
|
|
|
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
|
|
|
|
if (st->sync_state != PFSYNC_S_NONE)
|
|
|
|
pfsync_q_del(st);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (st->sync_state) {
|
|
|
|
case PFSYNC_S_UPD_C:
|
|
|
|
case PFSYNC_S_IACK:
|
|
|
|
pfsync_q_del(st);
|
|
|
|
case PFSYNC_S_NONE:
|
|
|
|
pfsync_q_ins(st, PFSYNC_S_UPD);
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case PFSYNC_S_INS:
|
|
|
|
case PFSYNC_S_UPD:
|
|
|
|
case PFSYNC_S_DEL:
|
|
|
|
/* we're already handling it */
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic("pfsync_update_state_req: unexpected sync state %d",
|
|
|
|
st->sync_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pfsync_delete_state(struct pf_state *st)
|
|
|
|
{
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2005-05-03 16:43:32 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
splassert(IPL_SOFTNET);
|
2005-05-03 16:43:32 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
if (sc == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_ACK))
|
|
|
|
pfsync_deferred(st, 1);
|
|
|
|
if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
|
|
|
|
if (st->sync_state != PFSYNC_S_NONE)
|
|
|
|
pfsync_q_del(st);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_len == PFSYNC_MINPKT)
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
|
|
|
|
V_pfsyncif);
|
|
|
|
#else
|
|
|
|
timeout_add_sec(&sc->sc_tmo, 1);
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
switch (st->sync_state) {
|
|
|
|
case PFSYNC_S_INS:
|
|
|
|
/* we never got to tell the world so just forget about it */
|
|
|
|
pfsync_q_del(st);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case PFSYNC_S_UPD_C:
|
|
|
|
case PFSYNC_S_UPD:
|
|
|
|
case PFSYNC_S_IACK:
|
|
|
|
pfsync_q_del(st);
|
|
|
|
/* FALLTHROUGH to putting it on the del list */
|
|
|
|
|
|
|
|
case PFSYNC_S_NONE:
|
|
|
|
pfsync_q_ins(st, PFSYNC_S_DEL);
|
|
|
|
return;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2004-02-26 02:04:28 +00:00
|
|
|
default:
|
2011-06-28 11:57:25 +00:00
|
|
|
panic("pfsync_delete_state: unexpected sync state %d",
|
|
|
|
st->sync_state);
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_clear_states(u_int32_t creatorid, const char *ifname)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct {
|
|
|
|
struct pfsync_subheader subh;
|
|
|
|
struct pfsync_clr clr;
|
|
|
|
} __packed r;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2005-02-09 19:29:13 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-10-19 10:16:42 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2005-02-09 19:29:13 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
splassert(IPL_SOFTNET);
|
2005-02-09 19:29:13 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
if (sc == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bzero(&r, sizeof(r));
|
|
|
|
|
|
|
|
r.subh.action = PFSYNC_ACT_CLR;
|
|
|
|
r.subh.count = htons(1);
|
|
|
|
|
|
|
|
strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname));
|
|
|
|
r.clr.creatorid = creatorid;
|
|
|
|
|
|
|
|
pfsync_send_plus(&r, sizeof(r));
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
void
|
|
|
|
pfsync_q_ins(struct pf_state *st, int q)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2005-02-09 19:29:13 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2005-02-09 19:29:13 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2005-02-09 19:29:13 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
size_t nlen = pfsync_qs[q].len;
|
|
|
|
int s;
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
KASSERT(st->sync_state == PFSYNC_S_NONE,
|
|
|
|
("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
|
|
|
|
#else
|
|
|
|
KASSERT(st->sync_state == PFSYNC_S_NONE);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#if 1 || defined(PFSYNC_DEBUG)
|
|
|
|
if (sc->sc_len < PFSYNC_MINPKT)
|
2005-02-09 19:29:13 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
panic("pfsync pkt len is too low %zu", sc->sc_len);
|
2005-02-09 19:29:13 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
panic("pfsync pkt len is too low %d", sc->sc_len);
|
2005-02-09 19:29:13 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
if (TAILQ_EMPTY(&sc->sc_qs[q]))
|
|
|
|
nlen += sizeof(struct pfsync_subheader);
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) {
|
2004-02-26 02:34:12 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splnet();
|
|
|
|
pfsync_sendout();
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->sc_len += nlen;
|
|
|
|
TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
|
|
|
|
st->sync_state = q;
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
void
|
|
|
|
pfsync_q_del(struct pf_state *st)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
int q = st->sync_state;
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2006-06-14 11:11:54 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-11 14:24:03 +00:00
|
|
|
KASSERT(st->sync_state != PFSYNC_S_NONE,
|
2011-06-28 11:57:25 +00:00
|
|
|
("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__));
|
2006-06-14 11:11:54 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
KASSERT(st->sync_state != PFSYNC_S_NONE);
|
2006-06-14 11:11:54 +00:00
|
|
|
#endif
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_len -= pfsync_qs[q].len;
|
|
|
|
TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
|
|
|
|
st->sync_state = PFSYNC_S_NONE;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (TAILQ_EMPTY(&sc->sc_qs[q]))
|
|
|
|
sc->sc_len -= sizeof(struct pfsync_subheader);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
void
|
|
|
|
pfsync_update_tdb(struct tdb *t, int output)
|
|
|
|
{
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
size_t nlen = sizeof(struct pfsync_tdb);
|
|
|
|
int s;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL)
|
|
|
|
return;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) {
|
|
|
|
if (TAILQ_EMPTY(&sc->sc_tdb_q))
|
|
|
|
nlen += sizeof(struct pfsync_subheader);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
|
|
|
|
s = splnet();
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_sendout();
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_UNLOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
nlen = sizeof(struct pfsync_subheader) +
|
|
|
|
sizeof(struct pfsync_tdb);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_len += nlen;
|
|
|
|
TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry);
|
|
|
|
SET(t->tdb_flags, TDBF_PFSYNC);
|
|
|
|
t->tdb_updates = 0;
|
|
|
|
} else {
|
|
|
|
if (++t->tdb_updates >= sc->sc_maxupdates)
|
|
|
|
schednetisr(NETISR_PFSYNC);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (output)
|
|
|
|
SET(t->tdb_flags, TDBF_PFSYNC_RPL);
|
|
|
|
else
|
|
|
|
CLR(t->tdb_flags, TDBF_PFSYNC_RPL);
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
void
|
|
|
|
pfsync_delete_tdb(struct tdb *t)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC))
|
|
|
|
return;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_len -= sizeof(struct pfsync_tdb);
|
|
|
|
TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry);
|
|
|
|
CLR(t->tdb_flags, TDBF_PFSYNC);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (TAILQ_EMPTY(&sc->sc_tdb_q))
|
|
|
|
sc->sc_len -= sizeof(struct pfsync_subheader);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset)
|
2004-06-16 23:24:02 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset);
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bzero(ut, sizeof(*ut));
|
|
|
|
ut->spi = t->tdb_spi;
|
|
|
|
bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst));
|
|
|
|
/*
|
|
|
|
* When a failover happens, the master's rpl is probably above
|
|
|
|
* what we see here (we may be up to a second late), so
|
|
|
|
* increase it a bit for outbound tdbs to manage most such
|
|
|
|
* situations.
|
|
|
|
*
|
|
|
|
* For now, just add an offset that is likely to be larger
|
|
|
|
* than the number of packets we can see in one second. The RFC
|
|
|
|
* just says the next packet must have a higher seq value.
|
|
|
|
*
|
|
|
|
* XXX What is a good algorithm for this? We could use
|
|
|
|
* a rate-determined increase, but to know it, we would have
|
|
|
|
* to extend struct tdb.
|
|
|
|
* XXX pt->rpl can wrap over MAXINT, but if so the real tdb
|
|
|
|
* will soon be replaced anyway. For now, just don't handle
|
|
|
|
* this edge case.
|
|
|
|
*/
|
|
|
|
#define RPL_INCR 16384
|
|
|
|
ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ?
|
|
|
|
RPL_INCR : 0));
|
|
|
|
ut->cur_bytes = htobe64(t->tdb_cur_bytes);
|
|
|
|
ut->sproto = t->tdb_sproto;
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
return (sizeof(*ut));
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_bulk_start(void)
|
2004-02-26 02:04:28 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
|
|
|
#else
|
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
|
|
|
#endif
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
|
|
#else
|
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync: received bulk update request\n");
|
|
|
|
|
2011-10-23 15:15:17 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-11 14:19:04 +00:00
|
|
|
PF_LOCK_ASSERT();
|
2011-10-23 15:15:17 +00:00
|
|
|
if (TAILQ_EMPTY(&V_state_list))
|
|
|
|
#else
|
|
|
|
if (TAILQ_EMPTY(&state_list))
|
|
|
|
#endif
|
|
|
|
pfsync_bulk_status(PFSYNC_BUS_END);
|
|
|
|
else {
|
|
|
|
sc->sc_ureq_received = time_uptime;
|
|
|
|
if (sc->sc_bulk_next == NULL)
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
sc->sc_bulk_next = TAILQ_FIRST(&V_state_list);
|
|
|
|
#else
|
|
|
|
sc->sc_bulk_next = TAILQ_FIRST(&state_list);
|
|
|
|
#endif
|
2012-01-07 12:40:45 +00:00
|
|
|
sc->sc_bulk_last = sc->sc_bulk_next;
|
2011-10-23 15:15:17 +00:00
|
|
|
|
2012-01-07 12:40:45 +00:00
|
|
|
pfsync_bulk_status(PFSYNC_BUS_START);
|
|
|
|
callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc);
|
2011-10-23 15:15:17 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_bulk_update(void *arg)
|
2007-07-03 12:16:07 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = arg;
|
|
|
|
struct pf_state *st = sc->sc_bulk_next;
|
|
|
|
int i = 0;
|
2007-07-03 12:16:07 +00:00
|
|
|
int s;
|
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splsoftnet();
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-10-23 15:15:17 +00:00
|
|
|
for (;;) {
|
2011-06-28 11:57:25 +00:00
|
|
|
if (st->sync_state == PFSYNC_S_NONE &&
|
|
|
|
st->timeout < PFTM_MAX &&
|
|
|
|
st->pfsync_time <= sc->sc_ureq_received) {
|
|
|
|
pfsync_update_state_req(st);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
st = TAILQ_NEXT(st, entry_list);
|
|
|
|
if (st == NULL)
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
st = TAILQ_FIRST(&V_state_list);
|
|
|
|
#else
|
|
|
|
st = TAILQ_FIRST(&state_list);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2011-10-23 15:15:17 +00:00
|
|
|
if (st == sc->sc_bulk_last) {
|
|
|
|
/* we're done */
|
|
|
|
sc->sc_bulk_next = NULL;
|
|
|
|
sc->sc_bulk_last = NULL;
|
|
|
|
pfsync_bulk_status(PFSYNC_BUS_END);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) <
|
|
|
|
#else
|
|
|
|
if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) <
|
|
|
|
#endif
|
|
|
|
sizeof(struct pfsync_state)) {
|
|
|
|
/* we've filled a packet */
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_bulk_next = st;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
callout_reset(&sc->sc_bulk_tmo, 1,
|
2011-10-23 15:08:18 +00:00
|
|
|
pfsync_bulk_update, sc);
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
timeout_add(&sc->sc_bulk_tmo, 1);
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-10-23 15:15:17 +00:00
|
|
|
break;
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
2011-10-23 15:15:17 +00:00
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
CURVNET_RESTORE();
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
splx(s);
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_bulk_status(u_int8_t status)
|
2004-06-16 23:24:02 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct {
|
|
|
|
struct pfsync_subheader subh;
|
|
|
|
struct pfsync_bus bus;
|
|
|
|
} __packed r;
|
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
bzero(&r, sizeof(r));
|
|
|
|
|
|
|
|
r.subh.action = PFSYNC_ACT_BUS;
|
|
|
|
r.subh.count = htons(1);
|
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
r.bus.creatorid = V_pf_status.hostid;
|
|
|
|
#else
|
|
|
|
r.bus.creatorid = pf_status.hostid;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received);
|
|
|
|
r.bus.status = status;
|
|
|
|
|
|
|
|
pfsync_send_plus(&r, sizeof(r));
|
2004-06-16 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_bulk_fail(void *arg)
|
2004-06-16 23:24:02 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = arg;
|
2004-06-16 23:24:02 +00:00
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
|
2011-06-28 11:57:25 +00:00
|
|
|
/* Try again */
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
|
|
|
|
pfsync_bulk_fail, V_pfsyncif);
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_request_update(0, 0);
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_UNLOCK();
|
2004-06-16 23:24:02 +00:00
|
|
|
} else {
|
|
|
|
/* Pretend like the transfer was ok */
|
|
|
|
sc->sc_ureq_sent = 0;
|
|
|
|
sc->sc_bulk_tries = 0;
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
if (!sc->pfsync_sync_ok && carp_demote_adj_p)
|
|
|
|
(*carp_demote_adj_p)(-V_pfsync_carp_adj,
|
|
|
|
"pfsync bulk fail");
|
|
|
|
sc->pfsync_sync_ok = 1;
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
Restore a feature that was present in 5.x and 6.x, and was cleared in
7.x, 8.x and 9.x with pf(4) imports: pfsync(4) should suppress CARP
preemption, while it is running its bulk update.
However, reimplement the feature in more elegant manner, that is
partially inspired by newer OpenBSD:
- Rename term "suppression" to "demotion", to match with OpenBSD.
- Keep a global demotion factor, that can be raised by several
conditions, for now these are:
- interface goes down
- carp(4) has problems with ip_output() or ip6_output()
- pfsync performs bulk update
- Unlike in OpenBSD the demotion factor isn't a counter, but
is actual value added to advskew. The adjustment values for
particular error conditions are also configurable, and their
defaults are maximum advskew value, so a single failure bumps
demotion to maximum. This is for POLA compatibility, and should
satisfy most users.
- Demotion factor is a writable sysctl, so user can do
foot shooting, if he desires to.
2011-12-20 13:53:31 +00:00
|
|
|
#if NCARP > 0
|
2011-06-28 11:57:25 +00:00
|
|
|
if (!pfsync_sync_ok)
|
2007-07-03 12:16:07 +00:00
|
|
|
carp_group_demote_adj(&sc->sc_if, -1);
|
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_sync_ok = 1;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (pf_status.debug >= PF_DEBUG_MISC)
|
2004-12-10 17:42:47 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
printf("pfsync: failed to receive bulk update\n");
|
|
|
|
}
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
CURVNET_RESTORE();
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
void
|
|
|
|
pfsync_send_plus(void *plus, size_t pluslen)
|
|
|
|
{
|
2006-12-29 13:59:50 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2006-12-29 13:59:50 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-02-26 02:04:28 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
int s;
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-10-19 13:13:56 +00:00
|
|
|
PF_LOCK_ASSERT();
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) {
|
2007-07-03 12:16:07 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc->sc_len + pluslen > sc->sc_if.if_mtu) {
|
2007-07-03 12:16:07 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splnet();
|
|
|
|
pfsync_sendout();
|
|
|
|
splx(s);
|
|
|
|
}
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
sc->sc_plus = plus;
|
|
|
|
sc->sc_len += (sc->sc_pluslen = pluslen);
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splnet();
|
|
|
|
pfsync_sendout();
|
|
|
|
splx(s);
|
2007-07-03 12:16:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_up(void)
|
2007-07-03 12:16:07 +00:00
|
|
|
{
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING))
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING))
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
2011-06-28 11:57:25 +00:00
|
|
|
return (0);
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2004-06-16 23:24:02 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
int
|
|
|
|
pfsync_state_in_use(struct pf_state *st)
|
|
|
|
{
|
2004-06-16 23:24:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = V_pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#else
|
2011-06-28 11:57:25 +00:00
|
|
|
struct pfsync_softc *sc = pfsyncif;
|
2004-06-16 23:24:02 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
if (sc == NULL)
|
|
|
|
return (0);
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-10-23 15:15:17 +00:00
|
|
|
if (st->sync_state != PFSYNC_S_NONE ||
|
|
|
|
st == sc->sc_bulk_next ||
|
|
|
|
st == sc->sc_bulk_last)
|
2011-06-28 11:57:25 +00:00
|
|
|
return (1);
|
2004-02-26 02:04:28 +00:00
|
|
|
|
2011-10-23 15:15:17 +00:00
|
|
|
return (0);
|
2004-02-26 02:04:28 +00:00
|
|
|
}
|
2004-02-26 02:34:12 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
u_int pfsync_ints;
|
|
|
|
u_int pfsync_tmos;
|
|
|
|
|
2007-07-03 12:16:07 +00:00
|
|
|
void
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_timeout(void *arg)
|
2007-07-03 12:16:07 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
#if defined(__FreeBSD__) && defined(VIMAGE)
|
|
|
|
struct pfsync_softc *sc = arg;
|
|
|
|
#endif
|
|
|
|
int s;
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_tmos++;
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
s = splnet();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_LOCK();
|
|
|
|
#endif
|
|
|
|
pfsync_sendout();
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
PF_UNLOCK();
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
splx(s);
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
/* this is a softnet/netisr handler */
|
|
|
|
void
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
pfsyncintr(void *arg)
|
2011-10-23 14:59:54 +00:00
|
|
|
{
|
|
|
|
struct pfsync_softc *sc = arg;
|
2011-10-27 09:47:00 +00:00
|
|
|
struct mbuf *m, *n;
|
2011-10-23 14:59:54 +00:00
|
|
|
|
|
|
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
|
|
|
pfsync_ints++;
|
|
|
|
|
2012-01-11 18:34:57 +00:00
|
|
|
PF_LOCK();
|
|
|
|
if (sc->sc_len > PFSYNC_MINPKT)
|
|
|
|
pfsync_sendout1(0);
|
|
|
|
_IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m);
|
|
|
|
PF_UNLOCK();
|
2011-10-27 09:47:00 +00:00
|
|
|
|
|
|
|
for (; m != NULL; m = n) {
|
2011-10-23 14:59:54 +00:00
|
|
|
|
2011-10-27 09:47:00 +00:00
|
|
|
n = m->m_nextpkt;
|
|
|
|
m->m_nextpkt = NULL;
|
2011-10-23 14:59:54 +00:00
|
|
|
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)
|
|
|
|
== 0)
|
|
|
|
V_pfsyncstats.pfsyncs_opackets++;
|
|
|
|
else
|
|
|
|
V_pfsyncstats.pfsyncs_oerrors++;
|
|
|
|
}
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
#else
|
|
|
|
pfsyncintr(void)
|
2007-07-03 12:16:07 +00:00
|
|
|
{
|
2011-06-28 11:57:25 +00:00
|
|
|
int s;
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_ints++;
|
|
|
|
|
|
|
|
s = splnet();
|
|
|
|
pfsync_sendout();
|
|
|
|
splx(s);
|
|
|
|
}
|
2011-10-23 14:59:54 +00:00
|
|
|
#endif
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
int
|
|
|
|
pfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
|
|
|
|
size_t newlen)
|
|
|
|
{
|
2007-07-03 12:16:07 +00:00
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
#ifdef notyet
|
|
|
|
/* All sysctl names at this level are terminal. */
|
|
|
|
if (namelen != 1)
|
|
|
|
return (ENOTDIR);
|
|
|
|
|
|
|
|
switch (name[0]) {
|
|
|
|
case PFSYNCCTL_STATS:
|
|
|
|
if (newp != NULL)
|
|
|
|
return (EPERM);
|
|
|
|
return (sysctl_struct(oldp, oldlenp, newp, newlen,
|
|
|
|
&V_pfsyncstats, sizeof(V_pfsyncstats)));
|
2007-07-03 12:16:07 +00:00
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
#endif
|
|
|
|
return (ENOPROTOOPT);
|
2007-07-03 12:16:07 +00:00
|
|
|
}
|
|
|
|
|
2004-03-17 21:11:02 +00:00
|
|
|
#ifdef __FreeBSD__
|
2012-01-09 08:50:22 +00:00
|
|
|
static int
|
|
|
|
pfsync_multicast_setup(struct pfsync_softc *sc)
|
2007-03-19 17:52:15 +00:00
|
|
|
{
|
2012-01-09 08:50:22 +00:00
|
|
|
struct ip_moptions *imo = &sc->sc_imo;
|
|
|
|
int error;
|
2007-03-19 17:52:15 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) {
|
|
|
|
sc->sc_sync_if = NULL;
|
|
|
|
return (EADDRNOTAVAIL);
|
|
|
|
}
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
imo->imo_membership = (struct in_multi **)malloc(
|
|
|
|
(sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC,
|
|
|
|
M_WAITOK | M_ZERO);
|
|
|
|
imo->imo_max_memberships = IP_MIN_MEMBERSHIPS;
|
|
|
|
imo->imo_multicast_vif = -1;
|
2007-03-19 17:52:15 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
if ((error = in_joingroup(sc->sc_sync_if, &sc->sc_sync_peer, NULL,
|
|
|
|
&imo->imo_membership[0])) != 0) {
|
|
|
|
free(imo->imo_membership, M_PFSYNC);
|
|
|
|
return (error);
|
2007-03-19 17:52:15 +00:00
|
|
|
}
|
2012-01-09 08:50:22 +00:00
|
|
|
imo->imo_num_memberships++;
|
|
|
|
imo->imo_multicast_ifp = sc->sc_sync_if;
|
|
|
|
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
|
|
|
|
imo->imo_multicast_loop = 0;
|
2007-03-19 17:52:15 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
return (0);
|
2007-03-19 17:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
static void
|
|
|
|
pfsync_multicast_cleanup(struct pfsync_softc *sc)
|
|
|
|
{
|
|
|
|
struct ip_moptions *imo = &sc->sc_imo;
|
|
|
|
|
|
|
|
in_leavegroup(imo->imo_membership[0], NULL);
|
|
|
|
free(imo->imo_membership, M_PFSYNC);
|
|
|
|
imo->imo_membership = NULL;
|
|
|
|
imo->imo_multicast_ifp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
extern struct domain inetdomain;
|
|
|
|
static struct protosw in_pfsync_protosw = {
|
2012-01-11 14:24:03 +00:00
|
|
|
.pr_type = SOCK_RAW,
|
|
|
|
.pr_domain = &inetdomain,
|
|
|
|
.pr_protocol = IPPROTO_PFSYNC,
|
|
|
|
.pr_flags = PR_ATOMIC|PR_ADDR,
|
|
|
|
.pr_input = pfsync_input,
|
|
|
|
.pr_output = (pr_output_t *)rip_output,
|
|
|
|
.pr_ctloutput = rip_ctloutput,
|
|
|
|
.pr_usrreqs = &rip_usrreqs
|
2012-01-09 08:50:22 +00:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2011-06-28 11:57:25 +00:00
|
|
|
static int
|
2012-01-09 08:50:22 +00:00
|
|
|
pfsync_init()
|
2005-06-10 17:23:49 +00:00
|
|
|
{
|
2012-01-09 08:50:22 +00:00
|
|
|
VNET_ITERATOR_DECL(vnet_iter);
|
2011-06-28 11:57:25 +00:00
|
|
|
int error = 0;
|
2005-06-10 17:23:49 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
VNET_LIST_RLOCK();
|
|
|
|
VNET_FOREACH(vnet_iter) {
|
|
|
|
CURVNET_SET(vnet_iter);
|
|
|
|
V_pfsync_cloner = pfsync_cloner;
|
|
|
|
V_pfsync_cloner_data = pfsync_cloner_data;
|
|
|
|
V_pfsync_cloner.ifc_data = &V_pfsync_cloner_data;
|
|
|
|
if_clone_attach(&V_pfsync_cloner);
|
|
|
|
error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif,
|
|
|
|
SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie);
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
if (error)
|
|
|
|
goto fail_locked;
|
|
|
|
}
|
|
|
|
VNET_LIST_RUNLOCK();
|
|
|
|
#ifdef INET
|
|
|
|
error = pf_proto_register(PF_INET, &in_pfsync_protosw);
|
2011-06-28 11:57:25 +00:00
|
|
|
if (error)
|
2012-01-09 08:50:22 +00:00
|
|
|
goto fail;
|
|
|
|
error = ipproto_register(IPPROTO_PFSYNC);
|
|
|
|
if (error) {
|
|
|
|
pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
#endif
|
2011-12-20 12:34:16 +00:00
|
|
|
PF_LOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_state_import_ptr = pfsync_state_import;
|
|
|
|
pfsync_up_ptr = pfsync_up;
|
|
|
|
pfsync_insert_state_ptr = pfsync_insert_state;
|
|
|
|
pfsync_update_state_ptr = pfsync_update_state;
|
|
|
|
pfsync_delete_state_ptr = pfsync_delete_state;
|
|
|
|
pfsync_clear_states_ptr = pfsync_clear_states;
|
|
|
|
pfsync_state_in_use_ptr = pfsync_state_in_use;
|
|
|
|
pfsync_defer_ptr = pfsync_defer;
|
2011-12-20 12:34:16 +00:00
|
|
|
PF_UNLOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
|
|
|
|
return (0);
|
2012-01-09 08:50:22 +00:00
|
|
|
|
|
|
|
fail:
|
|
|
|
VNET_LIST_RLOCK();
|
|
|
|
fail_locked:
|
|
|
|
VNET_FOREACH(vnet_iter) {
|
|
|
|
CURVNET_SET(vnet_iter);
|
|
|
|
if (V_pfsync_swi_cookie) {
|
|
|
|
swi_remove(V_pfsync_swi_cookie);
|
|
|
|
if_clone_detach(&V_pfsync_cloner);
|
|
|
|
}
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
}
|
|
|
|
VNET_LIST_RUNLOCK();
|
|
|
|
|
|
|
|
return (error);
|
2011-06-28 11:57:25 +00:00
|
|
|
}
|
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
static void
|
|
|
|
pfsync_uninit()
|
2011-06-28 11:57:25 +00:00
|
|
|
{
|
2012-01-09 08:50:22 +00:00
|
|
|
VNET_ITERATOR_DECL(vnet_iter);
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2011-12-20 12:34:16 +00:00
|
|
|
PF_LOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
pfsync_state_import_ptr = NULL;
|
|
|
|
pfsync_up_ptr = NULL;
|
|
|
|
pfsync_insert_state_ptr = NULL;
|
|
|
|
pfsync_update_state_ptr = NULL;
|
|
|
|
pfsync_delete_state_ptr = NULL;
|
|
|
|
pfsync_clear_states_ptr = NULL;
|
|
|
|
pfsync_state_in_use_ptr = NULL;
|
|
|
|
pfsync_defer_ptr = NULL;
|
2011-12-20 12:34:16 +00:00
|
|
|
PF_UNLOCK();
|
2011-06-28 11:57:25 +00:00
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
ipproto_unregister(IPPROTO_PFSYNC);
|
|
|
|
pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW);
|
|
|
|
VNET_LIST_RLOCK();
|
|
|
|
VNET_FOREACH(vnet_iter) {
|
|
|
|
CURVNET_SET(vnet_iter);
|
|
|
|
swi_remove(V_pfsync_swi_cookie);
|
|
|
|
if_clone_detach(&V_pfsync_cloner);
|
|
|
|
CURVNET_RESTORE();
|
|
|
|
}
|
|
|
|
VNET_LIST_RUNLOCK();
|
2005-06-10 17:23:49 +00:00
|
|
|
}
|
|
|
|
|
2004-02-26 02:34:12 +00:00
|
|
|
static int
|
|
|
|
pfsync_modevent(module_t mod, int type, void *data)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case MOD_LOAD:
|
2012-01-09 08:50:22 +00:00
|
|
|
error = pfsync_init();
|
|
|
|
break;
|
|
|
|
case MOD_QUIESCE:
|
|
|
|
/*
|
|
|
|
* Module should not be unloaded due to race conditions.
|
|
|
|
*/
|
|
|
|
error = EPERM;
|
2004-02-26 02:34:12 +00:00
|
|
|
break;
|
|
|
|
case MOD_UNLOAD:
|
2012-01-09 08:50:22 +00:00
|
|
|
pfsync_uninit();
|
2004-02-26 02:34:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-01-09 08:50:22 +00:00
|
|
|
return (error);
|
2004-02-26 02:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static moduledata_t pfsync_mod = {
|
|
|
|
"pfsync",
|
|
|
|
pfsync_modevent,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PFSYNC_MODVER 1
|
|
|
|
|
2012-01-09 12:06:02 +00:00
|
|
|
DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
|
2004-02-26 02:34:12 +00:00
|
|
|
MODULE_VERSION(pfsync, PFSYNC_MODVER);
|
2011-06-28 11:57:25 +00:00
|
|
|
MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER);
|
2004-02-26 02:34:12 +00:00
|
|
|
#endif /* __FreeBSD__ */
|