I've been trying to send UDP packets using a raw socket, however, the sent packets are not received locally. The same packets are received if sent to a remote destination. The test is performed under KVM. The same test seems to be working under Parallels.
The socket is set up with:
raw_socket = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
There's a receive filter attached and it is set as promiscuous. Packets are received correctly. Sent packets ARE received in Wireshark and analysed correctly. However, the local program (e.g. nc -l -u -p ...) does not receive the packet. If I send the same packet to a remote destination, the packet is received correctly. The fact that Wireshark receives the packet suggests that it is not dropped by any iptables rules (I've also checked all DROP rules counters and there are no dropped packets).
It seems as if the packet is routed but not reprocessed by the network stack, if that even makes sense.
It's supposed to be an example code in a network course, and currently, I'm losing face in front of my students. Hope none of them are on this list ;-).
Would appreciate any help, Yuval.
A few comments about the code. For brevity, the UDP checksum is set to 0, the IP checksum is calculated from the header. Both are validated by Wireshark (and accepted by the remote machine on KVM as well). The code parses a message and sends a reply on the buffer it received. udp_hdr and ip_hdr point to the corresponding headers in the packet buffer (buffer), while payload points to the start of the L7 data.
Here's the code: { /* Process the request. */ ssize_t msg_len; int max_len = sizeof (buffer) - (payload - buffer); int tmp_port; in_addr_t tmp_ip; struct ether_addr tmp_ether;
msg_len = parse_and_send (ctx, payload, size, max_len);
if (msg_len < 0)
{
/* Error */
error_print (ctx, "Failed to parse and construct answer.");
continue;
}
if (msg_len == 0)
{
/* No message to send. */
continue;
}
/* Switch sources & destinations and update payload lengths. */
tmp_port = udp_hdr->dest;
udp_hdr->dest = udp_hdr->source;
udp_hdr->source = tmp_port;
udp_hdr->len = htons (msg_len +
(payload - (const uint8_t*) udp_hdr));
tmp_ip = ip_hdr->daddr;
compute_udp_cksum (udp_hdr);
ip_hdr->daddr = ip_hdr->saddr;
ip_hdr->saddr = tmp_ip;
ip_hdr->tot_len = htons (msg_len +
(payload - (const uint8_t*) ip_hdr));
compute_ip_cksum (ip_hdr);
memcpy (tmp_ether.ether_addr_octet, ether_hdr->ether_dhost,
sizeof (tmp_ether));
memcpy (ether_hdr->ether_dhost, ether_hdr->ether_shost, ETH_ALEN);
memcpy (ether_hdr->ether_shost, tmp_ether.ether_addr_octet,
sizeof (tmp_ether));
if (sendto (ctx->raw_socket,
&buffer, msg_len + (payload - buffer), 0,
(struct sockaddr*) &ll_addr, sizeof (ll_addr)) < 0)
{
ERROR_SYSTEM (ctx, "Sending packet");
error_print (ctx, "Failed to send packet");
continue;
}
}