linux传输数据包丢失,pcap_next偶尔会丢失Linux上的数据包

昨天,我问我的asynchronous use of libpcap was making me lose packets。今天,我看起来更进一步,似乎问题不在于异步使用libpcap,而在于使用pcap_next_ex。偶尔(10个用完了1000个),pcap_next_ex将在pcap句柄超时过期之前返回,告诉程序没有要读取的数据包(即使它们在那里)。

下面的概念验证再现了这个问题。它依赖于libpcap,pthread,boost和libcrafter(一个漂亮的C++数据包制作库)。基本上,它会向目标发送一组TCP-SYN数据包,并尝试使用libpcap获取响应。调用pcap_loop的线程是并行运行的 - 当主程序错过某些响应(如上所述)时,该线程捕获所有数据包。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace boost;

using namespace Crafter;

using namespace std;

int captureThreadCount = 0;

typedef vector, posix_time::time_duration> > PacketTimestamp;

PacketTimestamp capturedThreadPackets;

void captureThreadCallback(u_char* user, const struct pcap_pkthdr* h, const u_char* bytes)

{

shared_ptr packet = make_shared();

packet->PacketFromIP(bytes + 16, h->caplen - 16);

posix_time::time_duration timestamp = posix_time::seconds(h->ts.tv_sec) +

posix_time::microseconds(h->ts.tv_usec);

capturedThreadPackets.push_back(make_pair(packet, timestamp));

++captureThreadCount;

}

void* captureThread(void* arg)

{

pcap_t* pcap = (pcap_t*) arg;

pcap_loop(pcap, -1, captureThreadCallback, NULL);

}

int main(int argc, char* argv[])

{

if (argc != 5) {

cout << "Usage: " << argv[0] << " " << endl;

exit(1);

}

InitCrafter();

// Parameters.

string sourceIp = argv[1];

string destinationIp = argv[2];

int port = atoi(argv[3]);

int nTries = atoi(argv[4]);

char errorBuffer[1024];

// Socket for sending,

int sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

// And sockaddr_in to send to.

struct sockaddr_in sin;

sin.sin_family = AF_INET;

sin.sin_port = htons(port);

sin.sin_addr.s_addr = inet_addr(destinationIp.c_str());

// One pcap for the main thread (calling pcap_next),

pcap_t* pcapForNext = pcap_open_live(NULL, BUFSIZ, false, 1000, errorBuffer);

// Another pcap for a capture thread (calling pcap_loop),

pcap_t* pcapCapture = pcap_open_live(NULL, BUFSIZ, false, 1000, errorBuffer);

// Both filtered for SYN+ACK or RST+ACK from destination:port to source.

string filterExpression = (boost::format("ip src %s and dst %s and src port %d and ((tcp[tcpflags] & (tcp-syn|tcp-ack) != 0) or (tcp[tcpflags] & (tcp-rst|tcp-ack) != 0))") % destinationIp % sourceIp % port).str();

struct bpf_program filter;

pcap_compile(pcapForNext, &filter, filterExpression.c_str(), false, 0);

pcap_setfilter(pcapForNext, &filter);

pcap_setfilter(pcapCapture, &filter);

pcap_freecode(&filter);

// Don't forget the capture thread!

pthread_t thread;

pthread_create(&thread, NULL, captureThread, pcapCapture);

// Some statistics.

int packetsSent = 0;

int packetsReceived = 0;

int packetsTimeout = 0;

int packetsFailed = 0;

// Let's probe.

for (int i = 0; i < nTries; ++i) {

// Create packet,

IP ipHeader;

ipHeader.SetSourceIP(sourceIp);

ipHeader.SetDestinationIP(destinationIp);

TCP tcpHeader;

tcpHeader.SetSrcPort(12345 + i);

tcpHeader.SetDstPort(port);

tcpHeader.SetFlags(TCP::SYN);

shared_ptr packet = make_shared(ipHeader / tcpHeader);

// Check the time,

struct timeval tv;

gettimeofday(&tv, NULL);

posix_time::time_duration sentTime =

posix_time::seconds(tv.tv_sec) + posix_time::microseconds(tv.tv_usec);

// And send it.

if (packet->SocketSend(sd) > 0) {

cerr << "Sent packet " << i << " at " << sentTime << "." << endl;

++packetsSent;

}

else {

cerr << "Sending packet " << i << " failed." << endl;

continue;

}

struct pcap_pkthdr* pktHeader;

const u_char* pktData;

int r;

// Wait for the response.

if ((r = pcap_next_ex(pcapForNext, &pktHeader, &pktData)) > 0) {

posix_time::time_duration timestamp =

posix_time::seconds(pktHeader->ts.tv_sec) +

posix_time::microseconds(pktHeader->ts.tv_usec);

cerr << "Response " << i << " received at " << timestamp << "." << endl;

++packetsReceived;

}

else if (r == 0) {

cerr << "Timeout receiving response for " << i << "." << endl;

++packetsTimeout;

}

else {

cerr << "Failed receiving response for " << i << "." << endl;

++packetsFailed;

}

}

// Wait (to ensure "fast packets" are captured by the capture thread),

usleep(500000); // 500 ms.

for (PacketTimestamp::iterator i = capturedThreadPackets.begin();

i != capturedThreadPackets.end(); ++i) {

TCP* tcpLayer = GetTCP(*i->first);

cout << "Captured packet " << (tcpLayer->GetDstPort() - 12345) << " at " << i->second << "." << endl;

}

cout << "SNT=" << packetsSent <<

", RCV=" << packetsReceived <<

", TIM=" << packetsTimeout <<

", FLD=" << packetsFailed <<

", CAP=" << captureThreadCount << "." << endl;

CleanCrafter();

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值