c++ - 原始套接字两次读取相同的数据包
问题描述
我的目的是读取发送到满足条件的特定类型 IP 地址的所有数据包isIpInRange()
。
这是我为此使用的代码。中的代码scannerThread
就是我上面所说的。主线程中的代码用于与 nodejs Web 应用程序建立另一个 TCP 连接,我应该将捕获的实际数据包发送到该应用程序(来自 IP 标头及以上)。
#include <bits/stdc++.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <fcntl.h>
#include <linux/tcp.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
using namespace std;
int rsfd, sfd;
string getIP(unsigned int IP)
{
unsigned char *p = (unsigned char *)&IP;
return to_string(p[0]) + "." + to_string(p[1]) + "." + to_string(p[2]) + "." + to_string(p[3]);
}
void print(ip I)
{
cout << "Version: " << (int)I.ip_v << endl;
cout << "Header Length: " << (int)I.ip_hl << endl;
cout << "Type of Service: " << (int)I.ip_tos << endl;
cout << "Packet Length: " << ntohs((int)I.ip_len) << endl;
cout << "ID: " << ntohs((int)I.ip_id) << endl;
cout << "Fragment: " << ntohs((int)I.ip_off) << endl;
cout << "Time to Live: " << (int)I.ip_ttl << endl;
cout << "Higher Level Protocol: " << (int)I.ip_p << endl;
cout << "CheckSum: " << ntohs((int)I.ip_sum) << endl;
cout << "Sender: " << getIP(I.ip_src.s_addr) << endl;
cout << "Receiver: " << getIP(I.ip_dst.s_addr) << endl;
}
bool isIpInRange(in_addr_t ipaddr)
{
uint8_t *p = (uint8_t *)&ipaddr;
return p[0] == 127 && p[1] == 200;
}
void *scanner(void *arg)
{
rsfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sfd < 0)
{
perror("RAW socket");
exit(1);
}
sockaddr_ll addr;
memset(&addr, 0, sizeof(addr));
if ((addr.sll_ifindex = if_nametoindex("lo")) == 0)
{
perror("if_nametoindex() failed to obtain interface index ");
exit(EXIT_FAILURE);
}
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_family = AF_PACKET;
bind(rsfd, (sockaddr *)&addr, sizeof(addr));
char buffer[1024];
char *buf;
int bytes;
while (1)
{
bytes = recvfrom(rsfd, buffer, 1024, 0, NULL, NULL);
buffer[bytes] = 0;
buf = buffer + 14;
ip *I = (ip *)buf;
if (!isIpInRange(I->ip_dst.s_addr))
// if (I->ip_dst.s_addr != 16828543)
continue;
print(*I);
if (I->ip_p == 17)
cout << buf + 28 << endl;
else if (I->ip_p == 6)
cout << buf + 40 << endl;
// send(sfd, buf, bytes - 14, 0);
cout<<endl;
}
}
int main()
{
sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
{
perror("TCP socket");
exit(1);
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(12000);
if (connect(sfd, (sockaddr *)&addr, sizeof(sockaddr_in)) < 0)
{
perror("connect");
exit(1);
}
pthread_t scannerThread;
pthread_create(&scannerThread, NULL, scanner, NULL);
int bytes;
char buffer[1024];
char *buf;
while (1)
{
bytes = recv(sfd, buffer, 1024, 0);
buffer[bytes] = 0;
cout << bytes << " bytes received from outside" << endl;
}
pthread_join(scannerThread, NULL);
}
现在我正在使用另一个程序发送一个 UDP 数据报。
#include <bits/stdc++.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
using namespace std;
int main(int argc, char *argv[])
{
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.200.0.1");
addr.sin_port = htons(10000);
char buffer[1024] = "KILL";
int bytes;
sendto(sfd, buffer, 5, 0, (sockaddr *)&addr, sizeof(addr));
}
问题是原始套接字正在读取我发送两次的相同数据包。一切都是一样的。它两次打印相同的 IP 标头。Web 应用程序两次接收到相同的数据包。我调试并检查,readfrom()
在 2 次连续迭代中返回相同的数据。顺便说一句,如果我发送 TCP 连接请求,也会发生同样的事情。
我正在检查 Wireshark,它只注意到 1 个 UDP 数据包。当然,有一个 ICMP 数据包说不127.200.0.1
可用,但这是设计使然。这可能是这个问题的原因吗?如果没有,还有什么?
解决方案
推荐阅读
- android - 带有 Retrofit 2 Cache-Control 的离线模式
- java - 错误:“items”不支持 c:forEach jsp 中的运行时表达式
- r - 在购物篮分析中,我有什么办法只能在关联规则的 lhs 中获得 1 项?
- php - 如何一次抛出错误消息?
- java - 递归结构上的 DTO 投影
- angularjs - Angularjs Ng-init 在通过 ng-repeat 时显示相同的检索到的表单值
- db2 - DB2 锁定场景
- elasticsearch - 如何在 Elasticsearch 上索引混合语言内容?
- python-3.x - rasa nlu 多模型 python
- android - 无法使用 Webview android 获取 HTTP 401 错误的回调