Exemple #1
0
int ProcessDHCPMessage (struct dhcp_packet *pDhcpPkt, int *pSize)
{
unsigned char *p=NULL;
struct LL_IP  *pCurIP=NULL, *pProposedIP=NULL;	// Thanks Sam Leitch !
int            Ark, nDhcpType = 0;
struct in_addr sRequestedAddr;
DWORD sStaticIP;

    if (IsDHCP (*pDhcpPkt))
    {
       // search DHCP message type
       p = DHCPSearchOptionsField (pDhcpPkt->options, DHO_DHCP_MESSAGE_TYPE, NULL);
       if (p!=NULL)        nDhcpType = *p;
     }
    if (pDhcpPkt->yiaddr.s_addr!=INADDR_ANY  &&  pDhcpPkt->yiaddr.s_addr!=INADDR_NONE )
            return FALSE ; // address already assigned

     // the tab has one undef raw
     for (Ark=0 ; Ark<SizeOfTab(tDHCPType)-1 && nDhcpType!=tDHCPType[Ark].nType ; Ark++) ;
     LOG (5, "Rcvd %s Msg for IP %s, Mac %s",
                      tDHCPType[Ark].sType,
                      inet_ntoa (pDhcpPkt->ciaddr),
                      haddrtoa(pDhcpPkt->chaddr, pDhcpPkt->hlen,':'));


    // if (sParamDHCP.nPoolSize==0) return FALSE;   // no allocation pool --> listen only

     switch (nDhcpType)
     {
        case 0           :    // BootP
            if(sParamDHCP.nIgnoreBootp)
            {
               LOG (5, "Ignoring Bootp request");
               break;
            }
        case DHCPDISCOVER :
            sStaticIP = DHCP_StaticAssignation (pDhcpPkt);
			if (sStaticIP != INADDR_NONE)
			{
               LOG (0, "%s: statically assigned to address %s", 
								haddrtoa(pDhcpPkt->chaddr, pDhcpPkt->hlen,':'), 
								inet_ntoa (* (struct in_addr *) & sStaticIP) );
               pDhcpPkt->yiaddr.s_addr = sStaticIP;
			}
			else
			{
               p  = DHCPSearchOptionsField (pDhcpPkt->options, DHO_DHCP_REQUESTED_ADDRESS, NULL);
               if (p!=NULL)
              {
                   pDhcpPkt->ciaddr = * (struct in_addr *) p;
                   LOG (5, "Client requested address %s", inet_ntoa (pDhcpPkt->ciaddr));
              }
              pProposedIP  = DHCP_IPAllocate (nDhcpType, & pDhcpPkt->ciaddr, pDhcpPkt->chaddr, pDhcpPkt->hlen);
              if (pProposedIP == NULL)
              {
                  LOG (1, "no more address or address previously allocated by another server");
                  return FALSE;
              }
              pDhcpPkt->yiaddr.s_addr = pProposedIP->dwIP.s_addr;
              LOG (2, "%s: proposed address %s", IsDHCP(*pDhcpPkt) ? "DHCP" : "BOOTP", inet_ntoa (pProposedIP->dwIP) );

              //If this is a bootp, there is no other response from the client.  
              //Since we don't want leases expiring (or being mistaken for unAcked DHCP offers),
              //set renewed to a distant time
              if(nDhcpType == 0  &&  sStaticIP == INADDR_NONE)     // patched by Rolf Offermanns
                  ForceRenewTime(pProposedIP, 0x66666666);         // fixed by Sam Leitch
            } // dynamically assigned address

            // populate the packet to be returned
            pDhcpPkt->op = BOOTREPLY;
            // translate $IP$ and $MAC$ from boot file name
            TranslateExp (sParamDHCP.szBootFile, pDhcpPkt->file, pDhcpPkt->yiaddr, pDhcpPkt->chaddr);
           *pSize = DHCPOptionsReply (pDhcpPkt, DHCPOFFER);
            break ;

		//NJW Changed how requests are handled to mimic linux -- requests are responded to even if we didn't originally allocate, but only if the requested address is in our pool range

        case DHCPREQUEST :
         {BOOL bSERVER = FALSE;  // TRUE if Tftpd32 has assigned this address
           // Static Allocation ?
             // search field REQUEST ADDR in options
            sStaticIP = DHCP_StaticAssignation (pDhcpPkt);
			if (sStaticIP != INADDR_NONE)
			{
			    // populate the packet to be returned
                   pDhcpPkt->op = BOOTREPLY;
                   pDhcpPkt->yiaddr.s_addr = sStaticIP;
                 // translate $IP$ and $MAC$ from boot file name
                 TranslateExp (sParamDHCP.szBootFile, pDhcpPkt->file, pDhcpPkt->yiaddr, pDhcpPkt->chaddr);
                   *pSize = DHCPOptionsReply (pDhcpPkt, DHCPACK);
				   break;
			}

           // has tftpd32 dinamically assigned this address
           pCurIP = DHCPSearchByMacAddress (pDhcpPkt->chaddr, pDhcpPkt->hlen);
           if (pCurIP==NULL)  return FALSE; // not attributed by Tftpd32 --> do not answer
           // search field REQUEST ADDR in options
            // if specified should fit database
			p  = DHCPSearchOptionsField (pDhcpPkt->options, DHO_DHCP_REQUESTED_ADDRESS, NULL);
            if (p!=NULL)
			{
				pDhcpPkt->ciaddr = * (struct in_addr *) p;
			}

			if(AddrFitsPool(&pDhcpPkt->ciaddr))
			{
				//Look up the address, if it's not found, or the owner is this macaddr,
				//or the lease was expired, allow the serving.
				BOOL wasexpired = FALSE;
				pProposedIP = DHCPSearchByIP(&pDhcpPkt->ciaddr, &wasexpired);
				bSERVER = !pProposedIP || wasexpired || (0 == memcmp(pProposedIP->sMacAddr, pDhcpPkt->chaddr, 6));
			}

			if (bSERVER)
			{

				pProposedIP  = DHCP_IPAllocate (nDhcpType, & pDhcpPkt->ciaddr, pDhcpPkt->chaddr, pDhcpPkt->hlen);
				if (pProposedIP == NULL)
				{
					  LOG (1, "no more addresses or address previously allocated by another server");
					  return FALSE;
				}
				if (pProposedIP->tAllocated==0) SetAllocTime(pProposedIP);
				SetRenewTime(pProposedIP);
				LOG (5, "Previously allocated address %s acked", inet_ntoa (pProposedIP->dwIP));
				// populate the packet to be returned
				pDhcpPkt->op = BOOTREPLY;
				pDhcpPkt->yiaddr.s_addr = pProposedIP->dwIP.s_addr;
                TranslateExp (sParamDHCP.szBootFile, pDhcpPkt->file, pDhcpPkt->yiaddr, pDhcpPkt->chaddr);
				*pSize = DHCPOptionsReply (pDhcpPkt, DHCPACK);
			}
			else
			{
				LOG (5, "Client requested address %s which was not allocated by tftpd32 and is either outside our pool or is used by someone else",
							  inet_ntoa (pDhcpPkt->ciaddr) );
				return FALSE ; // do not answer
 			}
           } // Block for bSERVER declaration
           break;


        case DHCPDECLINE :
             // search current item and its precedent
          pCurIP = DHCPSearchByMacAddress (pDhcpPkt->chaddr, pDhcpPkt->hlen);
           if (pCurIP!=NULL)
           {
             p  = DHCPSearchOptionsField (pDhcpPkt->options, DHO_DHCP_REQUESTED_ADDRESS, NULL);
             if (p!=NULL) 
              {
                 sRequestedAddr.s_addr = * (DWORD *) p;
                 if ( pCurIP->dwIP.s_addr==sRequestedAddr.s_addr) 
                 {
                     DHCPDestroyItem (pCurIP);
                     LOG (5, "item destroyed");
                 }
             }
           }
		   //The decline is sent when an address is already in use.  Do an ARP and 
		   //add a lease for the in-use address
		   {
			 ULONG mac[2];
			 ULONG maclen = 6;
			// search field REQUEST ADDR in options
			// if specified should fit database
			p  = DHCPSearchOptionsField (pDhcpPkt->options, DHO_DHCP_REQUESTED_ADDRESS, NULL);
			if (p!=NULL)
			{
				pDhcpPkt->ciaddr = * (struct in_addr *) p;
			}

			 if(NO_ERROR == SendARP(pDhcpPkt->ciaddr.s_addr, 0, mac, &maclen))
			 {
				pProposedIP  = DHCP_IPAllocate (nDhcpType, & pDhcpPkt->ciaddr, (unsigned char*)mac, maclen);
				if (pProposedIP)
				{
					if (pProposedIP->tAllocated==0) SetAllocTime(pProposedIP);
					ForceRenewTime(pProposedIP, 0x66666666);   //Give a bootp lease, since the device may not do dhcp      
					LOG (5, "Added lease for existing address %s", inet_ntoa (pProposedIP->dwIP));
				}
			 }
		   }
           break;

        case DHCPRELEASE :
            // do not destroy the item but mark it free
           pCurIP = DHCPSearchByMacAddress (pDhcpPkt->chaddr, pDhcpPkt->hlen);
           if (pCurIP!=NULL) // then mac address found in table
           {
                ZeroAllocTime(pCurIP);
                ZeroRenewTime(pCurIP);
                LOG (5, "item %s released", haddrtoa(pDhcpPkt->chaddr, pDhcpPkt->hlen,':') );
           }
           break;
       } // switch type


DHCPScan();

// answer only to BootP, Request or discover msg
return  (nDhcpType==0 || nDhcpType==DHCPDISCOVER || nDhcpType==DHCPREQUEST);
} // ProcessDHCPMessage
Exemple #2
0
//////////////////////////////////////////////////////////////////////////////////////////////
// AddOption Translation
// Translates the option values into a value
// Use the SnmpCmd syntax ("a ip @" "s string", "i integer", "x string", "u unsigned")
//////////////////////////////////////////////////////////////////////////////////////////////
int TranslateParam2Value (char *buffer, int len, const char *opt_val, struct in_addr ip, const char *tMac)
{
char sz[256];
const char *p, *q;
int  nIPAddr, nLen, c;
// the number of bytes used by n hexa digit 0xABCDE which has 5 digits will form a 4-byte number)
static const char cvt[] = { 0, 1, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8 };
   if (opt_val[1] == ' ')
   { 
       p = opt_val+2;	// p points on data 
	   switch (opt_val [0])
	   {
			case 'a' : // list of IP address
				for (nIPAddr=0 ;  *p!=0 && nIPAddr*4<len-4; nIPAddr++ ) 
				{
				  * ((unsigned long *) buffer + nIPAddr) = inet_addr (p);
				   while ( *p!=0 &&  (isdigit(*p) || *p=='.') )  p++;  // go to end of address
				   while ( *p!=0 && *p==' ' ) p++;	// skip spaces
				}
				return nIPAddr * sizeof (unsigned long);
			case 's' : // string
					lstrcpyn (sz, p, len);
					TranslateExp (sz, buffer, ip, tMac);
					buffer [len-1] = 0;
					return lstrlen (buffer);
			case 'I' :	// integer 
			    * (unsigned short *) buffer = atoi (p);
				return sizeof (unsigned short);
			case 'i' :	// integer 
			    * (unsigned long *) buffer = atoi (p);
				return sizeof (unsigned long);
			case 'N' :	// integer network order
			    * (unsigned short *) buffer = htons (atoi (p));
				return sizeof (unsigned short);
			case 'n' :	// integer long network order
			    * (unsigned long *) buffer = htonl (atoi (p));
				return sizeof (unsigned long);			
			case 'b' :	// list of 1 (b)yte digits
				for (nLen=0 ;  *p!=0 && nLen<len-1; nLen++ ) 
				{					
					sscanf(p, "%u", & c);  
					buffer [nLen] = (char) c;  
				    while ( *p!=0 && isdigit(*p) ) p++;	// to next digit
 				    while ( *p!=0 && (*p==' ' || *p=='.' || *p==':') ) p++;	// skip spaces
				}
				return nLen;
			case 'x' :	// list of he(x) digits
				for (nLen=0 ;  *p!=0 && nLen<len-8; p = q ) 
				{					
					for ( q = p; isxdigit(*q) ; q++ );  // search next field
					switch (  cvt [ min (q-p, 8) ]  )
					{
						case 1 : sscanf(p, "%x", & c);  buffer [nLen] = (char) c;  break;
						case 2 : sscanf(p, "%hx",  buffer+nLen); break;
						case 4 : sscanf(p, "%lx",  buffer+nLen); break;
						case 8 : sscanf(p, "%llx", buffer+nLen); break;
					}
				   nLen += cvt [min (q-p, 8)] ;
				   while ( *q!=0 && (*q==' ' || *q=='.' || *q==':') ) q++;	// skip spaces
				}
				return nLen;
	   } // switch opt_val[0]
   }
   // non trouve --> conserver la chaine
	lstrcpyn (sz, opt_val, len);
	TranslateExp (sz, buffer, ip, tMac);
	( (char *) buffer) [len-1] = 0;
	return lstrlen (buffer);
} // TranslateParam2Value
Exemple #3
0
//////////////////////////////////////////////////////////////////////////////////////////////
// fill DHCP fields
//////////////////////////////////////////////////////////////////////////////////////////////
int DHCPOptionsReply (struct dhcp_packet  *pDhcpPkt, int nDhcpType)
{
unsigned char  *pOpt = (unsigned char *) (pDhcpPkt->options + (sizeof DHCP_OPTIONS_COOKIE - 1));
HANDLE            hFile;
struct in_addr *pNearest;
int             Ark, Evan;
char            sz[256];
static struct S_DhcpOptions sDhcpOpt [] =       // 0 for unspecified
{
    DHO_DHCP_MESSAGE_TYPE,      1,	  ~TFTPD32_NONE,
    DHO_DHCP_SERVER_IDENTIFIER, 4,	  ~TFTPD32_NONE,
    DHO_SUBNET_MASK,            4,	  ~TFTPD32_NONE,
    DHO_ROUTERS,                4,	  ~TFTPD32_NONE,
    DHO_DOMAIN_NAME_SERVERS,    4,	  ~TFTPD32_NONE,
    DHO_LOG_SERVERS,            4,	   TFTPD32_SYSLOG_SERVER,
    DHO_NETBIOS_NAME_SERVERS,   4,	  ~TFTPD32_NONE,
    DHO_DHCP_LEASE_TIME,        4,	  ~TFTPD32_NONE,
    DHO_DHCP_RENEWAL_TIME,      4,	  ~TFTPD32_NONE,
    DHO_DHCP_REBINDING_TIME,    4,	  ~TFTPD32_NONE,
    DHO_BOOT_SIZE,              0,	   TFTPD32_TFTP_SERVER,
    DHO_DOMAIN_NAME,            0,	  ~TFTPD32_NONE,
    DHO_CUSTOM,                 0,	  ~TFTPD32_NONE,
    DHO_END,                    0,	  ~TFTPD32_NONE,
};

	//Always pack the magic cookie again, just in case it was corrupted
	*(DWORD*)(pDhcpPkt->options) = * (DWORD*) DHCP_OPTIONS_COOKIE;

	// pNearest points on the "good" LAN interface
   pNearest = FindNearestServerAddress (&pDhcpPkt->yiaddr, & sParamDHCP.dwMask, FALSE);
   //HACK -- If we are the bootp server, we are also the tftpserver
   if (sSettings.uServices & TFTPD32_TFTP_SERVER) 
      pDhcpPkt->siaddr = *pNearest;   // Next server (TFTP server is enabled)
   for (Ark=0 ; Ark<SizeOfTab(sDhcpOpt) ; Ark++)
   {
	 // skip if linked to a service which is not started (change suggested by Colin)
	 if (! (sSettings.uServices & sDhcpOpt[Ark].nServices)) 
			continue;

     if (sDhcpOpt[Ark].nLen!=0) 
     {
        *pOpt++ = (unsigned char) sDhcpOpt[Ark].nDHCPOpt ; 
        *pOpt++ = (unsigned char) sDhcpOpt[Ark].nLen;
      }
      switch (sDhcpOpt[Ark].nDHCPOpt)
      {
       case DHO_DHCP_MESSAGE_TYPE       :  * pOpt = (unsigned char) nDhcpType ; break ; 
       case DHO_LOG_SERVERS             :  // fallthrough
       case DHO_DHCP_SERVER_IDENTIFIER  :  * (DWORD *) pOpt = pNearest->s_addr; break ;
       case DHO_SUBNET_MASK             :  * (DWORD *) pOpt = sParamDHCP.dwMask.s_addr; break ;
       case DHO_ROUTERS                 :  * (DWORD *) pOpt = (sParamDHCP.dwGateway.s_addr == 0xffffffff ? pDhcpPkt->yiaddr.s_addr : sParamDHCP.dwGateway.s_addr); break ;
       case DHO_NETBIOS_NAME_SERVERS    :
       case DHO_DOMAIN_NAME_SERVERS     :  * (DWORD *) pOpt = sParamDHCP.dwDns.s_addr;  break; 
       case DHO_DHCP_LEASE_TIME         :  * (DWORD *) pOpt = htonl (sParamDHCP.nLease * 60);  break ;
       case DHO_DHCP_RENEWAL_TIME       :
       case DHO_DHCP_REBINDING_TIME     :  * (DWORD *) pOpt = htonl (sParamDHCP.nLease/2 * 60);  break ;
       case DHO_BOOT_SIZE               :
              // translate $IP$ and $MAC$ from boot file name
              TranslateExp (sParamDHCP.szBootFile, sz, pDhcpPkt->yiaddr, pDhcpPkt->chaddr);
              hFile = CreateFile(sz,        // open the file
                                 GENERIC_READ,                 // open for reading
                                 FILE_SHARE_READ,              // share for reading
                                 NULL,                         // no security
                                 OPEN_EXISTING,                // existing file only
                                 FILE_ATTRIBUTE_NORMAL,       // normal file
                                 NULL);                       // no attr. template
               if (hFile != INVALID_HANDLE_VALUE)
               {
                  *pOpt++ = DHO_BOOT_SIZE ;
                  *pOpt++ = sizeof (unsigned short);
                  * (unsigned short *) pOpt = htons ( (unsigned short) (1+GetFileSize (hFile, NULL) / 512) ) ;
                  pOpt += sizeof (unsigned short);
                  CloseHandle( hFile ) ;         // close the file
               }
              break;
        case DHO_DOMAIN_NAME             :
             if (sParamDHCP.szDomainName[0]!=0)
             {
                  *pOpt++ = DHO_DOMAIN_NAME;
                  *pOpt   = lstrlen (sParamDHCP.szDomainName);
                   memcpy (pOpt+1, sParamDHCP.szDomainName, *pOpt);
                   pOpt += 1+*pOpt; 
              }
              break;
     case DHO_CUSTOM : // Manage custom options
         for (Evan=0 ; Evan < SizeOfTab (sParamDHCP.t) ; Evan++)
                if (sParamDHCP.t[Evan].nAddOption != 0)
                {
                   *pOpt++ = (unsigned char) sParamDHCP.t[Evan].nAddOption;
				   *pOpt = TranslateParam2Value (pOpt+1, 64, sParamDHCP.t[Evan].szAddOption, pDhcpPkt->yiaddr, pDhcpPkt->chaddr);
                   pOpt += 1+*pOpt;
               }
              break;
     case DHO_END                     : 
                 *pOpt++ = DHO_END;
                 *pOpt++ = DHO_PAD;
                 *pOpt++ = DHO_PAD;
                 break;
       } // switch option
     pOpt += sDhcpOpt[Ark].nLen ;    // points on next field
   } // for all option

return (int) (pOpt - (unsigned char*) pDhcpPkt);
} // DHCPOptionsReply