Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/test/integration/tcp_dump.cc
Line
Count
Source (jump to first uncovered line)
1
#include "test/integration/tcp_dump.h"
2
3
#include <sys/types.h>
4
5
#include <csignal>
6
#include <fstream>
7
8
#include "envoy/common/platform.h"
9
10
#include "source/common/common/assert.h"
11
#include "source/common/common/fmt.h"
12
13
namespace Envoy {
14
15
TcpDump::TcpDump(const std::string& path, const std::string& iface,
16
0
                 const std::vector<uint32_t>& ports) {
17
#ifdef WIN32
18
  ENVOY_LOG_MISC(debug, "tcpdump not supported on windows");
19
#else
20
  // Remove any extant pcap file.
21
0
  ::unlink(path.c_str());
22
  // Derive the port filter expression.
23
0
  std::string port_expr;
24
0
  for (uint32_t port : ports) {
25
0
    if (!port_expr.empty()) {
26
0
      port_expr += " or ";
27
0
    }
28
0
    port_expr += "tcp port " + std::to_string(port);
29
0
  }
30
0
  ENVOY_LOG_MISC(debug, "tcpdumping iface {} to {} with filter \"{}\"", iface, path, port_expr);
31
  // Fork a child process. We use explicit fork/wait over popen/pclose to gain
32
  // the ability to send signals to the pid.
33
0
  tcpdump_pid_ = ::fork();
34
0
  RELEASE_ASSERT(tcpdump_pid_ >= 0, "");
35
  // execlp in the child process.
36
0
  if (tcpdump_pid_ == 0) {
37
0
    const int rc = ::execlp("tcpdump", "tcpdump", "-i", iface.c_str(), "-w", path.c_str(),
38
0
                            "--immediate-mode", port_expr.c_str(), nullptr);
39
0
    if (rc == -1) {
40
0
      ::perror("tcpdump");
41
0
      exit(1);
42
0
    }
43
0
  }
44
  // Wait in parent process until tcpdump is running and has created the pcap
45
  // file.
46
0
  while (true) {
47
0
    std::ifstream test_file{path};
48
0
    if (test_file.good()) {
49
0
      break;
50
0
    }
51
    // If the child died unexpectedly, handle this.
52
0
    int status;
53
0
    int rc = ::waitpid(tcpdump_pid_, &status, WNOHANG);
54
0
    RELEASE_ASSERT(rc != -1, "");
55
0
    if (rc > 0) {
56
0
      RELEASE_ASSERT(rc == tcpdump_pid_, "");
57
0
      RELEASE_ASSERT(WIFEXITED(status), "");
58
0
      RELEASE_ASSERT(WEXITSTATUS(status) == 1, "");
59
0
      ENVOY_LOG_MISC(debug, "tcpdump exited abnormally");
60
0
      tcpdump_pid_ = 0;
61
0
      break;
62
0
    }
63
    // Give 50ms sleep.
64
0
    ::usleep(50000); // NO_CHECK_FORMAT(real_time)
65
0
  }
66
0
#endif
67
0
}
68
69
0
TcpDump::~TcpDump() {
70
0
#ifndef WIN32
71
0
  if (tcpdump_pid_ > 0) {
72
0
    RELEASE_ASSERT(::kill(tcpdump_pid_, SIGINT) == 0, "");
73
0
    int status;
74
0
    RELEASE_ASSERT(::waitpid(tcpdump_pid_, &status, 0) != -1, "");
75
0
    RELEASE_ASSERT(WIFEXITED(status), "");
76
0
    RELEASE_ASSERT(WEXITSTATUS(status) == 0, "");
77
0
    ENVOY_LOG_MISC(debug, "tcpdump terminated");
78
0
  }
79
0
#endif
80
0
}
81
82
} // namespace Envoy