From: xyzt on
Hello

I try to send DHCP RENEW packets to the network and receive the
responses. I broadcast the packet and I can see that it's successfully
sent using Wireshark. But I have difficulties receiving the
responses.I use packet sockets to catch the packets. I can see that
there are responses to my RENEW packet using Wireshark, but my
function 'packet_receive_renew' sometimes catch the packets but
sometimes it can not catch the packets. I set the file descriptor
using FDSET but the 'select' in my code can not realize that there are
new packets for that file descriptor and timeout occurs. I couldn't
make it clear that why it sometimes catches the packets and sometimes
doesn't.
Anybody have an idea?
Thanks in advance.

Here's the receive function.

int packet_receive_renew(struct client_info* info)
{
int fd;
struct sockaddr_ll sock, si_other;
struct sockaddr_in si_me;
fd_set rfds;
struct timeval tv;
time_t start, end;
int bcast = 1;

int ret = 0, try = 0;
char buf[1500] = {'\0'};
uint8_t tmp[BUFLEN] = {'\0'};
struct dhcp_packet pkt;
socklen_t slen = sizeof(si_other);
struct dhcps* new_dhcps;

memset((char *) &si_me, 0, sizeof(si_me));
memset((char *) &si_other, 0, sizeof(si_other));
memset(&pkt, 0, sizeof(struct dhcp_packet));

#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68)

static const struct sock_filter filter_instr[] = {
/* check for udp */
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 4), /* L5, L1,
is UDP? */
/* skip IP header */
BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
/* check udp source and destination ports */
BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /*
L3, L4 */
/* returns */
BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ), /* L3: pass
*/
BPF_STMT(BPF_RET|BPF_K, 0), /* L4:
reject */
};

static const struct sock_fprog filter_prog = {
.len = sizeof(filter_instr) / sizeof(filter_instr[0]),
/* casting const away: */
.filter = (struct sock_filter *) filter_instr,
};

#ifdef DEBUG
printf("opening raw socket on ifindex %d\n", info->interf.if_index);
#endif
if (-1==(fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))))
{
perror("packet_receive_renew::socket");
return -1;
}
#ifdef DEBUG
printf("got raw socket fd %d\n", fd);
#endif

/* Use only if standard ports are in use */
/* Ignoring error (kernel may lack support for this) */
if (-1==setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
sizeof(filter_prog)))
perror("packet_receive_renew::setsockopt");

sock.sll_family = AF_PACKET;
sock.sll_protocol = htons(ETH_P_IP);
//sock.sll_pkttype = PACKET_BROADCAST;
sock.sll_ifindex = info->interf.if_index;
if (-1 == bind(fd, (struct sockaddr *) &sock, sizeof(sock))) {
perror("packet_receive_renew::bind");
close(fd);
return -3;
}

if (-1 == setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bcast,
sizeof(bcast))) {
perror("packet_receive_renew::setsockopt");
close(fd);
return -1;
}

FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
ret = time(&start);
if (-1 == ret) {
perror("packet_receive_renew::time");
close(fd);
return -1;
}

while(1) {
ret = select(fd + 1, &rfds, NULL, NULL, &tv);
time(&end);
if (TOTAL_PENDING <= (end - start)) {
#ifdef DEBUG
fprintf(stderr, "End receiving\n");
#endif
break;
}
if (-1 == ret)
{
perror("packet_receive_renew::select");
close(fd);
return -4;
}
else if (ret) {
new_dhcps = (struct dhcps*)calloc(1, sizeof(struct dhcps));
if (-1 == recvfrom(fd, buf, 1500, 0, (struct sockaddr*)&si_other,
&slen)) {
perror("packet_receive_renew::recvfrom");
close(fd);
return -4;
}
deref_packet((unsigned char*)buf, &pkt, info);
if (-1!=(ret=get_option_val(pkt.options,
DHO_DHCP_SERVER_IDENTIFIER, tmp))) {
sprintf((char*)tmp, "%d.%d.%d.%d", tmp[0],tmp[1],tmp[2],tmp[3]);
#ifdef DEBUG
fprintf(stderr, "Received renew from %s\n", tmp);
#endif
}
else
{
#ifdef DEBUG
fprintf(stderr, "Couldnt get DHO_DHCP_SERVER_IDENTIFIER%s\n",
tmp);
#endif
close(fd);
return -5;
}
new_dhcps->dhcps_addr = strdup((char*)tmp);

//add to list
if (info->dhcps_list)
info->dhcps_list->next = new_dhcps;
else
info->dhcps_list = new_dhcps;
new_dhcps->next = NULL;
}
else {
try++;
tv.tv_sec = TOTAL_PENDING - try * TIMEOUT;
tv.tv_usec = 0;
#ifdef DEBUG
fprintf(stderr, "Timeout occured\n");
#endif
}
}
close(fd);
#ifdef DEBUG
printf("close fd:%d\n", fd);
#endif
return 0;
}
From: Mickey on
On Apr 12, 1:42 pm, xyzt <abahadirdo...(a)gmail.com> wrote:

> I try to send DHCP RENEW packets to the network and receive the
> responses. I broadcast the packet and I can see that it's successfully
> sent using Wireshark. But I have difficulties receiving the
> responses.I use packet sockets to catch the packets. I can see that
> there are responses to my RENEW packet using Wireshark, but my
> function 'packet_receive_renew' sometimes catch the packets but
> sometimes it can not catch the packets. I set the file descriptor
> using FDSET but the 'select' in my code can not realize that there are
> new packets for that file descriptor and timeout occurs. I couldn't
> make it clear that why it sometimes catches the packets and sometimes
> doesn't.
> Anybody have an idea?

This link gives a good answer:
http://stackoverflow.com/questions/285790/irritating-select-behaviour-in-c

select modifies its arguments. You have to re-initialize rfds each
time.

- Jyoti
http://acceptingall.wordpress.com/2010/02/20/as-many-faiths-that-many-ways/