Skip to content

Repo for the PacketLab pktmon tool to generate monitor programs

Notifications You must be signed in to change notification settings

CAIDA/pktlab-pktmon

Repository files navigation

PacketLab Monitor Builder (pktmon)

For building pktlab monitors!

Prerequisites

  • libpktlab with SSL support. This can be obtained by following the instructions in installing the PacketLab software package (from pre-built binaries or from source).
  • The latest release of WASI-SDK, where this link provides the instructions to install the WASI SDK (from pre-built binaries or from source).

WASI SDK is used to compile the monitor C code into a WebAssembly binary (i.e. the monitor binary), with the wasi-libc library support for the memory manipulation functions. We won't use any system calls provided by the wasi-libc due to security concerns.

Compile Monitor Instructions

Run pktmon.sh to compile the C code into a monitor binary.

The usage of the pktmon.sh script is as follows:

# You should have the C code named `<name-of-monitor>.c` in the current directory
# Default name of the monitor is "monitor", which needs `monitor.c` to be present in the current directory
bash pktmon.sh <path-to-pktlab-pkg> <path-to-wasi-sdk> <name-of-monitor(default to "monitor")>

For example, if the PacketLab software package is installed at the /opt/pktlab directory, WASI SDK is installed at the /opt/wasi-sdk directory, and you have a monitor C code named any_monitor.c, then you can run the following command:

bash pktmon.sh /opt/pktlab /opt/wasi-sdk any_monitor

This will generate a monitor binary named any_monitor.wasm in the current directory, and output the SHA256 digest of the monitor in the any_monitor.digest file.

You can then use ppksman from the pktlab Python3 package to sign a new exppriv or delpriv certificate with the monitor's digest, which you can then distribute with the compiled monitor to expermenters for them to use to contact your pktlab endpoint.

How to Write a Custom Monitor

Monitor Template

The template for the monitor is provided in the monitor.template.c file. You can start by copying the contents of this file into a new file, and then implement the corresponding checks in the template.

There are two optional functions that you can implement in the monitor, which will be invoked by the endpoint before processing the Packetlab message and after the connection is about to be closed. These functions are:

/**
 * This function is called before the endpoint processes the Packetlab message.
 * You can use this function to initialize the monitor state for the message
 * checking, as well as report the monitor's status back to the controller.
 *
 * @param info[out]: The information to be reported back to the controller.
 * @param persistent_memory[in]: The persistent memory region for the monitor.
 * @param persistent_memory_len[in]: The length of the persistent memory region.
 * @return: Size of the info parameter. The maximum size is defined by
 *          PKTLAB_LINFO_INFO_MAX in pktlab.h. If the size of the info parameter
 *          is greater than PKTLAB_LINFO_INFO_MAX, the sender will truncate the
 *          response message in `info` to PKTLAB_LINFO_INFO_MAX.
 */
uint32_t initialize(void* info, void* persistent_memory, uint32_t persistent_memory_len);

/**
 * This function is called when the connection is about to be closed. You can
 * use this function to clean up the monitor state and report the monitor's
 * status back to the controller.
 *
 * @param info[out]: The information to be reported back to the controller.
 * @param persistent_memory[in]: The persistent memory region for the monitor.
 * @param persistent_memory_len[in]: The length of the persistent memory region.
 * @return: Size of the info parameter. The maximum size is defined by
 *          PKTLAB_LINFO_INFO_MAX in pktlab.h. If the size of the info parameter
 *          is greater than PKTLAB_LINFO_INFO_MAX, the sender will truncate the
 *          response message in `info` to PKTLAB_LINFO_INFO_MAX.
 */
uint32_t finallize(void *info, void* persistent_memory, uint32_t persistent_memory_len);

Currently, the monitor is implemented to check the following Packetlab messages with the corresponding functions:

  • nopen: check_pktlab_message_nopen
  • nclose: check_pktlab_message_nclose
  • nsend: check_pktlab_message_nsend
  • ndata: check_pktlab_message_ndata
  • ncap: check_pktlab_message_ncap

Also, the monitor can be implemented to handle the result messages from the endpoint after the endpoint processes Packetlab messages. These functions have the same arguments as the corresponding check functions, and have one additional argument enum pktlab_status errid to indicate the result of the endpoint processing the Packetlab message. These functions will be useful when the endpoint fails to process the Packetlab message for some reason, and the monitor can take corrective actions based on the result of the endpoint processing the Packetlab message.

