Skip to content

Commit

Permalink
Add support for writing packets to pcap file while running
Browse files Browse the repository at this point in the history
  • Loading branch information
schwabe committed Jan 5, 2025
1 parent e9936db commit 7564655
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
matrix:
os: [ ubuntu-20.04, ubuntu-22.04, ubuntu-24.04 ]
compiler: [clang, gcc]
installdeps: ['sudo apt install -y ninja-build cmake']
installdeps: ['sudo apt install -y ninja-build cmake libpcap-dev']
include:
- os: macos-latest
installdeps: 'brew install cmake'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
cmake-build-*
build
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,13 @@ add_executable(lwipovpn
netif/unixaf.h
netif/unixaf_host.c
netif/unixaf_host.h
netif/unixaf_pcap.c
netif/unixaf_pcap.h
)

# C doesn't seem to have a good easy to use random function. Use arc4random if available otherwise rand
find_library(PCAP_LIBRARY NAMES pcap)

# C doesn't seem to have a good easy to use random function. Use arc4random if available otherwise rand
check_symbol_exists(arc4random stdlib.h HAVE_ARC4RANDOM)

# we do not care about C90 compatibility in lwipovpn since OpenVPN itself requires C11
Expand All @@ -91,6 +95,7 @@ LIST(REMOVE_ITEM LWIP_COMPILER_FLAGS_OVPN -Waggregate-return)
target_include_directories(lwipovpn PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_OVPN_INCLUDE_DIRS})
target_compile_options(lwipovpn PRIVATE ${LWIP_COMPILER_FLAGS_OVPN})
target_compile_definitions(lwipovpn PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
target_link_libraries(lwipovpn PRIVATE ${PCAP_LIBRARY})
if (NOT "${HAVE_ARC4RANDOM}")
target_compile_definitions(lwipovpn PRIVATE -DARC4RANDOM_MISSING)
endif()
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Features
- IPv6 Support
- automatic configuration of IPv4 and IPv6 addresses
- tap or tun emulation
- write pcap file


Enabled apps
Expand All @@ -35,7 +36,16 @@ can be enabled/implemented to allow even more testing.
- shell (a simple shell that can be used with telnet to make some network diagnostics)
- tcp echo (port 7)
- udp echo (port 7)
-


PCAP File Support
-----------------
If the environment variable `LWIP_PCAP_FILE` is e.g. by setting it from OpenVPN via

setenv LWIP_PCAP_FILE /tmp/lwip.pcap

then lwipovpn will write all packets send/received into this pcap file. If the file
already exists, the new packets will be appended to it.

Limitations
-----------
Expand Down
22 changes: 20 additions & 2 deletions netif/unixaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include <string.h>
#include <stdbool.h>


#include "lwip/opt.h"

#include "lwip/debug.h"
Expand All @@ -48,9 +47,9 @@

#include "unixaf.h"
#include "unixaf_host.h"
#include "unixaf_pcap.h"
#include "lwip/sockets.h"


/* Define those to better describe your network interface. */
#define IFNAME0 'a'
#define IFNAME1 'f'
Expand All @@ -62,6 +61,7 @@
struct unixafif {
/* Add whatever per-interface state that is needed here. */
int fd;
struct unixafif_pcap pcap;
};

/* Forward declarations. */
Expand Down Expand Up @@ -182,6 +182,7 @@ static void set_tun_fd(struct netif *netif)
}
}


