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
static int ProcessMsg (SOCKET s, const struct S_ConsoleMsg *pmsg) { struct LL_TftpInfo *pTftp; int uServices; LogToMonitor ("TFTPd console receive msg %d\n", pmsg->type); switch (pmsg->type) { case C_CONS_KILL_TRF : LOG (1, "transfer %d must be killed", pmsg->u.kill.dwTransferId); for ( pTftp=pTftpFirst ; pTftp!=NULL && pTftp->tm.dwTransferId != pmsg->u.kill.dwTransferId ; pTftp = pTftp->next ); if (pTftp != NULL) { nak (pTftp, ECANCELLED); pTftp->st.ret_code=TFTP_TRF_STOPPED; } break; case C_TFTP_TERMINATE : LogToMonitor ("terminating TFTP service\n"); tThreads[TH_TFTP].gRunning = FALSE; WakeUpThread (TH_TFTP); break; case C_DHCP_TERMINATE : LogToMonitor ("terminating DHCP service\n"); tThreads[TH_DHCP].gRunning = FALSE; // wake up DHCP thread WakeUpThread (TH_DHCP); break; case C_TERMINATE : LogToMonitor ("stopping services\n"); TerminateWorkerThreads (FALSE); // keep management threads break; case C_SUSPEND : LogToMonitor ("suspending services\n"); TerminateWorkerThreads (TRUE); // keep management threads break; case C_START : LogToMonitor ("starting services\n"); StartMultiWorkerThreads (TRUE); break; case C_DHCP_RRQ_SETTINGS : LogToMonitor ("sending DHCP settings\n"); SendMsg (s, C_DHCP_RPLY_SETTINGS, & sParamDHCP, sizeof sParamDHCP); break; case C_TFTP_RRQ_SETTINGS : LogToMonitor ("sending TFTP settings\n"); SendMsg (s, C_TFTP_RPLY_SETTINGS, & sSettings, sizeof sSettings); break; case C_DHCP_WRQ_SETTINGS : LogToMonitor ("storing new DHCP settings\n"); DHCPSaveConfig ( & pmsg->u.dhcp_settings ); break; case C_TFTP_WRQ_SETTINGS : LogToMonitor ("storing new TFTP settings\n"); {static struct S_RestartTable sRestart; sRestart.newservices = pmsg->u.tftp_settings.uServices; sRestart.oldservices = sSettings.uServices; sRestart.flapservices = 0; if ( sSettings.Port != pmsg->u.tftp_settings.Port || lstrcmp (sSettings.szTftpLocalIP, pmsg->u.tftp_settings.szTftpLocalIP )!=0 ) sRestart.flapservices |= TFTPD32_TFTP_SERVER; // restart syslog if its settings log has changed if ( sSettings.uServices & TFTPD32_SYSLOG_SERVER && ( sSettings.bSyslogPipe != pmsg->u.tftp_settings.bSyslogPipe || strcmp(sSettings.szSyslogFile,pmsg->u.tftp_settings.szSyslogFile)!= 0 ) ) sRestart.flapservices |= TFTPD32_SYSLOG_SERVER; sSettings = pmsg->u.tftp_settings; if ( IsValidDirectory ( pmsg->u.tftp_settings.szBaseDirectory ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.tftp_settings.szBaseDirectory, sizeof sSettings.szWorkingDirectory ); _beginthread ( Tftpd32UpdateServices, 0, (void *) & sRestart ); Tftpd32SaveSettings (); } break; case C_TFTP_RESTORE_DEFAULT_SETTINGS : LogToMonitor ("restore default settings\n"); Tftpd32DestroySettings (); break; case C_TFTP_CHG_WORKING_DIR : LogToMonitor ("changing working directory to <%s>\n", pmsg->u.working_dir); if ( IsValidDirectory ( pmsg->u.working_dir ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.working_dir, sizeof sSettings.szWorkingDirectory ); break; case C_RRQ_WORKING_DIR : LogToMonitor ("sending working directory <%s>\n", sSettings.szWorkingDirectory); SendMsg (s, C_REPLY_WORKING_DIR, sSettings.szWorkingDirectory, 1 + lstrlen (sSettings.szWorkingDirectory) ); break; case C_DELETE_ASSIGNATION : LogToMonitor ("deleting DHCP entry %X\n", pmsg->u.del_lease.ip); { struct in_addr addr; BOOL dummy; addr.s_addr = pmsg->u.del_lease.ip; DHCPDestroyItem ( DHCPSearchByIP ( & addr, &dummy ) ); } break; case C_RRQ_GET_SERVICES : LogToMonitor ("sending running services\n"); uServices = GetRunningThreads (); SendMsg (s, C_REPLY_GET_SERVICES, & uServices, sizeof uServices ); break; case C_RRQ_GET_INTERFACES : LogToMonitor ("sending IP interfaces"); AnswerIPList (); break; case C_RRQ_DIRECTORY_CONTENT : LogToMonitor ("sending Directory content"); SendDirectoryContent (); break; case C_TFTP_GET_FULL_STAT : LogToMonitor ("sending Directory content"); ConsoleTftpGetStatistics (); break; default : LogToMonitor ("Service received unknown message %d\n", pmsg->type); break; } return 1; } // ReadMsg
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