struct LL_IP *DHCP_IPAllocate(int nDhcpType, struct in_addr *pPreviousAddr, const unsigned char *pMac, int nMacLen) { int Rc=1; struct LL_IP *pCurIP; ULONG dummy_mac[2]; int dummy_maclen = sizeof dummy_mac; do { pCurIP = DHCP_IPAllocate2 (pPreviousAddr, pMac, nMacLen); // 2010/09/27 Colin from Shangai points out that ICMP check should be done only for DISCOVER if (pCurIP!=NULL && sSettings.bPing && nDhcpType==DHCPDISCOVER) { // frees the ARP cache and send an ARP request ArpDeleteHost (pCurIP->dwIP); SendARP(pCurIP->dwIP.s_addr, 0, dummy_mac, &dummy_maclen); Rc = PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT && PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT && PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT ; if (!Rc) { LOG (2, "Suppress pingable address %s", inet_ntoa (pCurIP->dwIP)); DHCPReallocItem (pCurIP, pCurIP->dwIP.s_addr, FREE_DHCP_ADDRESS, 6); SetRenewTime (pCurIP); } } // bPing Settings } while (pCurIP!=NULL && !Rc); return pCurIP; }
// Search in configuration file/registry by Mac Address struct LL_IP *DHCPSearchByRegistry (const unsigned char *pMac, int nMacLen) { int Rc; HKEY hKey; char szIP[20]; DWORD dwSize; if (nMacLen!=6) return NULL; // work only for Ethernet and Token Ring szIP[0] = 0; Rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, // Key handle at root level. TFTPD32_DHCP_KEY, // Path name of child key. 0, // Reserved. KEY_READ, // Requesting read access. & hKey) == ERROR_SUCCESS; // Address of key to be returned. if (Rc) READKEY (haddrtoa(pMac, nMacLen), szIP); CloseHandle (hKey); if (isdigit (szIP[0])) // entry has been found return DHCPReallocItem (NULL, inet_addr (szIP), pMac, nMacLen); return NULL; } // DHCPSearchByRegistry
struct LL_IP *DHCP_IPAllocate2(struct in_addr *pPreviousAddr, const unsigned char *pMac, int nMacLen) { time_t tNow; int Ark; struct LL_IP *pCurIP /*, *pOldestIP*/; #define TWO_MINUTES 120 //If true, the client has requested an IP address that we should try to honor int useprev = (pPreviousAddr->s_addr != INADDR_ANY) && (AddrFitsPool(pPreviousAddr)); // search for the previously allocated mac address if (nMacLen>=6) // Ethernet Mac address { // search if mac the mac address is already known pCurIP = DHCPSearchByMacAddress (pMac, nMacLen); if(pCurIP) { //We found the previous MAC record. If the address requested is invalid, use //the address in the record. If it is valid, erase the record, since we should //give the requested address if(!useprev || (pPreviousAddr->s_addr == pCurIP->dwIP.s_addr)) { LOG (12, "Reply with previously allocated : %s", inet_ntoa (pCurIP->dwIP)); SetAllocTime(pCurIP); return pCurIP; } else //Remove the old address, and continue with the allocation logic { //Destroying the item takes care of the macaddr table as well. DHCPDestroyItem (pCurIP); pCurIP = NULL; } } // mac address found } // mac address not valid // search if requested address can be granted if(useprev) { // is the address already allocated but not renewed (or expired) BOOL wasexpired=FALSE; pCurIP = DHCPSearchByIP (pPreviousAddr, &wasexpired); if (pCurIP!=NULL) { //Only allocate if it's to the same address, or the lease expired, //otherwise reset for the real allocation if(wasexpired || (0 == memcmp(pCurIP->sMacAddr, pMac, nMacLen))) { LOG (5, "Request for %s granted", inet_ntoa (pCurIP->dwIP)); pCurIP = DHCPReallocItem (pCurIP, pPreviousAddr->s_addr, pMac, nMacLen); return pCurIP ; } else pCurIP = NULL; } else //Address not allocated before, just grant it { pCurIP = DHCPReallocItem (NULL, pPreviousAddr->s_addr, pMac, nMacLen); LOG (12, "Reply with requested address : %s", inet_ntoa (pCurIP->dwIP)); return pCurIP; } // } // Requested address asked // A new IP address should be allocated : // First check if the pool is large enough in order to allocate a new address if (sParamDHCP.nPoolSize>0 && nAllocatedIP < sParamDHCP.nPoolSize) { // search for an "hole" in the struct or take last elem + 1 // if an item was allocated and the first item is the first in pool //Don't allocate ip addresses ending in 0 or 255 if (nAllocatedIP>0 && tFirstIP[0]->dwIP.s_addr == sParamDHCP.dwAddr.s_addr) { for ( Ark=1 ; Ark<nAllocatedIP && ntohl (tFirstIP[Ark]->dwIP.s_addr) == AddrInc(tFirstIP[Ark-1]->dwIP); Ark ++ ); pCurIP = DHCPReallocItem (NULL, htonl (AddrInc(tFirstIP[Ark-1]->dwIP)), pMac, nMacLen); } else pCurIP = DHCPReallocItem (NULL, sParamDHCP.dwAddr.s_addr, pMac, nMacLen); // New address : ntohl (tFirstIP[Ark]->dwIP.s_addr) + 1 // it is OK if Ark has reach nAllocatedIP LOG (12, "Reply with new : %s", inet_ntoa (pCurIP->dwIP)); return pCurIP; } // new allocation // no free address, have to reuse an "old" one // try addresses which have not been acknowledged (tAllocated+2 minutes), // or that have expired // time (&tNow); for (Ark=0 ; Ark<nAllocatedIP; Ark++) { pCurIP = tFirstIP[Ark]; if ( pCurIP->tAllocated+TWO_MINUTES < tNow && ((pCurIP->tRenewed==0) || (tNow > pCurIP->tRenewed + (sParamDHCP.nLease * 60)))) { pCurIP = DHCPReallocItem (pCurIP, pCurIP->dwIP.s_addr, pMac, nMacLen); LOG (12, "Reply with reuse : %s", inet_ntoa (pCurIP->dwIP)); return pCurIP; } } // reuse an unacknowledged address /* Since we are replacing holes, unacked, and expired addresses, all addresses are currently used // search for the oldest one (use tAllocated and tRenewed) for (Ark=0, pOldestIP=NULL ; Ark<nAllocatedIP; Ark++) { pCurIP = tFirstIP[Ark]; if ( pCurIP->tRenewed!=0 && pCurIP->tRenewed < (unsigned) (pOldestIP==NULL ? 0xFFFFFFFF : pOldestIP->tRenewed ) && PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT && PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT && PingApi (&pCurIP->dwIP, DHCP_PINGTIMEOUT, NULL)==PINGAPI_TIMEOUT ) pOldestIP=pCurIP; } // search for oldest item in pOldestIP if (pOldestIP != NULL) { pCurIP = DHCPReallocItem (pOldestIP, pOldestIP->dwIP.s_addr, pMac, nMacLen); LOG (12, "Reply with reuse : %s", inet_ntoa (pCurIP->dwIP)); return pCurIP; // can be NULL } */ return NULL; } // DHCP_IPAllocate2