Building and Initializing wolfSentry for an application on FreeRTOS/lwIP
Building the wolfSentry library for FreeRTOS with lwIP and newlib-nano is supported directly by
the top level Makefile
. E.g., for an ARM Cortex M7, libwolfsentry.a
can be
built with
make HOST=arm-none-eabi EXTRA_CFLAGS='-mcpu=cortex-m7' RUNTIME=FreeRTOS-lwIP FREERTOS_TOP="$FREERTOS_TOP" LWIP_TOP="$LWIP_TOP"
FREERTOS_TOP
is the path to the top of the FreeRTOS distribution, with
FreeRTOS/Source
directly under it, and LWIP_TOP
is the path to the top of
the lwIP distribution, with src
directly under it.
The below code fragments can be added to a FreeRTOS application to enable wolfSentry with dynamically loaded policies (JSON). Many of the demonstrated code patterns are optional. The only calls that are indispensable are wolfsentry_init()
, wolfsentry_config_json_oneshot()
, and wolfsentry_install_lwip_filter_callbacks()
. Each of these also has API variants that give the user more control.
#define WOLFSENTRY_SOURCE_ID WOLFSENTRY_SOURCE_ID_USER_BASE
#define WOLFSENTRY_ERROR_ID_USER_APP_ERR0 (WOLFSENTRY_ERROR_ID_USER_BASE-1)
/* user-defined error IDs count down starting at WOLFSENTRY_ERROR_ID_USER_BASE (which is negative). */
#include <wolfsentry/wolfsentry_json.h>
#include <wolfsentry/wolfsentry_lwip.h>
static struct wolfsentry_context *wolfsentry_lwip_ctx = NULL;
static const struct wolfsentry_eventconfig demo_config = {
#ifdef WOLFSENTRY_HAVE_DESIGNATED_INITIALIZERS
.route_private_data_size = 64,
.route_private_data_alignment = 0, /* default alignment -- same as sizeof(void *). */
.max_connection_count = 10, /* by default, don't allow more than 10 simultaneous
* connections that match the same route.
*/
.derogatory_threshold_for_penaltybox = 4, /* after 4 derogatory events matching the same route,
* put the route in penalty box status.
*/
.penaltybox_duration = 300, /* keep routes in penalty box status for 5 minutes.
* denominated in seconds when passing to
* wolfsentry_init().
*/
.route_idle_time_for_purge = 0, /* 0 to disable -- autopurge doesn't usually make
* much sense as a default config.
*/
.flags = WOLFSENTRY_EVENTCONFIG_FLAG_COMMENDABLE_CLEARS_DEROGATORY, /* automatically clear
* derogatory count for a route when a commendable
* event matches the route.
*/
.route_flags_to_add_on_insert = 0,
.route_flags_to_clear_on_insert = 0,
.action_res_filter_bits_set = 0,
.action_res_filter_bits_unset = 0,
.action_res_bits_to_add = 0,
.action_res_bits_to_clear = 0
#else
64,
0,
10,
4,
300,
0,
WOLFSENTRY_EVENTCONFIG_FLAG_COMMENDABLE_CLEARS_DEROGATORY,
0,
0,
0,
0,
0,
0
#endif
};
/* This routine is to be called once by the application before any direct calls
* to lwIP -- i.e., before lwip_init() or tcpip_init().
*/
wolfsentry_errcode_t activate_wolfsentry_lwip(const char *json_config, int json_config_len)
{
wolfsentry_errcode_t ret;
char err_buf[512]; /* buffer for detailed error messages from
* wolfsentry_config_json_oneshot().
*/
/* Allocate a thread state struct on the stack. Note that the final
* semicolon is supplied by the macro definition, so that in single-threaded
* application builds this expands to nothing at all.
*/
WOLFSENTRY_THREAD_HEADER_DECLS
if (wolfsentry_lwip_ctx != NULL) {
printf("activate_wolfsentry_lwip() called multiple times.\n");
WOLFSENTRY_ERROR_RETURN(ALREADY);
}
#ifdef WOLFSENTRY_ERROR_STRINGS
/* Enable pretty-printing of the app source code filename for
* WOLFSENTRY_ERROR_FMT/WOLFSENTRY_ERROR_FMT_ARGS().
*/
ret = WOLFSENTRY_REGISTER_SOURCE();
WOLFSENTRY_RERETURN_IF_ERROR(ret);
/* Enable pretty-printing of an app-specific error code. */
ret = WOLFSENTRY_REGISTER_ERROR(USER_APP_ERR0, "failure in application code");
WOLFSENTRY_RERETURN_IF_ERROR(ret);
#endif
/* Initialize the thread state struct -- this sets the thread ID. */
WOLFSENTRY_THREAD_HEADER_INIT_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE);
/* Call the main wolfSentry initialization routine.
*
* WOLFSENTRY_CONTEXT_ARGS_OUT() is a macro that abstracts away
* conditionally passing the thread struct pointer to APIs that need it. If
* this is a single-threaded build (!defined(WOLFSENTRY_THREADSAFE)), then
* the thread arg is omitted entirely.
*
* WOLFSENTRY_CONTEXT_ARGS_OUT_EX() is a variant that allows the caller to
* supply the first arg explicitly, when "wolfsentry" is not the correct arg
* to pass. This is used here to pass a null pointer for the host platform
* interface ("hpi").
*/
ret = wolfsentry_init(
wolfsentry_build_settings,
WOLFSENTRY_CONTEXT_ARGS_OUT_EX(NULL /* hpi */),
&demo_config,
&wolfsentry_lwip_ctx);
if (ret < 0) {
printf("wolfsentry_init() failed: " WOLFSENTRY_ERROR_FMT "\n",
WOLFSENTRY_ERROR_FMT_ARGS(ret));
goto out;
}
/* Insert user-defined actions here, if any. */
ret = wolfsentry_action_insert(
WOLFSENTRY_CONTEXT_ARGS_OUT_EX(wolfsentry_lwip_ctx),
"my-action",
WOLFSENTRY_LENGTH_NULL_TERMINATED,
WOLFSENTRY_ACTION_FLAG_NONE,
my_action_handler,
NULL,
NULL);
if (ret < 0) {
printf("wolfsentry_action_insert() failed: " WOLFSENTRY_ERROR_FMT "\n",
WOLFSENTRY_ERROR_FMT_ARGS(ret));
goto out;
}
if (json_config) {
if (json_config_len < 0)
json_config_len = (int)strlen(json_config);
/* Do the initial load of the policy. */
ret = wolfsentry_config_json_oneshot(
WOLFSENTRY_CONTEXT_ARGS_OUT_EX(wolfsentry_lwip_ctx),
(unsigned char *)json_config,
(size_t)json_config_len,
WOLFSENTRY_CONFIG_LOAD_FLAG_NONE,
err_buf,
sizeof err_buf);
if (ret < 0) {
printf("wolfsentry_config_json_oneshot() failed: %s\n", err_buf);
goto out;
}
} /* else the application will need to set up the policy programmatically,
* or itself call wolfsentry_config_json_oneshot() or sibling APIs.
*/
/* Install lwIP callbacks. Once this call returns with success, all lwIP
* traffic designated for filtration by the mask arguments shown below will
* be subject to filtering (or other supplementary processing) according to
* the policy loaded above.
*
* Note that if a given protocol is gated out of LWIP, its mask argument
* must be passed as zero here, else the call will return
* IMPLEMENTATION_MISSING error will occur.
*
* The callback installation also registers a cleanup routine that will be
* called automatically by wolfsentry_shutdown().
*/
#define LWIP_ALL_EVENTS ( \
(1U << FILT_BINDING) | \
(1U << FILT_DISSOCIATE) | \
(1U << FILT_LISTENING) | \
(1U << FILT_STOP_LISTENING) | \
(1U << FILT_CONNECTING) | \
(1U << FILT_ACCEPTING) | \
(1U << FILT_CLOSED) | \
(1U << FILT_REMOTE_RESET) | \
(1U << FILT_RECEIVING) | \
(1U << FILT_SENDING) | \
(1U << FILT_ADDR_UNREACHABLE) | \
(1U << FILT_PORT_UNREACHABLE) | \
(1U << FILT_INBOUND_ERR) | \
(1U << FILT_OUTBOUND_ERR))
ret = wolfsentry_install_lwip_filter_callbacks(
WOLFSENTRY_CONTEXT_ARGS_OUT_EX(wolfsentry_lwip_ctx),
#if LWIP_ARP || LWIP_ETHERNET
LWIP_ALL_EVENTS, /* ethernet_mask */
#else
0,
#endif
#if LWIP_IPV4 || LWIP_IPV6
LWIP_ALL_EVENTS, /* ip_mask */
#else
0,
#endif
#if LWIP_ICMP || LWIP_ICMP6
LWIP_ALL_EVENTS, /* icmp_mask */
#else
0,
#endif
#if LWIP_TCP
LWIP_ALL_EVENTS, /* tcp_mask */
#else
0,
#endif
#if LWIP_UDP
LWIP_ALL_EVENTS /* udp_mask */
#else
0
#endif
);
if (ret < 0) {
printf("wolfsentry_install_lwip_filter_callbacks: "
WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(ret));
}
out:
if (ret < 0) {
/* Clean up if initialization failed. */
wolfsentry_errcode_t shutdown_ret =
wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry_lwip_ctx));
if (shutdown_ret < 0)
printf("wolfsentry_shutdown: "
WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(shutdown_ret));
}
WOLFSENTRY_THREAD_TAILER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE);
WOLFSENTRY_ERROR_RERETURN(ret);
}
/* to be called once by the application after any final calls to lwIP. */
wolfsentry_errcode_t shutdown_wolfsentry_lwip(void)
{
wolfsentry_errcode_t ret;
if (wolfsentry_lwip_ctx == NULL) {
printf("shutdown_wolfsentry_lwip() called before successful activation.\n");
return -1;
}
/* after successful shutdown, wolfsentry_lwip_ctx will once again be a null
* pointer as it was before init.
*/
ret = wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(&wolfsentry_lwip_ctx, NULL));
if (ret < 0) {
printf("wolfsentry_shutdown: "
WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(ret));
}
return ret;
}