//Read in and initialize the leases void LoadLeases(void) { //We need to make sure the leases we load actually fit in the address pool, so we'll be //tracking the index to the lease file and the index to the allocated list int leaseindex, allocindex; // From Nick : I realized that there was a race condition in that code, // particularly with the reading and saving of KEY_LEASE_NUMLEASES // I’ve added a function, which LoadLeases calls immediately on entry: WaitForMsgQueueToFinish (LL_ID_SETTINGS); nAllocatedIP = 0; ReadKey(TFTPD32_DHCP_KEY, KEY_LEASE_NUMLEASES, &nAllocatedIP, sizeof(nAllocatedIP), REG_DWORD, szTftpd32IniFile); if (nAllocatedIP > sParamDHCP.nPoolSize) { SVC_WARNING ("The pool size is too small for the number of leases, ignoring extra leases"); nAllocatedIP = sParamDHCP.nPoolSize; } allocindex = 0; for(leaseindex = 0; leaseindex < nAllocatedIP; ++leaseindex) { char key [_MAX_PATH]; char tmpval [_MAX_PATH]; tFirstIP[allocindex] = malloc (sizeof(struct LL_IP)); memset(tFirstIP[allocindex], 0, sizeof(struct LL_IP)); tFirstIP[allocindex]->dwAllocNum = leaseindex; sprintf(key, "%s%d%s", KEY_LEASE_PREFIX, leaseindex, KEY_LEASE_MAC); if(ReadKey(TFTPD32_DHCP_KEY, key, tmpval, _MAX_PATH, REG_SZ, szTftpd32IniFile)) atohaddr(tmpval, tFirstIP[allocindex]->sMacAddr, 6); sprintf(key, "%s%d%s", KEY_LEASE_PREFIX, leaseindex, KEY_LEASE_IP); if(ReadKey(TFTPD32_DHCP_KEY, key, tmpval, _MAX_PATH, REG_SZ, szTftpd32IniFile)) tFirstIP[allocindex]->dwIP.s_addr = inet_addr(tmpval); sprintf(key, "%s%d%s", KEY_LEASE_PREFIX, leaseindex, KEY_LEASE_ALLOC); if(ReadKey(TFTPD32_DHCP_KEY, key, tmpval, _MAX_PATH, REG_SZ, szTftpd32IniFile)) tFirstIP[allocindex]->tAllocated = atotime(tmpval); sprintf(key, "%s%d%s", KEY_LEASE_PREFIX, leaseindex, KEY_LEASE_RENEW); if(ReadKey(TFTPD32_DHCP_KEY, key, tmpval, _MAX_PATH, REG_SZ, szTftpd32IniFile)) tFirstIP[allocindex]->tRenewed = atotime(tmpval); // fix errors in date conversion (registry modified at hand) if (tFirstIP[allocindex]->tAllocated == -1) tFirstIP[allocindex]->tAllocated = 0; if (tFirstIP[allocindex]->tRenewed == -1) tFirstIP[allocindex]->tRenewed = 0; //If the address doesn't fit in the pool, don't add it after all //Since we are assuming the leases were written in order, do a quick check for dups //and invalid macaddrs if((!AddrFitsPool(&tFirstIP[allocindex]->dwIP)) || (IsMacEmpty(tFirstIP[allocindex])) || ((allocindex > 0) && (tFirstIP[allocindex]->dwIP.s_addr == tFirstIP[allocindex - 1]->dwIP.s_addr))) { free(tFirstIP[allocindex]); tFirstIP[allocindex] = NULL; } else { tMAC[allocindex] = tFirstIP[allocindex]; //Copy to cross index ++allocindex; //Move on to the next one } } if(allocindex != nAllocatedIP) SetNumAllocated(allocindex); // ensure that data base is sorted (especially if we've dropped some leases in the load) qsort (tMAC, nAllocatedIP, sizeof *tMAC, MACCompare); qsort (tFirstIP, nAllocatedIP, sizeof *tFirstIP, QsortCompare); ReorderLeases(); } // LoadLeases
void ListenDhcpMessage (void *lpVoid) { struct dhcp_packet sDhcpPkt; char szHostname [128], *p; int Rc, nSize; struct S_WorkerParam *pParam = lpVoid; struct sockaddr_in SockFrom; int nFromLen = sizeof SockFrom; BOOL bUniCast; int True = 1; DHCPReadConfig (); Sleep (1000); //NJW Prompt to see if we should discover via ping before we start doing DHCP if(scanforleases) // && IDYES == CMsgBox(pParam->hWnd, "Should I reset the lease file and rediscover devices?", "Discover Devices", MB_YESNO)) { struct in_addr addr; int count; SetHourglass(TRUE); ReadKey(TFTPD32_DHCP_KEY, KEY_DHCP_POOL, & addr.s_addr, sizeof(addr.s_addr), REG_DWORD, szTftpd32IniFile); ReadKey(TFTPD32_DHCP_KEY, KEY_DHCP_POOLSIZE, &count, sizeof(count), REG_DWORD, szTftpd32IniFile); SetNumAllocated(0); FreeLeases(FALSE); if (sSettings.bPersLeases) LoadLeases (); if (sSettings.bPing) PingRange (&addr, count); // DHCPSaveConfig (); SetHourglass(FALSE); SVC_WARNING ("Lease file updated.\nDiscover Devices"); } // add broadcast permission to socket if (setsockopt (tThreads[TH_DHCP].skt, SOL_SOCKET, SO_BROADCAST, (char *) & True, sizeof True) != 0) { LOG (1, "can't set broadcast option.\nPlease, suppress DHCP server in the settings window"); LogToMonitor ("can't set broadcast option.\n"); tThreads[TH_DHCP].gRunning = FALSE; } while ( tThreads[TH_DHCP].gRunning ) { // send leases to GUI Dhcp_Send_Leases (tFirstIP, nAllocatedIP); memset (& sDhcpPkt, 0, sizeof sDhcpPkt); Rc = recvfrom ( tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, sizeof sDhcpPkt, 0, (struct sockaddr *) & SockFrom, & nFromLen); // recv error // since Tftpd32 sends broadcasts, it receives its own message, just ignore it if (Rc < 0) { if (GetLastError () != WSAECONNRESET) { LOG (1, "Recv error %d", GetLastError ()); Sleep (500); } continue; } // recv failed // if msg is too short // If all bootP fields have been read if (Rc < offsetof ( struct dhcp_packet, options )) { LOG (5, "Message truncated (length was %d)", Rc); if ( tThreads[TH_DHCP].gRunning ) Sleep (500); continue; } // if pool is empty and MAC address not statically assigned : ignore request if ( sParamDHCP.nPoolSize == 0 && DHCP_StaticAssignation (& sDhcpPkt)==INADDR_NONE ) { Sleep (100); continue; } // handle only nul-terminated strings sDhcpPkt.sname[sizeof sDhcpPkt.sname - 1] = 0; sDhcpPkt.file [sizeof sDhcpPkt.file - 1] = 0; // read host name, truncate it if (gethostname (szHostname , sizeof szHostname )==SOCKET_ERROR) lstrcpy (szHostname, "Tftpd32DchpServer"); if ((p=strchr (szHostname, '.'))!=NULL) *p=0; szHostname [sizeof sDhcpPkt.sname - 1] = 0; if (sDhcpPkt.sname[0]!=0 && lstrcmp (sDhcpPkt.sname, szHostname)!=0) { LOG (2, "Packet addressed to %s", sDhcpPkt.sname); continue; } // we have only to answer to BOOTREQUEST msg if (sDhcpPkt.op != BOOTREQUEST) { LOG (2, "%d Request %d not processed", GetCurrentThreadId (),sDhcpPkt.op); continue ; } // if request OK and answer ready bUniCast = ( SockFrom.sin_addr.s_addr!=htonl (INADDR_NONE) && SockFrom.sin_addr.s_addr!=htonl (INADDR_ANY) // fix 5/02/2006 : 127.0.0.2 should be handle as a broadcast && SockFrom.sin_addr.S_un.S_un_b.s_b1 != 127 ) ; // class A 127 if (ProcessDHCPMessage ( & sDhcpPkt, & nSize ) ) {struct servent *lpServEnt; // BinDump ((char *)&sDhcpPkt, sizeof sDhcpPkt, "DHCP"); SockFrom.sin_family = AF_INET; // if no source address was specified reply with a broadcast if (!bUniCast) SockFrom.sin_addr.s_addr = htonl (INADDR_NONE); // Added : DHCP relay detection --> send replies to port 67 and 68 // Colin and others point ourt that this is wrong. I guess they are right. // However it should not be an issue and i am sure that the host receive an address ! if (sDhcpPkt.giaddr.s_addr!=htonl(INADDR_ANY) || sDhcpPkt.giaddr.s_addr!=htonl(INADDR_NONE)) { // sends to port 67 lpServEnt = getservbyname ("bootps", "udp") ; SockFrom.sin_port = (lpServEnt != NULL) ? lpServEnt->s_port : htons (BOOTPS_PORT); Rc = sendto (tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, nSize, 0, (struct sockaddr *) & SockFrom, sizeof SockFrom); // and prepare for port 68 lpServEnt = getservbyname ("bootpc", "udp") ; SockFrom.sin_port = (lpServEnt != NULL) ? lpServEnt->s_port : htons (BOOTPC_PORT); } LOG (15, "Thread 0x%X: send %d bytes", GetCurrentThreadId(), nSize ); Rc = sendto (tThreads[TH_DHCP].skt, (char *) & sDhcpPkt, nSize, 0, (struct sockaddr *) & SockFrom, sizeof SockFrom); if (Rc<nSize) LOG (1, "sendto error %d: %s", GetLastError(), LastErrorText ()); } // ProcessDHCPMessage } // do it eternally LogToMonitor ("DHCP thread ends here\n"); _endthread (); } // ListenDhcpMessage