In linux, how can I pass a UDP packet using 0.0.0.0 as the source address.
Here is what I have tried so far.
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <net/if.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> int main(int argc, const char *argv[]) { struct sockaddr_in dst, src; struct ifreq ifr; int sock, tmp; char payload[128]; memset(payload, 0, 128); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_addr.s_addr = inet_addr("255.255.255.255"); dst.sin_port = htons(67); memset(&src,0,sizeof(src)); src.sin_family = AF_INET; src.sin_addr.s_addr = inet_addr("0.0.0.0"); src.sin_port = htons(68); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) perror("Failed to create socket"); tmp = 1; if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &tmp, sizeof(tmp)) < 0) perror("SO_BROADCAST failed"); if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) < 0) perror("SO_REUSEADDR failed"); if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &tmp, sizeof(tmp)) < 0) perror("IP_FREEBIND failed"); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name)); if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) perror("SO_BINDTODEVICE failed"); if (bind(sock, (const struct sockaddr*)&src, sizeof(struct sockaddr_in)) < 0) perror("bind failed"); if (connect(sock, (const struct sockaddr*)&dst, sizeof(struct sockaddr_in)) < 0) perror("bind failed"); if (write(sock, payload, 128) < 0 ) perror("Write failed"); close(sock); return 0; }
The problem is that the source address is set only to 0.0.0.0 if the interfaces do not have an IPv4 address. If only one interface has an IPv4 address, this address is used as the source address.
I looked at the source code of some of the existing DHCP clients and found that they use RAW sockets and build IP and UDP headers manually. This is an opportunity, but I would like to avoid it manually.