/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2022 Michael Pounov <misho@elwix.org>, CloudSigma AG
*
* 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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.
*/
#include "fwsync.h"
MALLOC_DEFINE(M_FWSYNC, "fwsync_memory", "FWSync - memory");
static struct ipfw_sopt_handler soc[] = {
{ IP_FW_SYNC_XCONFIG, 0, HDIR_SET, fwsync_cfg },
{ IP_FW_SYNC_DESTROY, 0, HDIR_SET, fwsync_destroy },
{ IP_FW_SYNC_XGETCONFIG, 0, HDIR_GET, fwsync_get_cfg },
{ IP_FW_SYNC_LIST, 0, HDIR_GET, fwsync_list },
{ IP_FW_SYNC_START, 0, HDIR_SET, fwsync_start },
{ IP_FW_SYNC_STOP, 0, HDIR_SET, fwsync_stop },
};
static volatile int fwsync_hooked = 0;
struct fwsync_context fws_ctx = { 0 };
int fwsync_debug = DRV_DEBUG;
static struct sysctl_ctx_list fwsync_sysctl_ctx;
struct cfg_sync fws_cfg;
//static struct sysctl_oid *fws_sysctl_oid, *fws_sysctl_dir;
struct task fws_sndpkt_task;
struct taskqueue *fws_tq;
struct callout fws_co;
struct mtx fws_mtx_c, fws_mtx_e, fws_mtx_u, fws_mtx_n;
fwsync_sndpkt_t fwsync_sndpkt, fwsync_updpkt, fwsync_natpkt;
struct fws_acct fws_acct;
SYSCTL_NODE(_net_inet_ip, IFT_FWSYNC, fwsync, CTLFLAG_RW, 0, "IPFW Sync - Sync firewall states");
SYSCTL_INT(_net_inet_ip_fwsync, OID_AUTO, debug, CTLFLAG_RW, &fwsync_debug, 0, "Debug driver");
SYSCTL_NODE(_net_inet_ip_fwsync, IFT_FWSYNC_ACCT, acct, CTLFLAG_RD, 0, "IPFW Sync - Handled states");
SYSCTL_ULONG(_net_inet_ip_fwsync_acct, OID_AUTO, collector_states, CTLFLAG_RD, &fws_acct.states[0], 0, "Sent states to network");
SYSCTL_ULONG(_net_inet_ip_fwsync_acct, OID_AUTO, edge_states, CTLFLAG_RD, &fws_acct.states[1], 0, "Received states from network");
SYSCTL_ULONG(_net_inet_ip_fwsync_acct, OID_AUTO, collector_aliases, CTLFLAG_RD, &fws_acct.aliases[0], 0, "Sent aliases to network");
SYSCTL_ULONG(_net_inet_ip_fwsync_acct, OID_AUTO, edge_aliases, CTLFLAG_RD, &fws_acct.aliases[1], 0, "Received aliases from network");
static int
fws_fini(void *arg)
{
struct fws_sndpkt *p;
DTRACE();
if (!fwsync_hooked)
return EBUSY;
if (fws_cfg.cfg.on || fws_ctx.config) {
uprintf("Unable to unload ELWIX %s driver, cause you have active configuration.\n"
"Before unload driver flush configuration!\n", DRV_NAME);
return EBUSY;
}
IPFW_DEL_SOPT_HANDLER(1, soc);
callout_drain(&fws_co);
if (fws_tq) {
taskqueue_drain_all(fws_tq);
taskqueue_free(fws_tq);
}
mtx_lock(&fws_mtx_n);
while (!TAILQ_EMPTY(&fwsync_natpkt)) {
p = TAILQ_FIRST(&fwsync_natpkt);
TAILQ_REMOVE(&fwsync_natpkt, p, sp_next);
free(p, M_FWSYNC);
}
mtx_unlock(&fws_mtx_n);
mtx_lock(&fws_mtx_u);
while (!TAILQ_EMPTY(&fwsync_updpkt)) {
p = TAILQ_FIRST(&fwsync_updpkt);
TAILQ_REMOVE(&fwsync_updpkt, p, sp_next);
free(p, M_FWSYNC);
}
mtx_unlock(&fws_mtx_u);
mtx_lock(&fws_mtx_c);
while (!TAILQ_EMPTY(&fwsync_sndpkt)) {
p = TAILQ_FIRST(&fwsync_sndpkt);
TAILQ_REMOVE(&fwsync_sndpkt, p, sp_next);
free(p, M_FWSYNC);
}
mtx_unlock(&fws_mtx_c);
mtx_destroy(&fws_mtx_c);
mtx_destroy(&fws_mtx_e);
mtx_destroy(&fws_mtx_u);
mtx_destroy(&fws_mtx_n);
fwsync_hooked = 0;
/* sysctl context */
sysctl_ctx_free(&fwsync_sysctl_ctx);
uprintf("Unloaded ELWIX %s driver version %d ...\n", DRV_NAME, DRV_VERSION);
return 0;
}
static int
fws_shut(void *arg)
{
DTRACE();
fws_fini(arg);
return 0;
}
static int
fws_init(void *arg)
{
DTRACE();
if (fwsync_hooked)
return 0;
memset(&fws_cfg, 0, sizeof fws_cfg);
memset(&fws_ctx, 0, sizeof fws_ctx);
memset(&fws_acct, 0, sizeof fws_acct);
TAILQ_INIT(&fwsync_sndpkt);
TAILQ_INIT(&fwsync_updpkt);
TAILQ_INIT(&fwsync_natpkt);
/* mutexes */
mtx_init(&fws_mtx_n, "fwsync mtx alias", NULL, MTX_DEF);
mtx_init(&fws_mtx_u, "fwsync mtx dynamic", NULL, MTX_DEF);
mtx_init(&fws_mtx_e, "fwsync mtx edge", NULL, MTX_DEF);
mtx_init(&fws_mtx_c, "fwsync mtx collector", NULL, MTX_DEF);
/* taskqueue */
fws_tq = taskqueue_create("fwsync_tq", M_NOWAIT, taskqueue_thread_enqueue, &fws_tq);
if (!fws_tq) {
printf("Failed to allocate fwsync task queue\n");
mtx_destroy(&fws_mtx_c);
mtx_destroy(&fws_mtx_e);
return ENOMEM;
} else
taskqueue_start_threads(&fws_tq, 1, PI_NET, "fwsync tq");
TASK_INIT(&fws_sndpkt_task, 0, fwsync_sndpkt_handler, &fwsync_sndpkt);
/* callout */
callout_init_mtx(&fws_co, &fws_mtx_e, 0);
/* sysctl context */
sysctl_ctx_init(&fwsync_sysctl_ctx);
IPFW_ADD_SOPT_HANDLER(1, soc);
fwsync_hooked = 1;
uprintf("Loaded ELWIX %s driver version %d ...\n", DRV_NAME, DRV_VERSION);
return 0;
}
static int
fwsync_main(module_t m, int what, void *arg)
{
int ret = 0;
switch (what) {
case MOD_LOAD:
ret = fws_init(arg);
break;
case MOD_UNLOAD:
ret = fws_fini(arg);
break;
case MOD_SHUTDOWN:
ret = fws_shut(arg);
break;
case MOD_QUIESCE:
/* don't unload driver if there have configured driver */
if (fws_cfg.cfg.on || fws_ctx.config)
ret = EBUSY;
break;
default:
ret = EINVAL;
break;
}
return ret;
}
static moduledata_t fwsync_mod = {
"ipfw_sync",
fwsync_main,
NULL
};
DECLARE_MODULE(ipfw_sync, fwsync_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY);
MODULE_DEPEND(ipfw_sync, libalias, 1, 1, 1);
MODULE_DEPEND(ipfw_sync, ipfw, 3, 3, 3);
MODULE_VERSION(ipfw_sync, DRV_VERSION);
SYSINIT(fws_init, SI_SUB_PROTO_FIREWALL, (SI_ORDER_ANY - 128), fws_init, NULL);
SYSUNINIT(fws_fini, SI_SUB_PROTO_FIREWALL, (SI_ORDER_ANY - 128), fws_fini, NULL);
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>