Goals
Create a software component implementing capturing network traffic with the following requirements.
- For SR140 installation, this component will be installed optional.
- Only the traffic from and to the machine running SR140 will be captured.
- Only IP traffic will always be captured.
- The basic configurable filtering is available:
- Capture only UDP packets or only TCP packets, or both TCP and UDP (default).
- Capture only packets coming from and to specified list of IP addresses (the other end is always local SR140 host machine)
- Capture only packets coming to or from specific ports on local SR140 machine.
- The resulting output files will be in .pcapng format files. They will be open for view/analysis in Wireshark UI.
- The resulting files will be of reasonable size. There will be rotation when max size is reached, also when day changes.
Additionally to helping resolve customer issues, the component will be useful internally for debugging new features, perhaps for automated tests etc.
Background and strategic fit
For debugging capturing, it has been requested to have the ability to capture network traces from the command line. Customers are not comfortable running Wireshark and they also do not like capturing all network traffic. The request is to be able to capture network traffic from the command line without running the Wireshark GUI. It would be useful to only capture a certain call for debugging call issues but the initial request is to just capture from the command line. Some other customers may want to avoid having network sniffing capacity installed on their network. So the solution should be implemented as an optional component. The user will decide whether to install it or not in the course of the SR140 installation process.
Assumptions
The executable that loads and uses btcap dynamic library has to be run with elevated permissions. It should be run as local Administrator in Windows. In Linux, it has to be started as root (or sudo). If btcap is loaded into the context of a non-elevated process then Start() entry point will return error.
Requirements
# | Title | Importance | Notes |
---|---|---|---|
1 | Capture IP network traffic to/from configured IP interface on the SR140 machine | High | |
2 | Save captured traffic to files in .pcapng format compatible with Wireshark | High | |
3 | Provide basic configurable filtering of network traffic | High | |
4 | Provide both Windows and Linux implementation | High | |
5 | Implement as a dynamically loaded library (.so, .dll) | High | |
6 | Finalize one .pcapng file and start the next one on reasonable conditions (max size reached, day changed) | High |
API Design
The capture traffic component is implemented as a dynamic library. Implementing it this way works well for making it optionally installed. The library is named btcap.dll on Windows and btcap.so on Linux. That naming schema appears to be in line with other library names in the problem area (pcap, wincap and so on). The code utilizing btcap library may be placed in a variety of executables including the SR140 server process itself. The executables using btcap library must be running as Administrator (in Window) or root (in Linux).
Important definitions:
- Capture Point. This is defined as one of IP network interfaces available on the host machine PLUS the IP version of packets that we want to capture (IPv4 or IPv6). So, for every NIC installed there can be 2 capture points configured - one for IPv4, and one for IPv6. Capture Point concept is defined simply because the underlying capture technologies require to choose one adapter AND one IP version to setup the packet capture. There will be various ways to identify a Capture Point. The simplest way to point to a particular capture point is to provide a IP address string. Btcap will then understand whether it is IPv4 or IPv6, and then identify the network interface that has the specified IP address. If none of the local IP interfaces have the specified address, then an attempt to start capture will fail.
- Capture Session. This describes the process of capturing network traffic from a single Capture Point. An executable using btcap library may start multiple capture sessions if necessary. With appropriate configuration, some or all of them can capture from the same Capture Point.
- Capture Session Config. This term describes the set of parameters that defines the session. It is primarily defined as a C structure BTCAP_SessionConfig. That structure can be initialized in the code or loaded from a config file. That adds flexibility to the solution. If the code utilizing btcap library is a standalone command line program, it is comfortable to load session config from the file. On the other hand, if that code is part of a bigger system such as SR140 server, it is perhaps easier to fill the config structure from the code. In the config file, each line follows name=value pattern.
Note: it is possible to extend the above config file format to have multiple sessions configured in one file. Config file could have sections named like this: [wlan0-v6], [eth0-v4], and so on. Each section would hold one session config. Reading such config file would have started all the sessions. Do we need this? Or is it too complicated?
Session Config File Overview
In this section, the session configuration is described. Valid parameters are described from config file perspective. However, it is assumed that for each parameter in config file, there is a corresponding field in the BTCAP_SessionConfig structure.
capture_ip
: IPv4 or IPv6 address of local network interface, defining the capture point. Example: capture_ip = 192.168.5.111
peer_ip_include
: We DO capture traffic between these IP addresses and our capture_ip. The value is a comma-separated list. Example: peer_ip_include
= 192.168.5.112, 192.168.5.113
peer_ip_exclude
: We IGNORE traffic between these IP addresses and our capture_ip. The value is a comma-separated list. Example: peer_ip_exclude = 192.168.5.*
. Note: Multicast addresses are always excluded.
tcp_packets
: Capture TCP packets. Example: tcp_packets = 1
udp_packets
: Capture UDPP packets. Example: udp_packets = 1
local_port_include
: We DO capture traffic on these local ports. The value is a comma-separated list. Example: local_port_include = 1983, 1984, 2010-2025
local_port_exclude
: We IGNORE traffic on these local ports. The value is a comma-separated list. Example: local_port_exclude = 1980,11908,9898
remote_port_include
: We DO capture traffic on these remote ports. The value is a comma-separated list. Example: remote_port_include = 1983, 1984, 2010-2025
remote_port_exclude
: We IGNORE traffic on these remote ports. The value is a comma-separated list. Example: remote_port_exclude = 1980,11908,9898
results_dir
: The path to a directory where the pcapng files are saved by this session. Example: results_dir = ../bin/pcapng-output
max_result_file_size
: Max pcapng file size before it roll over. Example: max_result_file_size = 55555
More parameters will be added as necessary.
Basic API
With the terms defined above, the exposed API is very simple. The API is the same for Windows and Linux. There are only a few C-style entry points exported from the library.
int btcap_start(const BTCAP_SessionConfig* config, int* sessionID); // Start Capture Session. Session ID is returned in *sessionID.
int btcap_stop(int sessionID); // Stop Capture Session with sessionID.
int btcap_read_config(const char* configFilePath, BTCAP_SessionConfig* config); // Read config file into the config structure.
All 3 methods return 0 on success or a non-zero error code.
To start a capture session, the user calls btcap_start() providing a pointer to initialized BTCAP_SessionConfig structure. btcap_start() attempts to start the capture session in a separate "capture thread". btcap_start() itself returns as soon as the capture thread successfully starts. If the capture cannot start for whatever reason, then the btcap_start() will return an error code, and the capture thread will not exist upon return. So btcap_start() is not blocking.
To stop a capture session, the user calls btcap_stop() providing the ID of the previously saved session. btcap_stop() signals the capture thread to stop and waits until it is done before returning.
btcap_read_config() API initializes the instance of BTCAP_SessionConfig structure referenced by its 2nd argument with the session config from the file at configFilePath.
Basic Usage Scenario
Here is the basic sequence of operations utilizing the btcap library (in pseudo-code).
---
// Load library and obtain exported entry point pointers by names. If load failed, exit.
// Config file path for this session
const char* configFilePath = ".\btcap.cfg";
// Allocate config structure
BTCAP_SessionConfig cfg = {};
// Optional: Initialize config structure from a config file path obtained/declared earlier. (Alternatively, just initialize all fields from the code).
btcap_read_config(configFilePath, &cfg);
// Start capture session
int sessionID = 0;
btcap_start(&cfg, &sessionID);
// Session started in separate thread. Do other stuff...
// Later stop the capture session
btcap_stop(sessionID);
// Unload the library
-----
Higher level API - BTCapHelper
A higher level API in form of class BTCapHelper was created. It's done mainly to hide the technical details of loading library, and also to hide differences in that area between platforms.
class BTCapHelper
{
public:
virtual ~BTCapHelper() {}
virtual int Start(BTCAP_SessionConfig* cfg) = 0;
virtual int Stop() = 0;
virtual int ReadConfig(const char* configFilePath, BTCAP_SessionConfig* cfg) = 0;
};
bool BTCap_isAvailable(const char* pathToLibrary);
BTCapHelper* BTCap_GetHelper(const char* pathToLibrary);
Usage scenario with BTCapHelper
Here is the fragment of using that higher level API:
-----
#include "../include/btcap-helper.h"
#ifdef WIN32
const char* libraryPath = "./btcap.dll";
#else
const char* libraryPath = "./btcap.so";
#endif
int main(int argc, char* argv[])
{
// TODO: pass this as a command line argument.
const char* btcapConfigPath = "./btcap.cfg";
printf("Checking if BTCap is available...\n");
bool ok = BTCap_isAvailable(libraryPath);
if (!ok)
{
printf(" BTCap is NOT available. Exiting.\n");
return 10;
}
printf(" BTCap is available.\n");
int rc;
BTCapHelper* btcap = BTCap_GetHelper(libraryPath);
BTCAP_SessionConfig btcapConfig = {0};
printf("Reading btcap session config file (%s) ...\n", btcapConfigPath);
rc = btcap->ReadConfig(btcapConfigPath, &btcapConfig);
printf("Starting btcap session...\n");
rc = btcap->Start(&btcapConfig);
#ifdef WIN32
SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#else
signal(SIGINT, sig_handler);
signal(SIGHUP, sig_handler);
signal(SIGSTOP, sig_handler);
signal(SIGKILL, sig_handler);
signal(SIGTERM, sig_handler);
#endif
printf("Running btcap session...\n");
while (!g_exit)
{
// Do other stuff
Sleep(1000);
}
printf("Stopping btcap session...\n");
btcap->Stop();
delete btcap;
printf("Exiting...\n");
return 0;
}
----
Implementation Overview
Questions
Below is a list of questions to be addressed as a result of this requirements document:
Question | Outcome |
---|---|
Add Comment