简体   繁体   English

recvfrom仅捕获发送到255.255.255.255的数据包

[英]recvfrom catches only packets sent to 255.255.255.255

I'm fighting with this strange problem, where recvfrom returns only when it catches broadcast packet with destination address of 255.255.255.255. 我正在解决这个奇怪的问题,即recvfrom仅在捕获到目标地址为255.255.255.255的广播数据包时才返回。 Packets addressed directly to the client (ie. using the client IP) are ignored. 直接寻址到客户端(即使用客户端IP)的数据包将被忽略。

Now some background (you can skip it, it's just to clarify what I'm trying to do) – I'm trying to implement a simple BOOTP client. 现在有一些背景知识(您可以跳过它,只是为了阐明我要做什么)–我正在尝试实现一个简单的BOOTP客户端。 I'm able to create a BOOTREQUEST, and a server replies to it with a correct BOOTREPLY (checked with wireshark and a simple analyzer I wrote using libpcap). 我能够创建BOOTREQUEST,并且服务器使用正确的BOOTREPLY进行回复(使用wireshark和我使用libpcap编写的简单分析器进行检查)。 However, even though I see the reply in wireshark, I'm not able to receive it in the client, because it uses the client's IP address as a destination. 但是,即使我在Wireshark中看到了答复,也无法在客户端中接收到它,因为它使用客户端的IP地址作为目的地。

I'm trying this on a network where I can catch BOOTP packets from other computers as well. 我正在一个可以从其他计算机捕获BOOTP数据包的网络上尝试此操作。 I found out that the recvfrom can receive BOOTREPLY packets with broadcast address. 我发现recvfrom可以接收具有广播地址的BOOTREPLY数据包。 The bad thing is that these are not mine as I allow the server to use unicast for the reply. 不好的是,这些不是我的,因为我允许服务器使用单播进行回复。

The code I use: 我使用的代码:

sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
    std::cerr << "Cannot create socket" << std::endl;
    return;
}

int broadcastON = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastON, sizeof(broadcastON));

sockaddr_in recv_address;
memset((char *) &recv_address, 0, sizeof(recv_address));
recv_address.sin_family = AF_INET;
recv_address.sin_port = htons(68);
recv_address.sin_addr.s_addr = htonl(INADDR_ANY);
int recv_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (recv_sockfd < 0)
{
    std::cerr << "Cannot create socket" << std::endl;
    return;
}
if (bind(recv_sockfd, (sockaddr *) &recv_address, sizeof(recv_address)) < 0)
{
    std::cerr << "Cannot bind socket" << std::endl;
    perror("bind");
    return;
}

sniff_bootp packet = createBootpPacket(mac);
sockaddr_in server_address;
memset((char *) &server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(67);
server_address.sin_addr.s_addr = htonl(INADDR_BROADCAST);
if (sendto(sockfd, &packet, sizeof(packet),0,(sockaddr *) &server_address, sizeof(server_address)) < 0)
{
    perror("sendto");
    return;
}
char msg[512];
while(1)
{
    sockaddr_in source_address;
    unsigned int cli_addr_len = sizeof(source_address);
    // HERE IS THE PROBLEM
    // returns only if the destination is broadcast
    int msg_length = recvfrom(recv_sockfd, msg, 512, 0, (sockaddr *) &source_address, &cli_addr_len);
    if (msg_length < 0) {
        perror("rcvfrom");
        continue;
    }

OK, took me a few days to figure this out, but I finally fixed it. 好的,花了我几天的时间弄清楚了,但是我终于解决了。

The problem was in fact that the packets I was trying to recvfrom was not destined for me. 问题实际上是我尝试从中接收的数据包不是发给我的。 Let me elaborate. 让我详细说明。 In bootp protocol, you send you MAC address and a server sends a reply either using broadcast or to an IP connected with the MAC address. 在bootp协议中,您向您发送MAC地址,服务器通过广播或与MAC地址连接的IP发送答复。 The problem was that I used MAC address of my other computer, so the reply was addressed to that computer and not me. 问题是我使用了另一台计算机的MAC地址,因此答复是针对该计算机而不是我。

So that's it – if you don't receive anything, make sure you are the destination. 就是这样–如果您什么都没有收到,请确保您是目的地。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM