首页 > 解决方案 > 原始套接字两次读取相同的数据包

问题描述

我的目的是读取发送到满足条件的特定类型 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可用,但这是设计使然。这可能是这个问题的原因吗?如果没有,还有什么?

标签: c++socketsudppacket-captureraw-sockets

解决方案


推荐阅读