static void
low_level_init(struct netif *netif) {
const char *dev_type;
Expand Down Expand Up @@ -242,6 +243,11 @@ low_level_output(struct netif *netif, struct pbuf *p) {
return ERR_IF;
}

if (unixaf->pcap.pcap)
{
unixaf_pcap_write_packet(&unixaf->pcap, p->tot_len, buf);
}

/* signal that packet should be sent(); */
size_t written = host_send(unixaf->fd, buf, p->tot_len, 0);
if (written < p->tot_len) {
Expand Down Expand Up @@ -277,6 +283,7 @@ low_level_input(struct netif *netif) {
/* Obtain the size of the packet and put it into the "len"
variable. */
readlen = host_recv(afif->fd, buf, sizeof(buf), 0);

if (readlen < 0) {
char errmsg[512];
snprintf(errmsg, sizeof(errmsg), "recv of fd %d returned %zd:",
Expand All @@ -292,6 +299,12 @@ low_level_input(struct netif *netif) {

MIB2_STATS_NETIF_ADD(netif, ifinoctets, len);

if (afif->pcap.pcap)
{
unixaf_pcap_write_packet(&afif->pcap, len, buf);
}


/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
Expand Down Expand Up @@ -365,6 +378,11 @@ unixafif_init(struct netif *netif) {

low_level_init(netif);

bool tap = netif->flags & NETIF_FLAG_ETHARP;

struct unixafif *uafif = (struct unixafif *) netif->state;
unixaf_pcap_init(&uafif->pcap, tap);

return ERR_OK;
}

Expand Down
82 changes: 82 additions & 0 deletions netif/unixaf_pcap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2024 Arne Schwabe
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 <pcap/pcap.h>
#include <stdlib.h>

#include "lwip/pbuf.h"
#include "unixaf_pcap.h"

/* This is the same mess as unixaf_host.c. pcap.h pulls in system network
* header files and those conflict with lwip's own functions.
* So this file "lives" in the system network header space */

void
unixaf_pcap_init(struct unixafif_pcap *if_pcap, bool tap)
{
const char *pcap_file = getenv("LWIP_PCAP_FILE");
if (!pcap_file) {
return;
}

/* We could use DLT_LINUX_SLL here instead and add the special header that
* would allow preserving the information of the direction in the pcap file */
int linktype = tap ? DLT_EN10MB : DLT_RAW;

if_pcap->pcap = pcap_open_dead(linktype, 65000);
if_pcap->pcap_dump = pcap_dump_open_append(if_pcap->pcap, pcap_file);

if (if_pcap->pcap_dump)
{
printf("lwipovpn: Capturing packets to '%s'\n", pcap_file);
}
else
{
fprintf(stderr, "Error opening pcap file '%s' for writing: %s\n", pcap_file,
pcap_geterr(if_pcap->pcap));
pcap_close(if_pcap->pcap);
if_pcap->pcap = NULL;
}
}

void
unixaf_pcap_write_packet(struct unixafif_pcap *if_pcap, int len, const char* buf)
{
struct pcap_pkthdr pkthdr;
pkthdr.len = len;
pkthdr.caplen = len;

gettimeofday(&pkthdr.ts, NULL);

/* The callback pointer is unsigned char * instead of void *, so we need
* to cast the pointer to it */
pcap_dump((unsigned char*) if_pcap->pcap_dump, &pkthdr, (const unsigned char *) buf);
pcap_dump_flush(if_pcap->pcap_dump);
}
64 changes: 64 additions & 0 deletions netif/unixaf_pcap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <[email protected]>
* Author: Arne Schwabe <[email protected]>
*
*/
#ifndef LWIP_UNIXAF_PCAP_H
#define LWIP_UNIXAF_PCAP_H

#include <sys/types.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/* This file cannot include system network header/pcap header, so use
* forward declarations here to define the pointers */
typedef struct pcap pcap_t;
typedef struct pcap_dumper pcap_dumper_t;

struct unixafif_pcap {
pcap_t *pcap;
pcap_dumper_t *pcap_dump;
};

void
unixaf_pcap_init(struct unixafif_pcap *if_pcap, bool tap);

void
unixaf_pcap_write_packet(struct unixafif_pcap *if_pcap, int len, const char* buf);

#ifdef __cplusplus
}
#endif

#endif /* LWIP_UNIXAF_PCAP_H */

0 comments on commit 7564655

Please sign in to comment.