0

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
		}
	}
#ifdef DEBUG	
	close(fd);
	printf("close fd:%d\n", fd);
#endif
	return 0;
}
1
Contributor
1
Reply
3
Views
7 Years
Discussion Span
Last Post by xyzt
0

I've solved the problem. I think it was an timing issue. I opened the listening socket and bind it before sending the message. So, it can catch the message without problem. Thanks.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.