Skip to content

Commit

Permalink
Merge pull request #871 from appneta/Feature_#853_direct_traffic_to_pcap
Browse files Browse the repository at this point in the history
Feature #853 direct traffic to pcap
  • Loading branch information
fklassen committed Jun 29, 2024
2 parents 3ece9a8 + 2ed8008 commit 26e47da
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 119 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dnl $Id$
AC_PREREQ([2.69])

dnl Set version info here!
AC_INIT([tcpreplay],[4.5.0-beta2],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
AC_INIT([tcpreplay],[4.5.0-beta3],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
AC_CONFIG_SRCDIR([src/tcpreplay.c])
AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_AUX_DIR(config)
Expand Down
5 changes: 3 additions & 2 deletions docs/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
06/23/2024 Version 4.5.0-beta3
06/29/2024 Version 4.5.0-beta3
- tcpreplay --include / --exclude to control which packets are replayed (#884)
- add -w (--suppress-warnings) option to suppress warning messages (#878)
- add -W (--suppress-warnings) option to suppress warning messages (#878)
- AF_XDP compile issue due to merge issue (#876)
- memory leak in tcpprep when using include/exclude (#869)
- memory leak in tcpprep when using RegEx (#867)
- fix nanosecond timestamp regression bug (#863)
- autotools - AC_HELP_STRING is obsolete in 2.70 (#856)
- add -w output.pcap command line option to direct the output to a pcap (#853)
- configure.ac: do not run conftest in case of cross compilation (#849)
- Haiku support (#847)
- --fixhdrlen option added to control action on packet length changes (#846)
Expand Down
145 changes: 95 additions & 50 deletions src/common/sendpacket.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/*
* Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
* Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
* Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
*
* The Tcpreplay Suite of tools is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
Expand All @@ -27,6 +27,7 @@
* injection method, then by all means add it here (and send me a patch).
*
* Anyways, long story short, for now the order of preference is:
* 0. pcap_dump
* 1. TX_RING
* 2. PF_PACKET
* 3. BPF
Expand Down Expand Up @@ -232,6 +233,7 @@ static struct tcpr_ether_addr *sendpacket_get_hwaddr_libxdp(sendpacket_t *);
#undef INJECT_METHOD
#define INJECT_METHOD "xsk_ring_prod_submit()"
#endif
static sendpacket_t *sendpacket_open_pcap_dump(const char *, char *) _U_;
static void sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...);
static sendpacket_t *sendpacket_open_khial(const char *, char *) _U_;
static struct tcpr_ether_addr *sendpacket_get_hwaddr_khial(sendpacket_t *) _U_;
Expand Down Expand Up @@ -457,6 +459,11 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr

break;

case SP_TYPE_LIBPCAP_DUMP:
pcap_dump((u_char *)sp->handle.dump.dump, pkthdr, data);
retcode = len;
break;

case SP_TYPE_NETMAP:
#ifdef HAVE_NETMAP
retcode = sendpacket_send_netmap(sp, data, len);
Expand Down Expand Up @@ -532,55 +539,57 @@ sendpacket_open(const char *device,

errbuf[0] = '\0';

/* khial is universal */
if (stat(device, &sdata) == 0) {
if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
sp = sendpacket_open_khial(device, errbuf);

} else {
switch (sdata.st_mode & S_IFMT) {
case S_IFBLK:
errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
case S_IFDIR:
errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
case S_IFIFO:
errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
case S_IFLNK:
errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
case S_IFREG:
errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
default:
errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
if (sendpacket_type == SP_TYPE_LIBPCAP_DUMP) {
sp = sendpacket_open_pcap_dump(device, errbuf);
} else {
/* khial is universal */
if (stat(device, &sdata) == 0) {
if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
sp = sendpacket_open_khial(device, errbuf);

} else {
switch (sdata.st_mode & S_IFMT) {
case S_IFBLK:
errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
case S_IFDIR:
errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
case S_IFIFO:
errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
case S_IFLNK:
errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
case S_IFREG:
errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
default:
errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
}
}
}
#ifdef HAVE_TUNTAP
} else if (strncmp(device, "tap", 3) == 0) {
sp = sendpacket_open_tuntap(device, errbuf);
} else if (strncmp(device, "tap", 3) == 0) {
sp = sendpacket_open_tuntap(device, errbuf);
#endif
} else {
} else {
#ifdef HAVE_NETMAP
if (sendpacket_type == SP_TYPE_NETMAP)
sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
else
if (sendpacket_type == SP_TYPE_NETMAP)
sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
else
#endif
#ifdef HAVE_LIBXDP
if (sendpacket_type == SP_TYPE_LIBXDP)
sp = sendpacket_open_xsk(device, errbuf);
else
if (sendpacket_type == SP_TYPE_LIBXDP)
sp = sendpacket_open_xsk(device, errbuf);
else
#endif
#if defined HAVE_PF_PACKET
sp = sendpacket_open_pf(device, errbuf);
sp = sendpacket_open_pf(device, errbuf);
#elif defined HAVE_BPF
sp = sendpacket_open_bpf(device, errbuf);
sp = sendpacket_open_bpf(device, errbuf);
#elif defined HAVE_LIBDNET
sp = sendpacket_open_libdnet(device, errbuf);
sp = sendpacket_open_libdnet(device, errbuf);
#elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
sp = sendpacket_open_pcap(device, errbuf);
#elif defined HAVE_LIBXDP
sp = sendpacket_open_xsk(device, errbuf);
sp = sendpacket_open_pcap(device, errbuf);
#else
#error "No defined packet injection method for sendpacket_open()"
#endif
}
}

if (sp) {
Expand Down Expand Up @@ -670,6 +679,11 @@ sendpacket_close(sendpacket_t *sp)
#endif
break;

case SP_TYPE_LIBPCAP_DUMP:
pcap_dump_close(sp->handle.dump.dump);
pcap_close(sp->handle.dump.pcap);
break;

case SP_TYPE_LIBDNET:
#ifdef HAVE_LIBDNET
eth_close(sp->handle.ldnet);
Expand Down Expand Up @@ -717,6 +731,9 @@ sendpacket_get_hwaddr(sendpacket_t *sp)

if (sp->handle_type == SP_TYPE_KHIAL) {
addr = sendpacket_get_hwaddr_khial(sp);
} else if (sp->handle_type == SP_TYPE_LIBPCAP_DUMP) {
sendpacket_seterr(sp, "Error: sendpacket_get_hwaddr() not yet supported for pcap dump");
return NULL;
} else {
#if defined HAVE_PF_PACKET
addr = sendpacket_get_hwaddr_pf(sp);
Expand Down Expand Up @@ -815,6 +832,37 @@ sendpacket_get_hwaddr_pcap(sendpacket_t *sp)
}
#endif /* HAVE_PCAP_INJECT || HAVE_PCAP_SENDPACKET */

/**
* Inner sendpacket_open() method for using libpcap
*/
static sendpacket_t *
sendpacket_open_pcap_dump(const char *device, char *errbuf)
{
pcap_t *pcap;
pcap_dumper_t* dump;
sendpacket_t *sp;

assert(device);
assert(errbuf);

dbg(1, "sendpacket: using Libpcap");

pcap = pcap_open_dead(DLT_EN10MB, MAX_SNAPLEN);
if ((dump = pcap_dump_open(pcap, device)) == NULL){
char* err_msg = pcap_geterr(pcap);
strlcpy(errbuf, err_msg, PCAP_ERRBUF_SIZE);
pcap_close(pcap);
return NULL;
}

sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
strlcpy(sp->device, device, sizeof(sp->device));
sp->handle.dump.pcap = pcap;
sp->handle.dump.dump = dump;
sp->handle_type = SP_TYPE_LIBPCAP_DUMP;
return sp;
}

#if defined HAVE_LIBDNET && !defined HAVE_PF_PACKET && !defined HAVE_BPF
/**
* Inner sendpacket_open() method for using libdnet
Expand Down Expand Up @@ -886,12 +934,9 @@ sendpacket_open_tuntap(const char *device, char *errbuf)
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1);

if (ioctl(tapfd, TUNSETIFF, (void *)&ifr) < 0) {
// ignore EBUSY - it just means that the tunnel has already been opened
if (errno != EBUSY) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to create tuntap interface: %s errno=%d", device, errno);
close(tapfd);
return NULL;
}
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to create tuntap interface: %s", device);
close(tapfd);
return NULL;
}
#elif defined(HAVE_FREEBSD)
if (*device == '/') {
Expand Down Expand Up @@ -1255,14 +1300,14 @@ sendpacket_get_dlt(sendpacket_t *sp)
int dlt = DLT_EN10MB;

switch (sp->handle_type) {
case SP_TYPE_KHIAL:
case SP_TYPE_NETMAP:
case SP_TYPE_TUNTAP:
case SP_TYPE_LIBXDP:
/* always EN10MB */
return dlt;
default:
;
case SP_TYPE_KHIAL:
case SP_TYPE_NETMAP:
case SP_TYPE_TUNTAP:
case SP_TYPE_LIBXDP:
case SP_TYPE_LIBPCAP_DUMP:
/* always EN10MB */
return dlt;
default:;
}

#if defined HAVE_BPF
Expand Down
7 changes: 7 additions & 0 deletions src/common/sendpacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef enum sendpacket_type_e {
SP_TYPE_KHIAL,
SP_TYPE_NETMAP,
SP_TYPE_TUNTAP,
SP_TYPE_LIBPCAP_DUMP,
SP_TYPE_LIBXDP
} sendpacket_type_t;

Expand All @@ -81,8 +82,14 @@ typedef enum khial_direction_e {
KHIAL_DIRECTION_TX,
} khial_direction_t;

typedef struct pcap_dump_s{
pcap_t *pcap;
pcap_dumper_t* dump;
} pcap_dump_t;

union sendpacket_handle {
pcap_t *pcap;
pcap_dump_t dump;
int fd;
#ifdef HAVE_LIBDNET
eth_t *ldnet;
Expand Down
Loading

0 comments on commit 26e47da

Please sign in to comment.