The corresponding functions are:

  • pktlab_message_nopen_result
  • pktlab_message_nclose_result
  • pktlab_message_nsend_result
  • pktlab_message_ncap_result

All of these result functions are optional, and you can choose to implement only the functions that are relevant to your monitor. ndata messages is sent by the endpoint to the controller so it doesn't have a corresponding result function.

Function Return Values

Monitor Check Functions

The monitor check functions's return value will determine if the request/notification message is allowed or not. Specifically, the return value rv of the check functions should be:

  1. rv == 0: The message is allowed.
  2. 1 <= rv < UINT16_MAX: The message is not allowed, and rv is the reason for dropping the message.
  3. rv >= UINT16_MAX: The message is not allowed, and the reason for dropping the message is an error in the monitor.
  4. rv < 0: The message is not allowed, and the reason for dropping the packet is intentionally hidden by the monitor.

For not allowed requests (non-ndata messages for now), a monitor reject (PKTLAB_ECTLMONREJ) result message is returned when 1 <= rv < UINT16_MAX (rv returned as errid), or rv < 0 (errid is 0), or rv >= UINT16_MAX when the endpoint is not configured to report crash (report_crash for reference endpoint pktendpt/pktlabme; errid is 0); a monitor unknown (PKTLAB_ECTLMONUKN) result message is returned when rv >= UINT16_MAX and the endpoint is configured to report crash.

For not allowed notifications (ndata message for now), a nblock notification is returned when 1 <= rv < UINT16_MAX (rv returned as monerrid) or when rv >= UINT16_MAX and the endpoint is configured to report crash (monerrid is 0). The not allowed notifications are otherwise just dropped silently.

The rejecting/complaining monitor indx is always returned when a monitor reject/monitor unknown/nblock message is returned.

Helper Functions

Some helper functions are provided in the monitor_helper.h file, which can be used in the monitor implementation. The following helper functions are provided:

/**
 * This function is used to read the content (packet data and other fields
 * defined in virtual memory) from the virtual memory region.
 *
 * @param addr[in]: The address of the virtual memory region to read from.
 * @param buf[out]: The buffer to store the content read from the virtual
 * memory.
 * @param len[in]: The length of the content to read from the virtual memory.
 * @return: 0 on success, other values on failure.
 */
extern int read_vmem_region(uint32_t addr, void *buf, uint32_t len);
/**
 * This function flushes the persistent memory
 * region to the disk immediately. This is useful when you want to ensure that
 * the changes to the persistent memory are reflected on the disk. The persistent
 * memory will always be flushed to the disk when the monitor connection is
 * closed.
 *
 * @return: 0 on success, other values on failure.
 */
extern int persistent_memory_flush();

Example Monitors

Some example monitors are provided in the example_monitors directory. You can use these monitors as a reference to write your own monitor.

  1. icmp_limit_monitor.c: This monitor is used to limit the number of ICMP packets sent by the controller. The controller can send a maximum of 10 ICMP packets, and the monitor will drop any ICMP packet sent after the limit is reached. No matter whether the controller is restarted or the endpoint is restarted, the monitor will keep the state of the number of ICMP packets sent based on the persistent memory.

  2. http_monitor.c: This monitor will only allow the controller to send HTTP requests and receive HTTP responses. The monitor is designed to drop any packet that is not an HTTP request or response. However, to simplify the implementation, the monitor will only check request methods and "HTTP" in the response status line. So, strictly, this monitor is not designed to be used in a real-world scenario, it is just an example to show how to write a monitor.

  3. tcp_only_monitor.c: This monitor will only allow the controller to communicate over TCP.

  4. pass_all_monitor.c: This monitor will allow everything.

Use the following commands to build the example monitors:

bash pktmon.sh <path-to-pktlab-pkg> <path-to-wasi-sdk> examples/icmp_limit_monitor
bash pktmon.sh <path-to-pktlab-pkg> <path-to-wasi-sdk> examples/http_monitor
bash pktmon.sh <path-to-pktlab-pkg> <path-to-wasi-sdk> examples/tcp_only_monitor
bash pktmon.sh <path-to-pktlab-pkg> <path-to-wasi-sdk> examples/pass_all_monitor

About

Repo for the PacketLab pktmon tool to generate monitor programs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published