File:  [ELWIX - Embedded LightWeight unIX -] / fwsync / driver / fwsync_mod.c
Revision 1.9: download - view: text, annotated - select for diffs - revision graph
Fri Aug 26 14:47:36 2022 UTC (20 months, 1 week ago) by misho
Branches: MAIN
CVS tags: fwsync1_2, HEAD, FWSYNC1_1
version 1.1
 - adds list command

/*-
 * 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>