Building and configuring a “reasonably well hidden” network monitor using a Raspberry Pi (PI)
This project follows on directly from Part 1 and is really just a stepping stone to introduce concepts required in later projects.
Wireshark is fine for a start and is a highly valuable tool (test/develop/test filters for example), but what about something a little more specific?
There are numerous of these programs available (tcpdump), so we will only provide brief references/details and some implementation considerations. (tcpdump can capture and save everything to a file without us writing any code)
As its being developed on a PI we will only consider linux, not Windows (a later project).
Getting Started:
Before commencing its necessary to decide on an approach:
Pure (standard) C.
Compared those below this is more work but the rewards are: very small, fast, reliable and easy to understand.
Hybrid C/C++.
By writing the capture part in C, but moving the housekeeping to C++ (or python?) its possible to reduce the work, but keep in mind that mixing C and C++ requires care.
Pure C++ (or as close as you can).
(You still must still pay careful attention to the C/C++ integration)
Pick a class library and off you go, there are many to choose from.
It may be faster to write but will be slower, larger and consume more resources which may rule small CPU / Memory configurations.
This application requires multiple threads so be prepapred to spend time getting them to work within your library.
A note about C and C++.
There seems to be a misconception that C++ is somehow a modified version of C.
Whilst from a syntactic position this appears “true”, under the covers there are many subtle differences.
Sign extension, handling of numbers, casts…its a long list.
Many bugs and security holes have been linked to this problem (compiling a C program in a C++ compiler without testing/verification).
For better or worse they are in fact different languages….
Resources and helpful information:
Please check out our Project References Page, in particular:
libpcap
tcpdump
The Linux Programming Interface
for all the necessary information and links
A logging app.
The steps any logging application performs are:
(1) Open a file for the data
(2) Intialize libpcap (including the capture filter(s))
(3) Start the capture.
(4) Save each packet arrives in the file.
(5) If the file grows too large close it and open another.
(6) When requested: stop the capture, close the file and exit.
Critical sections.
Lets examine the above steps and discuss those which require careful attention.
(1) Open a file for the data.
This is a normal activity undertaken in most programs.
Note how this file will be used in Step (4) and may be closed and another file opened in Step (5).
So a little care is required, especially if you are mixing C/C++.
Typically Step (1) is in a different thread to Steps (4) and (5).
(2) Intialise libpcap (including the capture filter(s)
libpcap expects all calls and parameters to be in “C”.
Make sure you have this covered.
(3) Start the capture.
There are many options on how to structure this so we will just list a few things you should consider:
Its probably best to have the user interact with one thread and invoke libpcap from another thread.
The user thread can:
(a) Send commands to libpcap as required (ie. stop) and monitor its performance.
(b) Use the exit of the libpcap thread to trigger any “tidy up” activities.
Hopefully its evident from the above that multithreading is helpful during the implementation.
Illustrating this with some code from one of our sniffers (heavily based on the examples at tcpdump).
In the following:
libpcap has already been initialised, when you execute it to capture packets (using the approach we prefer) the thread BLOCKS.
ie. It will only return when libpcap is instructed to exit (see below).
exit_stat = pcap_loop ( pcap_inst_handle, -1, code_callback_got_packet, _str );
/* This call BLOCKS (does not return) until one of 3 conditions below are met. */
/* The actual packet is captued and handled by: code_callback_got_packet. */
switch (exit_stat) {
case 0: /* should never happen */
capt_exitcode = CAPT_EXIT_1; /* status so the calling thread knows what is going on */
printf("Capture exit - TIMEOUT OR NO PACKET\n"); /* explanation to user */
break;
case -1: /* error */
capt_exitcode = CAPT_EXIT_2;
printf("Capture exit - ERROR\n");
break;
case -2: /* pcap_close called */
capt_exitcode = CAPT_EXIT_3;
exit_cleanup(CLEAN_PCAP | CLEAN_CAPTFILE); /* put all the tidy up stuff in a function */
printf("Capture exit - CLOSE\n");
break;
}
/* this function is invoked to process each packet */
/* whilst the above function has BLOCKED this callback is continually called */
static void code_callback_got_packet (u_int8_t *args_, const struct pcap_pkthdr *header_, const u_int8_t *packet_ )
{
}
So the program structure we favor is:
Thread 1: User interface, creates thread 2 for the capture.
Thread 2: performs libpcap initialization, capture call and all packet processing. (shown above)
(4) Save each packet arrives in the file.
This is being performed by the code associated with the libpacp capture.
It needs to be fast and efficient.
Standard C.
(5) If the file grows too large close it and open another.
This is being performed by the code associated with the libpacp capture.
It needs to be fast and efficient.
Standard C.
(6) When requested: stop the capture, close the file and exit.
This will cause the BLOCKED thread in (3) above to exit back to the user thread.
Standard C.
If I don’t wish to go further, how do I use this project
Thus far we have “hidden” our PI.
tcpdump uses the same filters as Wireshark (because pcap also does the capture for Wireshark)
So using tcpdump with the desired filters will provide a series of files, these files may be opened with Wireshark to view.
(python can also do this).
So you have a way to log/monitor a network without interfering with it.
The simplest way to make this project work would be to construct a pre-processor for tcpdump.
A nice GUI with options could be used to invoke tcpdump and handle the results.
It could also process the results.
(Also don’t rule out python for some of these tasks)
Wrap up
This project is not complicated but does require a number of techniques.
Its possible to do everything (with care) in C, C/C++ or C++ with the hybrid probably being the easiest.
We require the resources and some of the above in future projects.