Ejemplo n.º 1
0
/*=========================================================================*/ 
int DHCPGetOptionInfo(unsigned char *dhcpOptCodes, int dhcpOptCodeCnt, 
		DHCPInfoCallBack *dhcpInfoCB, void *context)
/* Calls dhcpInfoCB once for each requested option in dhcpOptCodes.

	Returns  -    	zero on success, non-zero on failure

	errno         	ENOTCONN error during read
               	ETIME read timed out
               	ENOMEM out of memory
               	EINVAL parse error

	BOOTP/DHCP packet header format:

	Offs	Len	Name		Description
	0		1		opcode	Message opcode: 1 = BOOTREQUEST, 2 = BOOTREPLY
	1		1		htype		Hardware address type (eg., 1 = 10mb ethernet)
	2		1		hlen		Hardware address length (eg., 6 = 10mb ethernet)
	3		1		hops		Client sets to zero, optionally used by relay agents
	4		4		xid		Transaction ID, random number chosen by client
	8		2		secs		Client sets to seconds since start of boot process
	10		2		flags		Bit 0: broadcast response bit
	12		4		ciaddr	Client IP address - only filled if client is bound
	16		4		yiaddr	'your' (Client) IP address
	20		4		siaddr	IP address of next server to use in bootstrap
	24		4		giaddr	Relay agent IP address, used in booting via RA
	28		16		chaddr	Client hardware address
	44		64		sname		Optional server host name, null-terminated string
	108	128	file		Boot file name, null-terminated string
	236	var	options	Optional parameters field

	The options field has the following format:

	Offs	Len	Name		Description
	0		4		cookie	4-byte cookie field: 99.130.83.99 (0x63825363)
	
	Followed by 1-byte option codes and 1-byte option lengths, except
	for the two special fixed length options, pad (0) and end (255).
	Options are defined in slp_dhcp.h as TAG_XXX values. The two we
	really care about here are options TAG_SLP_DA and TAG_SLP_SCOPE,
	78 and 79, respectively. 
	
	The format for TAG_SLP_DA (starting with the tag) is:
	
	Offs	Len	Name		Description
	0		1		tag		TAG_SLP_DA - directory agent ip addresses
	1		1		length	length of remaining data in the option
	2		1		mand		flag: the use of these DA's is mandatory
	3		4		a(0)		4-byte ip address
	...
	3+n*4	4		a(n)		4-byte ip address

	The format for TAG_SLP_SCOPE (starting with the tag) is:

	Offs	Len	Name		Description
	0		1		tag		TAG_SLP_SCOPE - directory scopes to use
	1		1		length	length of remaining data in the option
	2		1		mand		flag: the use of these scopes is mandatory
	3		var	scopes	a null-terminated, comma-separated string of scopes

	The "DHCP Message Type" option must be included in every DHCP message.
	All tags except for TAG_PAD(0) and TAG_END(255) begin with a tag value
	followed by a length of remaining data value. 
  =========================================================================*/ 
{
	UINT32 xid;
	time_t timer;
	struct timeval tv;
	int sockfd, retries;
	struct sockaddr_in sendaddr;
	unsigned char chaddr[MAX_MACADDR_SIZE];
	unsigned char hlen, htype;
	unsigned char sndbuf[512];
	unsigned char rcvbuf[512];
	struct hostent *hep;
	unsigned char *p;
	size_t rcvbufsz = 0;
	char host[256];

	/* Get our IP and MAC addresses */
	if(gethostname(host, (int)sizeof(host))
			|| !(hep = gethostbyname(host))
			|| dhcpGetAddressInfo((unsigned char *)hep->h_addr, 
					chaddr, &hlen, &htype))
		return -1;

	/* get a reasonably random transaction id value */
	xid = (UINT32)time(&timer);

	/* BOOTP request header */
	memset(sndbuf, 0, 236);		/* clear bootp header */
	p = sndbuf;
	*p++ = BOOTREQUEST;			/* opcode */
	*p++ = htype;
	*p++ = hlen;
	p++;								/* hops */
	ToUINT32(p, xid);
	p += 2 * sizeof(UINT32);	/* xid, secs, flags */
	memcpy(p, hep->h_addr, 4);
	p += 4 * sizeof(UINT32);	/* ciaddr, yiaddr, siaddr, giaddr */
	memcpy(p, chaddr, hlen);
	p += 16 + 64 + 128;			/* chaddr, sname and file */
	*p++ = DHCP_COOKIE1;			/* options, cookies 1-4 */
	*p++ = DHCP_COOKIE2;
	*p++ = DHCP_COOKIE3;
	*p++ = DHCP_COOKIE4;

	/* DHCP Message Type option */
	*p++ = TAG_DHCP_MSG_TYPE;
	*p++ = 1;						/* option length */
	*p++ = DHCP_MSG_INFORM;		/* message type is DHCPINFORM */

	/* DHCP Parameter Request option */
	*p++ = TAG_DHCP_PARAM_REQ;	/* request for DHCP parms */
	*p++ = (unsigned char)dhcpOptCodeCnt;
	memcpy(p, dhcpOptCodes, dhcpOptCodeCnt);
	p += dhcpOptCodeCnt;

	/* DHCP Client Identifier option */
	*p++ = TAG_CLIENT_IDENTIFIER;
	*p++ = hlen + 1;				/* option length */
	*p++ = htype;					/* client id is htype/haddr */
	memcpy(p, chaddr, hlen);
	p += hlen;

	/* End option */
	*p++ = TAG_END;

	/* get a broadcast send/recv socket and address */
	if((sockfd = dhcpCreateBCSkt(&sendaddr)) < 0)
		return -1;

	/* setup select timeout */
	tv.tv_sec = 0;
	tv.tv_usec = INIT_TMOUT_USECS;

	retries = 0;
	srand((unsigned)time(&timer));
	while (retries++ < MAX_DHCP_RETRIES)
	{
		if(dhcpSendRequest(sockfd, sndbuf, p - sndbuf, 
				(struct sockaddr *)&sendaddr, &tv) < 0)
		{
			if (errno != ETIMEDOUT)
			{
				closesocket(sockfd);
				return -1;
			}
		}
		else if((rcvbufsz = dhcpRecvResponse(sockfd, rcvbuf, 
				sizeof(rcvbuf), &tv)) < 0)
		{
			if (errno != ETIMEDOUT)
			{
				closesocket(sockfd);
				return -1;
			}
		}
		else if(rcvbufsz >= 236 && AsUINT32(&rcvbuf[4]) == xid)
			break;

		/* exponential backoff randomized by a 
			uniform number between -1 and 1 */
		tv.tv_usec = tv.tv_usec * 2 + (rand() % 3) - 1;
		tv.tv_sec = tv.tv_usec / USECS_PER_SEC;
		tv.tv_usec %= USECS_PER_SEC;
	}
	closesocket(sockfd);
	return rcvbufsz? dhcpProcessOptions(rcvbuf + 236, rcvbufsz - 236, 
			dhcpInfoCB, context): -1;
}
Ejemplo n.º 2
0
/** Queries a DHCP server and calls a callback once for each option.
 *
 * Queries the sub-net DHCP server for a specified set of DHCP options
 * and then calls a user-supplied callback function once for each of 
 * the desired options returned by the server.
 *
 * @param[in] dhcpOptCodes - An array of option codes to query for.
 * @param[in] dhcpOptCodeCnt - The number of elements in @p dhcpOptCodes.
 * @param[in] dhcpInfoCB - The callback function to call for each option.
 * @param[in] context - callback context.
 *
 * @return Zero on success; non-zero on failure, with errno set to 
 *    ENOTCONN (read error), ETIMEDOUT (read timeout), ENOMEM (out of
 *    memory), or EINVAL (on parse error).
 */
