19779d861e
Refs: #4834 Change-Id: If2455e1830f310beea434ffb455d960e11c4c2ed
140 lines
4.0 KiB
C++
140 lines
4.0 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2014-2019, Regents of the University of California,
|
|
* Arizona Board of Regents,
|
|
* Colorado State University,
|
|
* University Pierre & Marie Curie, Sorbonne University,
|
|
* Washington University in St. Louis,
|
|
* Beijing Institute of Technology,
|
|
* The University of Memphis.
|
|
*
|
|
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
|
* See AUTHORS.md for complete list of NFD authors and contributors.
|
|
*
|
|
* NFD is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Foundation,
|
|
* either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "pcap-helper.hpp"
|
|
|
|
#include <pcap/pcap.h>
|
|
#include <unistd.h>
|
|
|
|
#if !defined(PCAP_NETMASK_UNKNOWN)
|
|
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
|
#endif
|
|
|
|
namespace nfd {
|
|
namespace face {
|
|
|
|
PcapHelper::PcapHelper(const std::string& interfaceName)
|
|
: m_pcap(nullptr)
|
|
{
|
|
char errbuf[PCAP_ERRBUF_SIZE] = {};
|
|
m_pcap = pcap_create(interfaceName.data(), errbuf);
|
|
if (!m_pcap)
|
|
NDN_THROW(Error("pcap_create: " + std::string(errbuf)));
|
|
|
|
// Enable "immediate mode", effectively disabling any read buffering in the kernel.
|
|
// This corresponds to the BIOCIMMEDIATE ioctl on BSD-like systems (including macOS)
|
|
// where libpcap uses a BPF device. On Linux this forces libpcap not to use TPACKET_V3,
|
|
// even if the kernel supports it, thus preventing bug #1511.
|
|
if (pcap_set_immediate_mode(m_pcap, 1) < 0)
|
|
NDN_THROW(Error("pcap_set_immediate_mode failed"));
|
|
}
|
|
|
|
PcapHelper::~PcapHelper()
|
|
{
|
|
close();
|
|
}
|
|
|
|
void
|
|
PcapHelper::activate(int dlt)
|
|
{
|
|
int ret = pcap_activate(m_pcap);
|
|
if (ret < 0)
|
|
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
|
|
|
|
if (pcap_set_datalink(m_pcap, dlt) < 0)
|
|
NDN_THROW(Error("pcap_set_datalink: " + getLastError()));
|
|
|
|
if (pcap_setdirection(m_pcap, PCAP_D_IN) < 0)
|
|
NDN_THROW(Error("pcap_setdirection: " + getLastError()));
|
|
}
|
|
|
|
void
|
|
PcapHelper::close()
|
|
{
|
|
if (m_pcap) {
|
|
pcap_close(m_pcap);
|
|
m_pcap = nullptr;
|
|
}
|
|
}
|
|
|
|
int
|
|
PcapHelper::getFd() const
|
|
{
|
|
int fd = pcap_get_selectable_fd(m_pcap);
|
|
if (fd < 0)
|
|
NDN_THROW(Error("pcap_get_selectable_fd failed"));
|
|
|
|
// we need to duplicate the fd, otherwise both pcap_close() and the
|
|
// caller may attempt to close the same fd and one of them will fail
|
|
return ::dup(fd);
|
|
}
|
|
|
|
std::string
|
|
PcapHelper::getLastError() const
|
|
{
|
|
return pcap_geterr(m_pcap);
|
|
}
|
|
|
|
size_t
|
|
PcapHelper::getNDropped() const
|
|
{
|
|
pcap_stat ps{};
|
|
if (pcap_stats(m_pcap, &ps) < 0)
|
|
NDN_THROW(Error("pcap_stats: " + getLastError()));
|
|
|
|
return ps.ps_drop;
|
|
}
|
|
|
|
void
|
|
PcapHelper::setPacketFilter(const char* filter) const
|
|
{
|
|
bpf_program prog;
|
|
if (pcap_compile(m_pcap, &prog, filter, 1, PCAP_NETMASK_UNKNOWN) < 0)
|
|
NDN_THROW(Error("pcap_compile: " + getLastError()));
|
|
|
|
int ret = pcap_setfilter(m_pcap, &prog);
|
|
pcap_freecode(&prog);
|
|
if (ret < 0)
|
|
NDN_THROW(Error("pcap_setfilter: " + getLastError()));
|
|
}
|
|
|
|
std::tuple<const uint8_t*, size_t, std::string>
|
|
PcapHelper::readNextPacket() const
|
|
{
|
|
pcap_pkthdr* header;
|
|
const uint8_t* packet;
|
|
|
|
int ret = pcap_next_ex(m_pcap, &header, &packet);
|
|
if (ret < 0)
|
|
return std::make_tuple(nullptr, 0, getLastError());
|
|
else if (ret == 0)
|
|
return std::make_tuple(nullptr, 0, "timed out");
|
|
else
|
|
return std::make_tuple(packet, header->caplen, "");
|
|
}
|
|
|
|
} // namespace face
|
|
} // namespace nfd
|