I’m fighting with this strange problem, where recvfrom returns only when it catches broadcast packet with destination address of 255.255.255.255. Packets addressed directly to the client (ie. using the client IP) are ignored.
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. 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). 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.
I’m trying this on a network where I can catch BOOTP packets from other computers as well. I found out that the recvfrom can receive BOOTREPLY packets with broadcast address. 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. The problem was that I used MAC address of my other computer, so the reply was addressed to that computer and not me.
So that’s it – if you don’t receive anything, make sure you are the destination.