int DHCPGetOptionInfo(unsigned char * dhcpOptCodes, int dhcpOptCodeCnt, 
      DHCPInfoCallBack * dhcpInfoCB, void * context)
{
   uint32_t xid;
   time_t timer;
   struct timeval tv;
   sockfd_t sockfd; 
   int retries;
   struct sockaddr_storage sendaddr;
   unsigned char chaddr[MAX_MACADDR_SIZE];
   unsigned char hlen, htype;
   uint8_t sndbuf[512];
   uint8_t rcvbuf[512];
   struct hostent * hep;
   uint8_t * p;
   int rcvbufsz = 0;
   char host[256];

   /* Get our IP and MAC addresses */
   if (gethostname(host, (int)sizeof(host))
         || (hep = gethostbyname(host)) == 0
         || dhcpGetAddressInfo((unsigned char *)hep->h_addr, 
               chaddr, &hlen, &htype))
      return -1;

   /* get a reasonably random transaction id value */
   xid = (uint32_t)time(&timer);

   /* BOOTP request header */
   p = sndbuf;
   *p++ = BOOTREQUEST;        /* opcode */
   *p++ = htype;
   *p++ = hlen;
   *p++ = 0;                  /* hops */
   PutUINT32(&p, xid);
   PutUINT16(&p, 0);          /* seconds */
   PutUINT16(&p, 0);          /* flags */
   memcpy(p, hep->h_addr, 4); /* ciaddr */
   p += 4;
   PutUINT32(&p, 0);          /* yiaddr */
   PutUINT32(&p, 0);          /* siaddr */
   PutUINT32(&p, 0);          /* giaddr */
   memcpy(p, chaddr, hlen);   /* chaddr */
   p += hlen;
   memset(p, 0, 16-hlen);     /* remaining chaddr space */
   p += 16-hlen;
   memset(p, 0, 64 + 128);    /* server host name, boot file */
   p += 64 + 128;

   /* BOOTP options field */
   *p++ = DHCP_COOKIE1;       /* options, cookies 1-4 */
   *p++ = DHCP_COOKIE2;
   *p++ = DHCP_COOKIE3;
   *p++ = DHCP_COOKIE4;

   /* DHCP Message Type option */
   *p++ = TAG_DHCP_MSG_TYPE;
   *p++ = 1;                  /* option length */
   *p++ = DHCP_MSG_INFORM;    /* message type is DHCPINFORM */

   /* DHCP Parameter Request option */
   *p++ = TAG_DHCP_PARAM_REQ; /* request for DHCP parms */
   *p++ = (unsigned char)dhcpOptCodeCnt;
   memcpy(p, dhcpOptCodes, dhcpOptCodeCnt);
   p += dhcpOptCodeCnt;

   /* DHCP Client Identifier option */
   *p++ = TAG_CLIENT_IDENTIFIER;
   *p++ = hlen + 1;           /* option length */
   *p++ = htype;              /* client id is htype/haddr */
   memcpy(p, chaddr, hlen);
   p += hlen;

   /* End option */
   *p++ = TAG_END;

   /* get a broadcast send/recv socket and address */
   if ((sockfd = dhcpCreateBCSkt(&sendaddr)) == SLP_INVALID_SOCKET)
      return -1;

   /* setup select timeout */
   tv.tv_sec = 0;
   tv.tv_usec = INIT_TMOUT_USECS;

   retries = 0;
   srand((unsigned)time(&timer));
   while (retries++ < MAX_DHCP_RETRIES)
   {
      if (dhcpSendRequest(sockfd, sndbuf, p - sndbuf, 
            &sendaddr, sizeof(sendaddr), &tv) < 0)
      {
         if (errno != ETIMEDOUT)
         {
            closesocket(sockfd);
            return -1;
         }
      }
      else if ((rcvbufsz = dhcpRecvResponse(sockfd, rcvbuf, 
            sizeof(rcvbuf), &tv)) < 0)
      {
         if (errno != ETIMEDOUT)
         {
            closesocket(sockfd);
            return -1;
         }
      }
      else if (rcvbufsz >= 236 && AS_UINT32(&rcvbuf[4]) == xid)
         break;

      /* exponential backoff randomized by a 
       * uniform number between -1 and 1 
      */
      tv.tv_usec = tv.tv_usec * 2 + (rand() % 3) - 1;
      tv.tv_sec = tv.tv_usec / USECS_PER_SEC;
      tv.tv_usec %= USECS_PER_SEC;
   }
   closesocket(sockfd);
   return rcvbufsz? dhcpProcessOptions(rcvbuf + 236, rcvbufsz - 236, 
         dhcpInfoCB, context): -1;
}