On Wed, May 02, 2012 at 05:13:41PM +0530, Sreeram BS wrote:
> Hi,
> I have an program written with an intent to receive the broadcasted UDP
> packets. Unfortunately, I am not able to receive them.
> I have made several attempts by making modifications here and there in the
> program, but in vain. I have now become idealess and I have turned to you
> for help/suggestion.
> Kindly suggest.
> Here are the set of things I do:
>
> 1. I have my interface eth0 up, but deliberately I have no IP address
> assigned. [This is order to simulate a situation when DHCP discover is sent
> during booting.]
> 2. Create UDP socket.
> 3. Bind to the eth0 using SO_BINDTODEVICE
> 4. Enable broadcasting for this socket SO_BROADCAST.
> 5. Build a DHCPDiscover message.
> 6. Broadcast the message. This will elicit a response from the DHCP
> server in the local LAN. I am able to see the response in wireshark.
> 7. Call recvfrom() to receive the message. << recvfrom() waits forever.
> It is not able to grab the response >>
>
> The program is as follows:
Sorry, this has little to do with OpenBSD. Ask your question on some
Linux list.
-Otto
>
> ----------------------------------------
> [root@sreeramb-linux DHCP]# cat dhcp.c
> /* This is a test program to bind a socket to an interface
> * instead of to an IP address(which is done normally).
> * Also, broadcasting is enabled for this socket so that
> * any broadcast packet is sent over this socket.
> */
>
> #include <stdio.h>
> #include <sys/socket.h>
> #include <stdlib.h>
> #include <string.h>
> #include <netinet/in.h>
>
> #define SA struct sockaddr
> #define IFC "eth0"
> #define PORT 67
> #define IFCSZ sizeof(IFC)
>
> struct dhcp_header {
> unsigned char op;
> unsigned char htype;
> unsigned char hlen;
> unsigned char hops;
> int xid;
> short secs;
> short flags;
> struct in_addr ciaddr;
> struct in_addr yiaddr;
> struct in_addr siaddr;
> struct in_addr giaddr;
> unsigned char chaddr[16];
> unsigned char sname[64];
> unsigned char file[128];
> unsigned char opts[128];
> };
>
> int main(int argc, char **argv) {
> int sock, retn;
> struct sockaddr_in peer, addr;
> char mesg[] = "Hello World!";
> int val=1, size = sizeof(val);
>
> /* Create an UDP socket first. */
> sock = socket(AF_INET, SOCK_DGRAM, 0);
> if (sock < 0) {
> perror("Socket");
> exit(-1);
> }
> printf("Created socket successfully.\n");
>
> /* Enable the SO_DEBUG option for this socket. */
> retn = setsockopt(sock, SOL_SOCKET, SO_DEBUG, &val, size);
> if (retn < 0) {
> perror("SO_DEBUG");
> close(sock);
> exit(-1);
> }
> printf("Successfully enabled the SO_DEBUG flag for the socket.\n");
>
> /* Now, set the SO_REUSEADDR flag for this socket. */
> retn = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, size);
> if (retn < 0) {
> perror("SO_REUSEADDR");
> close(sock);
> exit(-1);
> }
> printf("Successfully set the SO_REUSEADDR flag to this socket.\n");
>
> #if 0
> /* Set the structure to send to the broadcast address. */
> memset(&addr, 0, sizeof(addr));
> addr.sin_family = AF_INET;
> addr.sin_port = htons(6800);
> retn = bind(sock, (SA *)&addr, sizeof(SA));
> if (retn < 0) {
> perror("BIND_TO_PORT");
> close(sock);
> exit(-3);
> }
> printf("Successfully bound to port 68 also.\n");
> #endif
>
> /* Now, bind to device, eth0 */
> retn = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, IFC, IFCSZ);
> if (retn < 0) {
> perror("SO_BINDTODEVICE:eth0");
> close(sock);
> exit(-1);
> }
> printf("Successfully bound to device '%s'\n", IFC);
>
> /* Now, set the broadcast flag for this socket. */
> val = 1, size = sizeof(val);
> retn = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, size);
> if (retn < 0) {
> perror("SO_BROADCAST");
> close(sock);
> exit(-1);
> }
> printf("Successfully set the broadcast flag to this socket.\n");
>
> /* Set the structure to send to the broadcast address. */
> memset(&addr, 0, sizeof(addr));
> addr.sin_family = AF_INET;
> addr.sin_port = htons(PORT);
> inet_aton("255.255.255.255", &addr.sin_addr);
>
> send_dhcp_discover(sock, addr);
> recv_dhcp_offer(sock);
> }
>
> int send_dhcp_discover(int sock, struct sockaddr_in addr) {
> int retn, i = 0;
> struct dhcp_header hdr;
>
> memset(&hdr, 0, sizeof(hdr));
> hdr.op = 1;
> hdr.htype = 1;
> hdr.hlen = 6;
> hdr.xid = 1;
> hdr.flags = 128;
> hdr.chaddr[0] = 0x08;
> hdr.chaddr[1] = 0x00;
> hdr.chaddr[2] = 0x27;
> hdr.chaddr[3] = 0x9D;
> hdr.chaddr[4] = 0x13;
> hdr.chaddr[5] = 0xEE;
>
>
> /* The first four octets are supposed to be magic number. */
> hdr.opts[i++] = 99;
> hdr.opts[i++] = 130;
> hdr.opts[i++] = 83;
> hdr.opts[i++] = 99;
>
> /* The next option depicts the message type. */
> hdr.opts[i++] = 53; // DHCP message type.
> hdr.opts[i++] = 1; // Length = 1
> hdr.opts[i++] = 1; // DHCP Discover message.
>
> /* Let the client make a wish that it be assigned 192.168.1.25 */
> hdr.opts[i++] = 50; // Preferred IP address
> hdr.opts[i++] = 4; // Length = 4
> inet_aton("192.168.1.25", (struct in_addr *)&hdr.opts[i]);
> i += 4;
>
> hdr.opts[i++] = 255; // End of options.
>
> /* Now, broadcast the message. */
> retn = sendto(sock, &hdr, sizeof(hdr), 0, (SA *)&addr, sizeof(SA));
> if (retn < 0) {
> perror("sendto");
> close(sock);
> exit(-2);
> }
> printf("Successfully broadcasted the message.\n");
>
> printf("IFC size is %d\n", IFCSZ);
> return 0;
> }
>
> /* This program will receive the DHCP offer message */
> int recv_dhcp_offer(int sock) {
> int retn, size = sizeof(SA);
> struct sockaddr_in server;
> unsigned char mesg[sizeof(struct dhcp_header)];
>
> /* Receive the message */
> retn = recvfrom(sock, mesg, sizeof(mesg), 0, (SA *)&server, &size);
> if (retn < 0) {
> perror("recvfrom");
> exit(-1);
> }
>
> printf("Received message: DHCP OFFER\n");
> return 0;
> }
>
> [root@sreeramb-linux DHCP]#
> ------------------------------------------
>
> Am I missing something very obvious. Kindly guide me.
>
> With regards,
> Sreeram