From 189f61d953b6e106871ff9dc9eba83613ffb453e Mon Sep 17 00:00:00 2001 From: huangxin Date: Wed, 26 Oct 2022 17:25:10 +0800 Subject: [PATCH] =?UTF-8?q?OCT=20=E6=B7=BB=E5=8A=A0DNS=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- srcs/dual_server/CMakeLists.txt | 13 + srcs/dual_server/dualserverd.cpp | 9765 ++++++++++++++++++++++++++++++ srcs/dual_server/dualserverd.h | 1121 ++++ srcs/dual_server/dualsvr.h | 18 + 4 files changed, 10917 insertions(+) create mode 100644 srcs/dual_server/CMakeLists.txt create mode 100644 srcs/dual_server/dualserverd.cpp create mode 100644 srcs/dual_server/dualserverd.h create mode 100644 srcs/dual_server/dualsvr.h diff --git a/srcs/dual_server/CMakeLists.txt b/srcs/dual_server/CMakeLists.txt new file mode 100644 index 0000000..664d4ed --- /dev/null +++ b/srcs/dual_server/CMakeLists.txt @@ -0,0 +1,13 @@ +SET(DHCPD_PROJECT_TARGET dualserverd) + +PROJECT(${DHCPD_PROJECT_TARGET} CXX) + +INCLUDE_DIRECTORIES(../libs/include ./) + +FILE(GLOB DHCPD_HEADS ./*.h) + +ADD_DEFINITIONS(-Wno-format-overflow -std=c++11) +#ADD_EXECUTABLE(${PROJECT_TARGET} opendhcpd.cpp ${DHCPD_HEADS}) +ADD_LIBRARY(${DHCPD_PROJECT_TARGET} dualserverd.cpp ${DHCPD_HEADS}) + +#TARGET_LINK_LIBRARIES(${PROJECT_TARGET} -lpthread) \ No newline at end of file diff --git a/srcs/dual_server/dualserverd.cpp b/srcs/dual_server/dualserverd.cpp new file mode 100644 index 0000000..b6980f8 --- /dev/null +++ b/srcs/dual_server/dualserverd.cpp @@ -0,0 +1,9765 @@ +/************************************************************************** +* Copyright (C) 2005 by Achal Dhir * +* achaldhir@gmail.com * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +// dualserver.cpp /// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCDFAInspection" +using namespace std; +#include "dualserverd.h" +#include "dualsvr.h" + +//Global Variables +data1 network; +data1 newNetwork; +data2 cfig; +bool verbatim = false; +data9 dhcpr; +data9 token; +data5 dnsr; +//data5 dnstcp; +MYBYTE currentInd = 0; +//MYBYTE newInd = 0; +data18 g_magin; +bool kRunning = true; +hostMap dnsCache[2]; +expiryMap dnsAge[2]; +dhcpMap dhcpCache; +char serviceName[] = "DUALServer"; +//expiryMap dhcpAge; +//char tempbuff[512] = ""; +//char extbuff[512]; +//char logBuff[256] = ""; +char exeFile[PATH_MAX] = ""; +char iniFile[PATH_MAX] = ""; +char leaFile[PATH_MAX] = ""; +char logFile[PATH_MAX] = ""; +char tempFile[PATH_MAX] = "/tmp/dualserver.tmp"; +char filePATH[PATH_MAX] = ""; +char htmlTitle[PATH_MAX] = ""; +char icoFile[PATH_MAX] = ""; +char *icoString = nullptr; +int icoSize = 0; +data71 g_lump; +char arpa[] = ".in-addr.arpa"; +char ip6arpa[] = ".ip6.arpa"; +bool dhcpService = true; +bool dnsService = true; +time_t t = time(nullptr); +timeval tv; +fd_set readfds; +//fd_set writefds; +pthread_mutex_t mutStateFile = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutLogFile = PTHREAD_MUTEX_INITIALIZER; +struct ifconf Ifc; +struct ifreq IfcBuf[MAX_SERVERS]; + +//constants +const char NBSP = 32; +const char RANGESET[] = "RANGE_SET"; +const char GLOBALOPTIONS[] = "GLOBAL_OPTIONS"; +//const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +//const char send200[] = "HTTP/1.1 200 OK\r\nDate: %s\r\nLast-Modified: %s\r\nContent-Type: text/html\r\nConnection: Close\r\nContent-Length: \r\n\r\n"; +//const char send200[] = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n"; +//const char send200[] = "HTTP/1.1 200 OK\r\nDate: %s\r\nLast-Modified: %s\r\nContent-Type: text/html\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n"; +//const char send403[] = "HTTP/1.1 403 Forbidden\r\nDate: %s\r\nLast-Modified: %s\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n"; +const char send403[] = "HTTP/1.1 403 Forbidden\r\n\r\n

403 Forbidden

"; +const char send404[] = "HTTP/1.1 404 Not Found\r\n\r\n

404 Not Found

"; +const char send200[] = "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nConnection: close\r\nContent-Length: %i\r\n\r\n"; +const char td200[] = "%s"; +const char tdnowrap200[] = "%s"; +const char sVersion[] = "Dual DHCP DNS Server Version 7.60 Linux Build 7057"; +const char htmlStart + [] = "\n\n%s\n\n\n"; +const char bodyStart + [] = "
\n
%s
Server: %s %s %shttp://dhcp-dns-server.sourceforge.net
"; +//const char bodyStart[] = "
%s
http://dhcp-dns-server.sourceforge.net/
"; +//const char bodyStart[] = "
%s
http://dhcp-dns-server.sourceforge.net
"; +//const char bodyStart[] = "
%s
%s
"; + +const data4 opData[] = { + {"SubnetMask", 1, 3, true}, + {"TimeOffset", 2, 4, true}, + {"Router", 3, 3, true}, + {"TimeServer", 4, 3, true}, + {"NameServer", 5, 3, true}, + {"DomainServer", 6, 3, true}, + {"LogServer", 7, 3, true}, + {"QuotesServer", 8, 3, true}, + {"LPRServer", 9, 3, true}, + {"ImpressServer", 10, 3, true}, + {"RLPServer", 11, 3, true}, + {"Hostname", 12, 1, true}, + {"BootFileSize", 13, 5, true}, + {"MeritDumpFile", 14, 1, true}, + {"DomainName", 15, 1, true}, + {"SwapServer", 16, 3, true}, + {"RootPath", 17, 1, true}, + {"ExtensionFile", 18, 1, true}, + {"ForwardOn/Off", 19, 7, true}, + {"SrcRteOn/Off", 20, 7, true}, + {"PolicyFilter", 21, 8, true}, + {"MaxDGAssembly", 22, 5, true}, + {"DefaultIPTTL", 23, 6, true}, + {"MTUTimeout", 24, 4, true}, + {"MTUPlateau", 25, 2, true}, + {"MTUInterface", 26, 5, true}, + {"MTUSubnet", 27, 7, true}, + {"BroadcastAddress", 28, 3, true}, + {"MaskDiscovery", 29, 7, true}, + {"MaskSupplier", 30, 7, true}, + {"RouterDiscovery", 31, 7, true}, + {"RouterRequest", 32, 3, true}, + {"StaticRoute", 33, 8, true}, + {"Trailers", 34, 7, true}, + {"ARPTimeout", 35, 4, true}, + {"Ethernet", 36, 7, true}, + {"DefaultTCPTTL", 37, 6, true}, + {"KeepaliveTime", 38, 4, true}, + {"KeepaliveData", 39, 7, true}, + {"NISDomain", 40, 1, true}, + {"NISServers", 41, 3, true}, + {"NTPServers", 42, 3, true}, + {"VendorSpecificInf", 43, 2, false}, + {"NETBIOSNameSrv", 44, 3, true}, + {"NETBIOSDistSrv", 45, 3, true}, + {"NETBIOSNodeType", 46, 6, true}, + {"NETBIOSScope", 47, 1, true}, + {"XWindowFont", 48, 1, true}, + {"XWindowManager", 49, 3, true}, + {"AddressRequest", 50, 3, false}, + {"AddressTime", 51, 4, true}, + {"OverLoad", 52, 7, false}, + {"DHCPMsgType", 53, 6, false}, + {"DHCPServerId", 54, 3, false}, + {"ParameterList", 55, 2, false}, + {"DHCPMessage", 56, 1, false}, + {"DHCPMaxMsgSize", 57, 5, false}, + {"RenewalTime", 58, 4, true}, + {"RebindingTime", 59, 4, true}, + {"ClassId", 60, 1, false}, + {"ClientId", 61, 2, false}, + {"NetWareIPDomain", 62, 1, true}, + {"NetWareIPOption", 63, 2, true}, + {"NISDomainName", 64, 1, true}, + {"NISServerAddr", 65, 3, true}, + {"TFTPServerName", 66, 1, true}, + {"BootFileOption", 67, 1, true}, + {"HomeAgentAddrs", 68, 3, true}, + {"SMTPServer", 69, 3, true}, + {"POP3Server", 70, 3, true}, + {"NNTPServer", 71, 3, true}, + {"WWWServer", 72, 3, true}, + {"FingerServer", 73, 3, true}, + {"IRCServer", 74, 3, true}, + {"StreetTalkServer", 75, 3, true}, + {"STDAServer", 76, 3, true}, + {"UserClass", 77, 1, false}, + {"DirectoryAgent", 78, 1, true}, + {"ServiceScope", 79, 1, true}, + {"RapidCommit", 80, 2, false}, + {"ClientFQDN", 81, 2, false}, + {"RelayAgentInformation", 82, 2, false}, + {"iSNS", 83, 1, true}, + {"NDSServers", 85, 3, true}, + {"NDSTreeName", 86, 1, true}, + {"NDSContext", 87, 1, true}, + {"LDAP", 95, 1, true}, + {"PCode", 100, 1, true}, + {"TCode", 101, 1, true}, + {"NetInfoAddress", 112, 3, true}, + {"NetInfoTag", 113, 1, true}, + {"URL", 114, 1, true}, + {"AutoConfig", 116, 7, true}, + {"NameServiceSearch", 117, 2, true}, + {"SubnetSelectionOption", 118, 3, true}, + {"DomainSearch", 119, 1, true}, + {"SIPServersDHCPOption", 120, 1, true}, + // { "121", 121, 1 , true}, + {"CCC", 122, 1, true}, + {"TFTPServerIPaddress", 128, 3, true}, + {"CallServerIPaddress", 129, 3, true}, + {"DiscriminationString", 130, 1, true}, + {"RemoteStatisticsServerIPAddress", 131, 3, true}, + {"HTTPProxyPhone", 135, 3, true}, + {"OPTION_CAPWAP_AC_V4", 138, 1, true}, + {"OPTIONIPv4_AddressMoS", 139, 1, true}, + {"OPTIONIPv4_FQDNMoS", 140, 1, true}, + {"SIPUAServiceDomains", 141, 1, true}, + {"OPTIONIPv4_AddressANDSF", 142, 1, true}, + {"IPTelephone", 176, 1, true}, + {"ConfigurationFile", 209, 1, true}, + {"PathPrefix", 210, 1, true}, + {"RebootTime", 211, 4, true}, + {"OPTION_6RD", 212, 1, true}, + {"OPTION_V4_ACCESS_DOMAIN", 213, 1, true}, + {"BootFileName", 253, 1, true}, + {"NextServer", 254, 3, true}, +}; + +int dual_server_main(int argc, char **argv) { + char logBuff[256] = ""; + + signal(SIGINT, catch_int); + signal(SIGABRT, catch_int); + signal(SIGTERM, catch_int); + signal(SIGQUIT, catch_int); + signal(SIGTSTP, catch_int); + signal(SIGHUP, catch_int); + signal(SIGPIPE, SIG_IGN); + //printf("%i\n", argc); + + for (int i = 1; i < argc; i++) { + if (!strcasecmp(argv[i], "-v")) + verbatim = true; + else if (!strcmp(argv[i], "-i") && argc > i + 1 && argv[i + 1][0] != '-') { + myTrim(iniFile, argv[i + 1]); + i++; + } else if (!strcmp(argv[i], "-s") && argc > i + 1 && argv[i + 1][0] != '-') { + myTrim(leaFile, argv[i + 1]); + i++; + } else if (!strcmp(argv[i], "-l") && argc > i + 1 && argv[i + 1][0] != '-') { + myTrim(logFile, argv[i + 1]); + i++; + } else if (!strcmp(argv[i], "-n") && argc > i + 1 && argv[i + 1][0] != '-') { + myTrim(icoFile, argv[i + 1]); + i++; + } else if (!strncasecmp(argv[i], "-i", 2)) + myTrim(iniFile, argv[i] + 2); + else if (!strncasecmp(argv[i], "-s", 2)) + myTrim(leaFile, argv[i] + 2); + else if (!strncasecmp(argv[i], "-l", 2)) + myTrim(logFile, argv[i] + 2); + else if (!strncasecmp(argv[i], "-n", 2)) + myTrim(icoFile, argv[i] + 2); + else + sprintf(logBuff, "Error: Invalid Argument %s", argv[i]); + } + + if (verbatim) { + if (logBuff[0]) { + printf("%s\n", logBuff); + sleep(1); + exit(EXIT_FAILURE); + } + + if (getuid()) { + printf("Error: Only root should run this program\n"); + sleep(1); + exit(EXIT_FAILURE); + } + + //printf("%i\n",sizeof(data7)); + memset(&cfig, 0, sizeof(cfig)); + cfig.ppid = getpid(); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, init, nullptr); + pthread_attr_destroy(&attr); + + if (errcode) { + printf("init thread Creation Failed"); + sleep(1); + exit(EXIT_FAILURE); + } + + while (true) { + if (!network.ready) { + network.readyForChange = true; + sleep(1); + continue; + } + + if ((dhcpService && !network.dhcpConn[0].ready) || (dnsService && !network.dnsUdpConn[0].ready)) { + sleep(1); + continue; + } + + //Sleep(200000); + + //network.busy = true; + FD_ZERO(&readfds); + tv.tv_sec = 20; + tv.tv_usec = 0; + + if (dhcpService) { + if (network.httpConn.ready) + FD_SET(network.httpConn.sock, &readfds); + + if (network.dhcpListener.ready) + FD_SET(network.dhcpListener.sock, &readfds); + + for (int i = 0; i < MAX_SERVERS && network.dhcpConn[i].ready; i++) + FD_SET(network.dhcpConn[i].sock, &readfds); + + if (cfig.dhcpReplConn.ready) + FD_SET(cfig.dhcpReplConn.sock, &readfds); + } + + if (dnsService) { + for (int i = 0; i < MAX_SERVERS && network.dnsUdpConn[i].ready; i++) + FD_SET(network.dnsUdpConn[i].sock, &readfds); + + for (int i = 0; i < MAX_SERVERS && network.dnsTcpConn[i].ready; i++) + FD_SET(network.dnsTcpConn[i].sock, &readfds); + + if (network.forwConn.ready) + FD_SET(network.forwConn.sock, &readfds); + } + + if (select(network.maxFD, &readfds, nullptr, nullptr, &tv)) { + t = time(nullptr); + + if (dhcpService) { + if (network.httpConn.ready && FD_ISSET(network.httpConn.sock, &readfds)) { + auto *req = (data19 *)calloc(1, sizeof(data19)); + + if (req) { + req->sockLen = sizeof(req->remote); + req->sock = accept(network.httpConn.sock, (sockaddr *)&req->remote, &req->sockLen); + ////errno = WSAGetLastError(); + + if (errno || req->sock == INVALID_SOCKET) { + sprintf(logBuff, "Accept Failed, Error %s", strerror(errno)); + logDHCPMess(logBuff, 1); + free(req); + } else + procHTTP(req); + } else { + sprintf(logBuff, "Memory Error"); + logDHCPMess(logBuff, 1); + } + } + + if (network.dhcpListener.ready && FD_ISSET(network.dhcpListener.sock, &readfds) + && gdmess(&dhcpr, 255) && sdmess(&dhcpr)) + alad(&dhcpr); + + if (cfig.dhcpReplConn.ready && FD_ISSET(cfig.dhcpReplConn.sock, &readfds)) { + errno = 0; + dhcpr.sockLen = sizeof(dhcpr.remote); + + dhcpr.bytes = (int)recvfrom(cfig.dhcpReplConn.sock, + dhcpr.raw, + sizeof(dhcpr.raw), + 0, + (sockaddr *)&dhcpr.remote, + &dhcpr.sockLen); + + ////errno = WSAGetLastError(); + + if (errno || dhcpr.bytes <= 0) + cfig.dhcpRepl = 0; + } + + for (int i = 0; i < MAX_SERVERS && network.dhcpConn[i].ready; i++) { + if (FD_ISSET(network.dhcpConn[i].sock, &readfds) && gdmess(&dhcpr, i) && sdmess(&dhcpr)) + alad(&dhcpr); + } + } + + if (dnsService) { + for (int i = 0; i < MAX_SERVERS && network.dnsUdpConn[i].ready; i++) { + if (FD_ISSET(network.dnsUdpConn[i].sock, &readfds)) { + if (gdnmess(&dnsr, i)) { + if (scanloc(&dnsr)) { + if (dnsr.dnsp->header.ancount) { + if (verbatim || cfig.dnsLogLevel >= 2) { + if (dnsr.dnsType == DNS_TYPE_SOA) + sprintf(logBuff, "SOA Sent for zone %s", dnsr.query); + else if (dnsr.dnsType == DNS_TYPE_NS) + sprintf(logBuff, "NS Sent for zone %s", dnsr.query); + else if (dnsr.cacheType == CTYPE_CACHED) + sprintf(logBuff, + "%s resolved from Cache to %s", + strquery(&dnsr), + getResult(&dnsr)); + else + sprintf(logBuff, + "%s resolved Locally to %s", + strquery(&dnsr), + getResult(&dnsr)); + + logDNSMess(&dnsr, logBuff, 2); + } + } else if (dnsr.dnsp->header.rcode == RCODE_NOERROR) { + dnsr.dnsp->header.rcode = RCODE_NAMEERROR; + + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, "%s not found", strquery(&dnsr)); + logDNSMess(&dnsr, logBuff, 2); + } + } + sdnmess(&dnsr); + } else if (!fdnmess(&dnsr)) { + if (!dnsr.dnsp->header.ancount + && (dnsr.dnsp->header.rcode == RCODE_NOERROR + || dnsr.dnsp->header.rcode == RCODE_NAMEERROR)) { + dnsr.dnsp->header.rcode = RCODE_NAMEERROR; + + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, "%s not found", strquery(&dnsr)); + logDNSMess(&dnsr, logBuff, 2); + } + } + sdnmess(&dnsr); + } + } else if (dnsr.dnsp) + sdnmess(&dnsr); + } + } + + for (int i = 0; i < MAX_SERVERS && network.dnsTcpConn[i].ready; i++) { + if (FD_ISSET(network.dnsTcpConn[i].sock, &readfds)) { + dnsr.sockInd = i; + dnsr.sockLen = sizeof(dnsr.remote); + errno = 0; + dnsr.sock = accept(network.dnsTcpConn[i].sock, (sockaddr *)&dnsr.remote, &dnsr.sockLen); + ////errno = WSAGetLastError(); + + if (dnsr.sock == INVALID_SOCKET || errno) { + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, "Accept Failed, Error=%s", strerror(errno)); + logDNSMess(logBuff, 1); + } + } else + procTCP(&dnsr); + } + } + + if (network.forwConn.ready && FD_ISSET(network.forwConn.sock, &readfds)) { + if (frdnmess(&dnsr)) { + sdnmess(&dnsr); + + if (verbatim || cfig.dnsLogLevel >= 2) { + if (dnsr.dnsIndex < MAX_SERVERS) { + if (dnsr.dnsp->header.ancount) { + if (getResult(&dnsr)) + sprintf(logBuff, + "%s resolved from Forwarding Server as %s", + strquery(&dnsr), + dnsr.tempname); + else + sprintf(logBuff, "%s resolved from Forwarding Server", strquery(&dnsr)); + } else + sprintf(logBuff, "%s not found by Forwarding Server", strquery(&dnsr)); + } else { + if (dnsr.dnsp->header.ancount) { + if (getResult(&dnsr)) + sprintf(logBuff, + "%s resolved from Conditional Forwarder as %s", + strquery(&dnsr), + dnsr.tempname); + else + sprintf(logBuff, "%s resolved from Conditional Forwarder", strquery(&dnsr)); + } else + sprintf(logBuff, "%s not found by Conditional Forwarder", strquery(&dnsr)); + } + + logDNSMess(&dnsr, logBuff, 2); + } + } + } + } + } else + t = time(nullptr); + + if (g_magin.done) { + currentInd = g_magin.currentInd; + g_magin.done = false; + //sprintf(logBuff, "New Index=%u", currentInd); + //logMess(logBuff, 2); + } else + checkSize(); + } + //printf("Here\n"); + } else { + if (logBuff[0]) { + syslog(LOG_MAKEPRI(LOG_LOCAL1, LOG_CRIT), "%s", logBuff); + sleep(1); + exit(EXIT_FAILURE); + } + + if (getuid()) { + syslog(LOG_MAKEPRI(LOG_LOCAL1, LOG_CRIT), "%s", "Only root should run this program"); + sleep(1); + exit(EXIT_FAILURE); + } + + /* Our process ID and Session ID */ + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log the failure */ + exit(EXIT_FAILURE); + } + + /* Change the current working directory */ + if ((chdir("/")) < 0) { + /* Log the failure */ + exit(EXIT_FAILURE); + } + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* Daemon-specific initialization goes here */ + //printf("%i\n",sizeof(data7)); + memset(&cfig, 0, sizeof(cfig)); + cfig.ppid = getpid(); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, init, nullptr); + pthread_attr_destroy(&attr); + + if (errcode) { + syslog(LOG_MAKEPRI(LOG_LOCAL1, LOG_CRIT), "%s", "init thread Creation Failed"); + sleep(1); + exit(EXIT_FAILURE); + } + + //listDSNCache(0); + /* The Big Loop */ + while (true) { + if (!network.ready) { + network.readyForChange = true; + sleep(1); + continue; + } + + if ((dhcpService && !network.dhcpConn[0].ready) || (dnsService && !network.dnsUdpConn[0].ready)) { + sleep(1); + continue; + } + //Sleep(200000); + + //network.busy = true; + FD_ZERO(&readfds); + tv.tv_sec = 20; + tv.tv_usec = 0; + + if (dhcpService) { + if (network.httpConn.ready) + FD_SET(network.httpConn.sock, &readfds); + + if (network.dhcpListener.ready) + FD_SET(network.dhcpListener.sock, &readfds); + + for (int i = 0; i < MAX_SERVERS && network.dhcpConn[i].ready; i++) + FD_SET(network.dhcpConn[i].sock, &readfds); + + if (cfig.dhcpReplConn.ready) + FD_SET(cfig.dhcpReplConn.sock, &readfds); + } + + if (dnsService) { + for (int i = 0; i < MAX_SERVERS && network.dnsUdpConn[i].ready; i++) + FD_SET(network.dnsUdpConn[i].sock, &readfds); + + for (int i = 0; i < MAX_SERVERS && network.dnsTcpConn[i].ready; i++) + FD_SET(network.dnsTcpConn[i].sock, &readfds); + + if (network.forwConn.ready) + FD_SET(network.forwConn.sock, &readfds); + } + + if (select(network.maxFD, &readfds, nullptr, nullptr, &tv)) { + t = time(nullptr); + + if (dhcpService) { + if (network.httpConn.ready && FD_ISSET(network.httpConn.sock, &readfds)) { + auto *req = (data19 *)calloc(1, sizeof(data19)); + + if (req) { + req->sockLen = sizeof(req->remote); + req->sock = accept(network.httpConn.sock, (sockaddr *)&req->remote, &req->sockLen); + ////errno = WSAGetLastError(); + + if (errno || req->sock == INVALID_SOCKET) { + sprintf(logBuff, "Accept Failed, Error %s", strerror(errno)); + logDHCPMess(logBuff, 1); + free(req); + } else + procHTTP(req); + } else { + sprintf(logBuff, "Memory Error"); + logDHCPMess(logBuff, 1); + } + } + + if (network.dhcpListener.ready && FD_ISSET(network.dhcpListener.sock, &readfds) + && gdmess(&dhcpr, 255) && sdmess(&dhcpr)) + alad(&dhcpr); + + if (cfig.dhcpReplConn.ready && FD_ISSET(cfig.dhcpReplConn.sock, &readfds)) { + errno = 0; + dhcpr.sockLen = sizeof(dhcpr.remote); + + dhcpr.bytes = (int)recvfrom(cfig.dhcpReplConn.sock, + dhcpr.raw, + sizeof(dhcpr.raw), + 0, + (sockaddr *)&dhcpr.remote, + &dhcpr.sockLen); + + ////errno = WSAGetLastError(); + + if (errno || dhcpr.bytes <= 0) + cfig.dhcpRepl = 0; + } + + for (int i = 0; i < MAX_SERVERS && network.dhcpConn[i].ready; i++) { + if (FD_ISSET(network.dhcpConn[i].sock, &readfds) && gdmess(&dhcpr, i) && sdmess(&dhcpr)) + alad(&dhcpr); + } + } + + if (dnsService) { + for (int i = 0; i < MAX_SERVERS && network.dnsUdpConn[i].ready; i++) { + if (FD_ISSET(network.dnsUdpConn[i].sock, &readfds)) { + if (gdnmess(&dnsr, i)) { + if (scanloc(&dnsr)) { + if (dnsr.dnsp->header.ancount) { + if (verbatim || cfig.dnsLogLevel >= 2) { + if (dnsr.dnsType == DNS_TYPE_SOA) + sprintf(logBuff, "SOA Sent for zone %s", dnsr.query); + else if (dnsr.dnsType == DNS_TYPE_NS) + sprintf(logBuff, "NS Sent for zone %s", dnsr.query); + else if (dnsr.cacheType == CTYPE_CACHED) + sprintf(logBuff, + "%s resolved from Cache to %s", + strquery(&dnsr), + getResult(&dnsr)); + else + sprintf(logBuff, + "%s resolved Locally to %s", + strquery(&dnsr), + getResult(&dnsr)); + + logDNSMess(&dnsr, logBuff, 2); + } + } else if (dnsr.dnsp->header.rcode == RCODE_NOERROR) { + dnsr.dnsp->header.rcode = RCODE_NAMEERROR; + + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, "%s not found", strquery(&dnsr)); + logDNSMess(&dnsr, logBuff, 2); + } + } + sdnmess(&dnsr); + } else if (!fdnmess(&dnsr)) { + if (!dnsr.dnsp->header.ancount + && (dnsr.dnsp->header.rcode == RCODE_NOERROR + || dnsr.dnsp->header.rcode == RCODE_NAMEERROR)) { + dnsr.dnsp->header.rcode = RCODE_NAMEERROR; + + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, "%s not found", strquery(&dnsr)); + logDNSMess(&dnsr, logBuff, 2); + } + } + sdnmess(&dnsr); + } + } else if (dnsr.dnsp) + sdnmess(&dnsr); + } + } + + for (int i = 0; i < MAX_SERVERS && network.dnsTcpConn[i].ready; i++) { + if (FD_ISSET(network.dnsTcpConn[i].sock, &readfds)) { + dnsr.sockInd = i; + dnsr.sockLen = sizeof(dnsr.remote); + errno = 0; + dnsr.sock = accept(network.dnsTcpConn[i].sock, (sockaddr *)&dnsr.remote, &dnsr.sockLen); + ////errno = WSAGetLastError(); + + if (dnsr.sock == INVALID_SOCKET || errno) { + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, "Accept Failed, Error=%s", strerror(errno)); + logDNSMess(logBuff, 1); + } + } else + procTCP(&dnsr); + } + } + + if (network.forwConn.ready && FD_ISSET(network.forwConn.sock, &readfds)) { + if (frdnmess(&dnsr)) { + sdnmess(&dnsr); + + if (verbatim || cfig.dnsLogLevel >= 2) { + if (dnsr.dnsIndex < MAX_SERVERS) { + if (dnsr.dnsp->header.ancount) { + if (getResult(&dnsr)) + sprintf(logBuff, + "%s resolved from Forwarding Server as %s", + strquery(&dnsr), + dnsr.tempname); + else + sprintf(logBuff, "%s resolved from Forwarding Server", strquery(&dnsr)); + } else + sprintf(logBuff, "%s not found by Forwarding Server", strquery(&dnsr)); + } else { + if (dnsr.dnsp->header.ancount) { + if (getResult(&dnsr)) + sprintf(logBuff, + "%s resolved from Conditional Forwarder as %s", + strquery(&dnsr), + dnsr.tempname); + else + sprintf(logBuff, "%s resolved from Conditional Forwarder", strquery(&dnsr)); + } else + sprintf(logBuff, "%s not found by Conditional Forwarder", strquery(&dnsr)); + } + + logDNSMess(&dnsr, logBuff, 2); + } + } + } + } + } else + t = time(nullptr); + + if (g_magin.done) { + currentInd = g_magin.currentInd; + g_magin.done = false; + //sprintf(logBuff, "New Index=%u", currentInd); + //logMess(logBuff, 2); + } else + checkSize(); + } + } + + closeConn(); + + if (cfig.dhcpReplConn.ready) + close(cfig.dhcpReplConn.sock); +} + +void closeConn() { + if (dhcpService) { + for (int i = 0; i < MAX_SERVERS && network.dhcpConn[i].loaded; i++) { + if (network.dhcpConn[i].ready) { + close(network.dhcpConn[i].sock); + network.dhcpConn[i].ready = false; + } + } + + if (network.dhcpListener.ready) { + close(network.dhcpListener.sock); + network.dhcpListener.ready = false; + } + + if (network.httpConn.ready) { + close(network.httpConn.sock); + network.httpConn.ready = false; + } + } + + if (dnsService) { + for (int i = 0; i < MAX_SERVERS && network.dnsUdpConn[i].loaded; i++) + if (network.dnsUdpConn[i].ready) { + close(network.dnsUdpConn[i].sock); + network.dnsUdpConn[i].ready = false; + } + + for (int i = 0; i < MAX_SERVERS && network.dnsTcpConn[i].loaded; i++) + if (network.dnsTcpConn[i].ready) { + close(network.dnsTcpConn[i].sock); + network.dnsTcpConn[i].ready = false; + } + + if (network.forwConn.ready) { + close(network.forwConn.sock); + network.forwConn.ready = false; + } + } +} + +void catch_int(int sig_num) { + char logBuff[256]; + + if (cfig.ppid == getpid()) { + kRunning = false; + network.ready = false; + + //while (kRunning && network.busy) + // sleep(1); + + sprintf(logBuff, "Closing Network Connections..."); + logMess(logBuff, 1); + + sleep(1); + closeConn(); + + if (cfig.dhcpReplConn.ready) + close(cfig.dhcpReplConn.sock); + + sprintf(logBuff, "Dual Server Stopped !\n"); + logMess(logBuff, 1); + + close(cfig.fixedSocket); + + sleep(1); + exit(EXIT_SUCCESS); + } +} + +bool chkQu(char *query) { + if (strlen(query) >= UCHAR_MAX) + return false; + + while (true) { + char *dp = strchr(query, '.'); + if (dp) { + MYWORD size = dp - query; + if (size >= 64) + return false; + query += (size + 1); + } else if (strlen(query) >= 64) + return false; + else + return true; + } +} + +MYWORD fQu(char *query, dnsPacket *mess, char *raw) { + auto *xname = (MYBYTE *)query; + auto *xraw = (MYBYTE *)raw; + MYWORD retvalue = 0; + bool goneout = false; + + while (true) { + MYWORD size = *xraw; + xraw++; + + if (!size) + break; + else if (size <= 63) { + if (!goneout) + retvalue += (size + 1); + + memcpy(xname, xraw, size); + xname += size; + xraw += size; + + if (!*xraw) + break; + + *xname = '.'; + xname++; + } else { + if (!goneout) + retvalue += 2; + + goneout = true; + size %= 128; + size %= 64; + size *= 256; + size += *xraw; + xraw = (MYBYTE *)mess + size; + } + } + + *xname = 0; + + if (!goneout) + retvalue++; + + return retvalue; +} + +MYWORD qLen(char *query) { + MYWORD fullsize = 1; + + while (true) { + char *dp = strchr(query, '.'); + + if (dp != nullptr) { + int size = (int)(dp - query); + query += (size + 1); + fullsize += (size + 1); + } else { + int size = (int)strlen(query); + + if (size) + fullsize += (size + 1); + + break; + } + } + //printf("%i\n",fullsize); + return fullsize; +} + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" +MYWORD pQu(char *raw, char *query) { + MYWORD fullsize = 1; + + while (true) { + char *i = strchr(query, '.'); + + if (i != nullptr) { + int size = i - query; + *raw = size; + raw++; + memcpy(raw, query, size); + raw += size; + query += (size + 1); + fullsize += (size + 1); + } else { + int size = (int)strlen(query); + if (size) { + *raw = size; + raw++; + strcpy(raw, query); + fullsize += (size + 1); + } + break; + } + } + //printf("%i\n",fullsize); + return fullsize; +} +#pragma clang diagnostic pop + +MYWORD fUShort(void *raw) { + return ntohs(*((MYWORD *)raw)); +} + +MYDWORD fUInt(void *raw) { + return ntohl(*((MYDWORD *)raw)); +} + +MYDWORD fIP(void *raw) { + return (*((MYDWORD *)raw)); +} + +MYBYTE pUShort(void *raw, MYWORD data) { + *((MYWORD *)raw) = htons(data); + return sizeof(MYWORD); +} + +MYBYTE pUInt(void *raw, MYDWORD data) { + *((MYDWORD *)raw) = htonl(data); + return sizeof(MYDWORD); +} + +MYBYTE pIP(void *raw, MYDWORD data) { + *((MYDWORD *)raw) = data; + return sizeof(MYDWORD); +} + +void addRREmpty(data5 *req) { + req->dnsp->header.ra = 0; + req->dnsp->header.at = 0; + req->dnsp->header.aa = 0; + req->dnsp->header.qr = 1; + req->dnsp->header.qdcount = 0; + req->dnsp->header.ancount = 0; + req->dnsp->header.nscount = 0; + req->dnsp->header.adcount = 0; + req->dp = &req->dnsp->data; +} + +void addRRError(data5 *req, MYBYTE rcode) { + req->dnsp->header.qr = 1; + req->dp = req->raw + req->bytes; + req->dnsp->header.rcode = rcode; +} + +void addRRNone(data5 *req) { + if (network.dns[0]) + req->dnsp->header.ra = 1; + else + req->dnsp->header.ra = 0; + + req->dnsp->header.at = 0; + req->dnsp->header.aa = 0; + + req->dnsp->header.qr = 1; + req->dnsp->header.ancount = 0; + req->dnsp->header.nscount = 0; + req->dnsp->header.adcount = 0; +} + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-multiway-paths-covered" +void addRRExt(data5 *req) { + char tempbuff[512]; + //char logBuff[512]; + //sprintf(logBuff, "%s=%s=%i\n", req->cname, req->query, req->bytes); + //logMess(logBuff, 2); + + if (strcasecmp(req->cname, req->query) != 0) { + MYBYTE temp[2048]; + memcpy(temp, req->raw, req->bytes); + auto *input = (dnsPacket *)temp; + req->dnsp = (dnsPacket *)req->raw; + + req->dnsp->header.aa = 0; + req->dnsp->header.at = 0; + req->dnsp->header.qdcount = htons(1); + req->dnsp->header.ancount = htons(1); + + //manuplate the response + req->dp = &req->dnsp->data; + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + + char *indp = &input->data; + + for (int i = 1; i <= ntohs(input->header.qdcount); i++) { + indp += fQu(tempbuff, input, indp); + indp += 4; + } + + for (int i = 1; i <= ntohs(input->header.ancount); i++) { + indp += fQu(tempbuff, input, indp); + MYWORD type = fUShort(indp); + req->dp += pQu(req->dp, tempbuff); + memcpy(req->dp, indp, 8); + req->dp += 8; + indp += 8; + //indp += 2; //type + //indp += 2; //class + //indp += 4; //ttl + MYWORD zLen = fUShort(indp); + indp += 2;//datalength + + switch (type) { + case DNS_TYPE_A: + req->dp += pUShort(req->dp, zLen); + req->dp += pIP(req->dp, fIP(indp)); + break; + case DNS_TYPE_CNAME: + fQu(tempbuff, input, indp); + MYWORD dl = pQu(req->dp + 2, tempbuff); + req->dp += pUShort(req->dp, dl); + req->dp += dl; + break; + } + + indp += zLen; + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + } + } else { + req->dnsp = (dnsPacket *)req->raw; + req->dp = req->raw + req->bytes; + } +} +#pragma clang diagnostic pop + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-multiway-paths-covered" +void addRRCache(data5 *req, data7 *cache) { + char tempbuff[512]; + + if (req->dnsType == DNS_TYPE_A) { + //manuplate the response + //printf("%s=%s\n", req->cname, req->query); + auto *input = (dnsPacket *)cache->response; + char *indp = &input->data; + req->dnsp = (dnsPacket *)req->raw; + req->dp = &req->dnsp->data; + + req->dnsp->header.aa = 0; + req->dnsp->header.at = 0; + req->dnsp->header.ancount = 0; + req->dnsp->header.qdcount = htons(1); + + req->dp = &req->dnsp->data; + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, req->dnsType); + req->dp += pUShort(req->dp, req->qclass); + + if (strcasecmp(req->cname, req->query) != 0) { + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + req->dnsp->header.ancount = htons(1); + } + + for (int i = 1; i <= ntohs(input->header.qdcount); i++) { + indp += fQu(tempbuff, input, indp); + indp += 4; + } + + for (int i = 1; i <= ntohs(input->header.ancount); i++) { + indp += fQu(tempbuff, input, indp); + MYWORD type = fUShort(indp); + + if (!strcasecmp(tempbuff, req->query)) + strcpy(tempbuff, req->query); + + req->dp += pQu(req->dp, tempbuff); + memcpy(req->dp, indp, 8); + req->dp += 8; + indp += 8; + //indp += 2; //type + //indp += 2; //class + //indp += 4; //ttl + MYWORD zLen = fUShort(indp); + indp += 2;//datalength + + switch (type) { + case DNS_TYPE_A: + req->dp += pUShort(req->dp, zLen); + req->dp += pIP(req->dp, fIP(indp)); + break; + case DNS_TYPE_CNAME: + fQu(tempbuff, input, indp); + MYWORD dl = pQu(req->dp + 2, tempbuff); + req->dp += pUShort(req->dp, dl); + req->dp += dl; + break; + } + + indp += zLen; + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + } + } else if (req->dnsType == DNS_TYPE_PTR || req->dnsType == DNS_TYPE_ANY || req->dnsType == DNS_TYPE_AAAA) { + req->dnsp = (dnsPacket *)req->raw; + MYWORD xid = req->dnsp->header.xid; + memcpy(req->raw, cache->response, cache->bytes); + req->dp = req->raw + cache->bytes; + req->dnsp->header.xid = xid; + } +} +#pragma clang diagnostic pop + +void addRRA(data5 *req) { + //if (req->qType == QTYPE_A_BARE && req->cacheType != CTYPE_NONE) + // sprintf(req->cname, "%s.%s", req->query, cfig.zone); + + if (strcasecmp(req->query, req->cname) != 0) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + } + + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + data7 *cache = req->iterBegin->second; + + if (strcasecmp(cache->name, req->mapname) != 0) + break; + + if (cache->ip) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + } + } + //req->bytes = req->dp - req->raw; +} + +void addRRPtr(data5 *req) { + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + if (data7 *cache = req->iterBegin->second) { + if (strcasecmp(cache->name, req->mapname) != 0) + break; + + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_PTR); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pUInt(req->dp, cfig.lease); + + if (!cache->hostname[0]) + strcpy(req->cname, cfig.zone); + else if (!strchr(cache->hostname, '.')) + sprintf(req->cname, "%s.%s", cache->hostname, cfig.zone); + else + strcpy(req->cname, cache->hostname); + + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + } + } + //req->bytes = req->dp - req->raw; +} + +void addRRServerA(data5 *req) { + //if (req->qType == QTYPE_A_BARE) + // sprintf(req->cname, "%s.%s", req->query, cfig.zone); + + if (strcasecmp(req->query, req->cname) != 0) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + } + + auto it = req->iterBegin; + + for (; it != dnsCache[currentInd].end(); it++) { + if (data7 *cache = it->second) { + if (strcasecmp(cache->name, req->mapname) != 0) + break; + + if (cache->ip && cache->ip == network.dnsUdpConn[req->sockInd].server) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + } + } + } + + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + if (data7 *cache = req->iterBegin->second) { + if (strcasecmp(cache->name, req->mapname) != 0) + break; + + if (cache->ip && cache->ip != network.dnsUdpConn[req->sockInd].server) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + } + } + } + //req->bytes = req->dp - req->raw; +} + +void addRRAny(data5 *req) { + if (req->qType == QTYPE_A_BARE || req->qType == QTYPE_A_LOCAL || req->qType == QTYPE_A_ZONE) + req->iterBegin = dnsCache[currentInd].find(setMapName(req->tempname, req->mapname, DNS_TYPE_A)); + else if (req->qType == QTYPE_P_LOCAL || req->qType == QTYPE_P_ZONE) + req->iterBegin = dnsCache[currentInd].find(setMapName(req->tempname, req->mapname, DNS_TYPE_PTR)); + else + return; + + addRRNone(req); + + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + if (data7 *cache = req->iterBegin->second) { + if (strcasecmp(cache->name, req->mapname) != 0) + break; + + if (cache->expiry < t) + continue; + + switch (cache->cacheType) { + case CTYPE_LOCAL_A: + case CTYPE_SERVER_A_AUTH: + case CTYPE_STATIC_A_AUTH: + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + break; + + case CTYPE_EXT_CNAME: + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(cache->hostname)); + req->dp += pQu(req->dp, cache->hostname); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + break; + + case CTYPE_LOCAL_CNAME: + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + sprintf(req->cname, "%s.%s", cache->hostname, cfig.zone); + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + break; + + case CTYPE_LOCAL_PTR_AUTH: + case CTYPE_LOCAL_PTR_NAUTH: + case CTYPE_STATIC_PTR_AUTH: + case CTYPE_STATIC_PTR_NAUTH: + case CTYPE_SERVER_PTR_AUTH: + case CTYPE_SERVER_PTR_NAUTH: + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_PTR); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + + if (!cache->hostname[0]) + strcpy(req->extbuff, cfig.zone); + else if (strchr(cache->hostname, '.')) + strcpy(req->extbuff, cache->hostname); + else + sprintf(req->extbuff, "%s.%s", cache->hostname, cfig.zone); + + req->dp += pUShort(req->dp, qLen(req->extbuff)); + req->dp += pQu(req->dp, req->extbuff); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + break; + } + } + } + + if (req->qType == QTYPE_A_ZONE) { + addRRMX(req); + addRRNS(req); + addRRSOA(req); + } else if (req->qType == QTYPE_P_ZONE) { + addRRNS(req); + addRRSOA(req); + } +} + +void addRRWildA(data5 *req, MYDWORD ip) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, ip); + //req->bytes = req->dp - req->raw; +} + +void addRRLocalhostA(data5 *req, data7 *cache) { + if (strcasecmp(req->query, req->mapname) != 0) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(req->mapname)); + req->dp += pQu(req->dp, req->mapname); + } + + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->mapname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + //req->bytes = req->dp - req->raw; +} + +void addRRLocalhostPtr(data5 *req, data7 *cache) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, req->query); + req->dp += pUShort(req->dp, DNS_TYPE_PTR); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, qLen(cache->hostname)); + req->dp += pQu(req->dp, cache->hostname); + //req->bytes = req->dp - req->raw; +} + +void addRRMX(data5 *req) { + if (cfig.mxCount[currentInd]) { + for (int m = 0; m < cfig.mxCount[currentInd]; m++) + addRRMXOne(req, m); + } + + //req->bytes = req->dp - req->raw; +} + +void addRRSOA(data5 *req) { + if (cfig.authorized && cfig.expireTime > t) { + req->dnsp->header.at = 1; + req->dnsp->header.aa = 1; + + if (req->qType == QTYPE_A_BARE || req->qType == QTYPE_A_LOCAL || req->qType == QTYPE_A_ZONE) + req->dp += pQu(req->dp, cfig.zone); + else if (req->qType == QTYPE_P_LOCAL || req->qType == QTYPE_P_ZONE) + req->dp += pQu(req->dp, cfig.authority); + else + return; + + if ((req->dnsType == DNS_TYPE_ANY || req->dnsType == DNS_TYPE_NS || req->dnsType == DNS_TYPE_SOA + || req->dnsType == DNS_TYPE_AXFR) + && (req->qType == QTYPE_A_ZONE || req->qType == QTYPE_P_ZONE)) + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + else + req->dnsp->header.nscount = htons(htons(req->dnsp->header.nscount) + 1); + + req->dp += pUShort(req->dp, DNS_TYPE_SOA); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + char *data = req->dp; + req->dp += 2; + req->dp += pQu(req->dp, cfig.nsP); + sprintf(req->extbuff, "hostmaster.%s", cfig.zone); + req->dp += pQu(req->dp, req->extbuff); + + if (req->qType == QTYPE_P_LOCAL || req->qType == QTYPE_P_EXT || req->qType == QTYPE_P_ZONE) + req->dp += pUInt(req->dp, cfig.serial2); + else + req->dp += pUInt(req->dp, cfig.serial1); + + req->dp += pUInt(req->dp, cfig.refresh); + req->dp += pUInt(req->dp, cfig.retry); + req->dp += pUInt(req->dp, cfig.expire); + req->dp += pUInt(req->dp, cfig.minimum); + pUShort(data, (req->dp - data) - 2); + } + //req->bytes = req->dp - req->raw; +} + +void addRRNS(data5 *req) { + //printf("%s=%u\n", cfig.ns, cfig.expireTime); + if (cfig.authorized && cfig.expireTime > t) { + req->dnsp->header.at = 1; + req->dnsp->header.aa = 1; + + //if (cfig.nsP[0]) + if (cfig.nsP[0] && (cfig.replication != 2 || cfig.dnsRepl > t)) { + if (req->qType == QTYPE_A_BARE || req->qType == QTYPE_A_LOCAL || req->qType == QTYPE_A_ZONE) + req->dp += pQu(req->dp, cfig.zone); + else if (req->qType == QTYPE_P_LOCAL || req->qType == QTYPE_P_ZONE) + req->dp += pQu(req->dp, cfig.authority); + else + return; + + if ((req->dnsType == DNS_TYPE_ANY || req->dnsType == DNS_TYPE_NS || req->dnsType == DNS_TYPE_SOA + || req->dnsType == DNS_TYPE_AXFR) + && (req->qType == QTYPE_A_ZONE || req->qType == QTYPE_P_ZONE)) + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + else + req->dnsp->header.nscount = htons(htons(req->dnsp->header.nscount) + 1); + + req->dp += pUShort(req->dp, DNS_TYPE_NS); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.expire); + req->dp += pUShort(req->dp, qLen(cfig.nsP)); + req->dp += pQu(req->dp, cfig.nsP); + } + + if (cfig.nsS[0] && (cfig.replication == 2 || cfig.dnsRepl > t)) + //if (cfig.nsS[0] && cfig.dnsRepl > t) + { + if (req->qType == QTYPE_A_BARE || req->qType == QTYPE_A_LOCAL || req->qType == QTYPE_A_ZONE) + req->dp += pQu(req->dp, cfig.zone); + else if (req->qType == QTYPE_P_LOCAL || req->qType == QTYPE_P_ZONE) + req->dp += pQu(req->dp, cfig.authority); + else + return; + + if ((req->dnsType == DNS_TYPE_ANY || req->dnsType == DNS_TYPE_NS || req->dnsType == DNS_TYPE_SOA + || req->dnsType == DNS_TYPE_AXFR) + && (req->qType == QTYPE_A_ZONE || req->qType == QTYPE_P_ZONE)) + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + else + req->dnsp->header.nscount = htons(htons(req->dnsp->header.nscount) + 1); + + req->dp += pUShort(req->dp, DNS_TYPE_NS); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.expire); + req->dp += pUShort(req->dp, qLen(cfig.nsS)); + req->dp += pQu(req->dp, cfig.nsS); + } + } + //req->bytes = req->dp - req->raw; +} + +void addRRAd(data5 *req) { + //printf("%s=%u\n", cfig.ns, cfig.expireTime); + if (cfig.authorized && cfig.expireTime > t) { + //if (cfig.nsP[0]) + if (cfig.nsP[0] && (cfig.replication != 2 || cfig.dnsRepl > t)) { + req->dnsp->header.adcount = htons(htons(req->dnsp->header.adcount) + 1); + req->dp += pQu(req->dp, cfig.nsP); + + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + + if (cfig.replication) + req->dp += pIP(req->dp, cfig.zoneServers[0]); + else + req->dp += pIP(req->dp, network.listenServers[req->sockInd]); + } + + if (cfig.nsS[0] && (cfig.replication == 2 || cfig.dnsRepl > t)) + //if (cfig.nsS[0] && cfig.dnsRepl > t) + { + req->dnsp->header.adcount = htons(htons(req->dnsp->header.adcount) + 1); + req->dp += pQu(req->dp, cfig.nsS); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cfig.zoneServers[1]); + } + } + //req->bytes = req->dp - req->raw; +} + +void addRRAOne(data5 *req) { + if (data7 *cache = req->iterBegin->second) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + + if (!cache->name[0]) + strcpy(req->cname, cfig.zone); + else if (!strchr(cache->name, '.')) + sprintf(req->cname, "%s.%s", cache->name, cfig.zone); + else + strcpy(req->cname, cache->name); + + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + //req->bytes = req->dp - req->raw; + } +} + +void addRRPtrOne(data5 *req) { + if (data7 *cache = req->iterBegin->second) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + sprintf(req->cname, "%s%s", cache->name, arpa); + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_PTR); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + + if (!cache->hostname[0]) + strcpy(req->cname, cfig.zone); + else if (!strchr(cache->hostname, '.')) + sprintf(req->cname, "%s.%s", cache->hostname, cfig.zone); + else + strcpy(req->cname, cache->hostname); + + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + } + + //req->bytes = req->dp - req->raw; +} + +void addRRSTAOne(data5 *req) { + if (data7 *cache = req->iterBegin->second) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + + if (!cache->name[0]) + strcpy(req->cname, cfig.zone); + else if (!strchr(cache->name, '.')) + sprintf(req->cname, "%s.%s", cache->name, cfig.zone); + else + strcpy(req->cname, cache->name); + + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, 4); + req->dp += pIP(req->dp, cache->ip); + } + //req->bytes = req->dp - req->raw; +} + +void addRRCNOne(data5 *req) { + if (data7 *cache = req->iterBegin->second) { + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + + if (!cache->name[0]) + strcpy(req->cname, cfig.zone); + else if (strchr(cache->name, '.')) + strcpy(req->cname, cache->name); + else + sprintf(req->cname, "%s.%s", cache->name, cfig.zone); + + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_CNAME); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + + if (!cache->hostname[0]) + strcpy(req->cname, cfig.zone); + else if (strchr(cache->hostname, '.')) + strcpy(req->cname, cache->hostname); + else + sprintf(req->cname, "%s.%s", cache->hostname, cfig.zone); + + req->dp += pUShort(req->dp, qLen(req->cname)); + req->dp += pQu(req->dp, req->cname); + } + //req->bytes = req->dp - req->raw; +} + +void addRRMXOne(data5 *req, MYBYTE m) { + //req->dp += pQu(req->dp, req->query); + req->dnsp->header.ancount = htons(htons(req->dnsp->header.ancount) + 1); + req->dp += pQu(req->dp, cfig.zone); + req->dp += pUShort(req->dp, DNS_TYPE_MX); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->dp += pUInt(req->dp, cfig.lease); + req->dp += pUShort(req->dp, strlen(cfig.mxServers[currentInd][m].hostname) + 4); + req->dp += pUShort(req->dp, cfig.mxServers[currentInd][m].pref); + req->dp += pQu(req->dp, cfig.mxServers[currentInd][m].hostname); + //req->bytes = req->dp - req->raw; +} + +void procHTTP(data19 *req) { + char logBuff[256]; + char tempbuff[512]; + req->ling.l_onoff = 1; //0 = off (l_linger ignored), nonzero = on + req->ling.l_linger = 30;//0 = discard data, nonzero = wait for data sent + setsockopt(req->sock, SOL_SOCKET, SO_LINGER, (const char *)&req->ling, sizeof(req->ling)); + + timeval tv1 {}; + fd_set readfds1; + FD_ZERO(&readfds1); + tv1.tv_sec = 1; + tv1.tv_usec = 0; + FD_SET(req->sock, &readfds1); + + if (!select((req->sock + 1), &readfds1, nullptr, nullptr, &tv1)) { + sprintf(logBuff, "HTTP Client %s, Message Receive failed", IP2String(tempbuff, req->remote.sin_addr.s_addr)); + logDHCPMess(logBuff, 1); + closesocket(req->sock); + free(req); + return; + } + + char buffer[2048]; + req->bytes = (int)recv(req->sock, buffer, sizeof(buffer), 0); + //errno = WSAGetLastError(); + + if ((verbatim || cfig.dhcpLogLevel >= 1) && (errno || req->bytes <= 0)) { + sprintf(logBuff, + "HTTP Client %s, Message Receive failed, WSAError %d", + IP2String(tempbuff, req->remote.sin_addr.s_addr), + errno); + logDHCPMess(logBuff, 1); + closesocket(req->sock); + free(req); + return; + } + + if (cfig.httpClients[0] && !findServer(cfig.httpClients, 8, req->remote.sin_addr.s_addr)) { + if (verbatim || cfig.dhcpLogLevel >= 2) { + sprintf(logBuff, "HTTP Client %s, Access Denied", IP2String(tempbuff, req->remote.sin_addr.s_addr)); + logDHCPMess(logBuff, 2); + } + + req->dp = (char *)calloc(1, sizeof(send403)); + req->bytes = sprintf(req->dp, send403); + return; + } + + if (verbatim || cfig.dhcpLogLevel >= 2) { + sprintf(logBuff, "HTTP Client %s, Request Processed", IP2String(tempbuff, req->remote.sin_addr.s_addr)); + logDHCPMess(logBuff, 2); + //printf("%s\n", buffer); + } + + buffer[sizeof(buffer) - 1] = 0; + char *fp = nullptr; + char *end = strchr(buffer, '\n'); + + if (end && end > buffer && (*(end - 1) == '\r')) { + *(end - 1) = 0; + + if (myTokenize(buffer, buffer, " ", true) > 1) + fp = myGetToken(buffer, 1); + } + + if (fp && !strcasecmp(fp, "/")) + sendStatus(req); + else if (fp && icoSize > 0 && !strcasecmp(fp, "/favicon.ico")) { + strcpy(req->contentType, "img"); + req->bytes = icoSize; + req->dp = (char *)calloc(1, icoSize); + memcpy(req->dp, icoString, icoSize); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, sendHTTP, (void *)req); + pthread_attr_destroy(&attr); + return; + } + // else if (fp && !strcasecmp(fp, "/scopestatus")) + // sendScopeStatus(req); + else { + if (fp && (verbatim || cfig.dhcpLogLevel >= 2)) { + sprintf(logBuff, "HTTP Client %s, %s not found", IP2String(tempbuff, req->remote.sin_addr.s_addr), fp); + logDHCPMess(logBuff, 2); + } else if (verbatim || cfig.dhcpLogLevel >= 2) { + sprintf(logBuff, "HTTP Client %s, Invalid request", IP2String(tempbuff, req->remote.sin_addr.s_addr)); + logDHCPMess(logBuff, 2); + } + + req->dp = (char *)calloc(1, sizeof(send404)); + req->bytes = sprintf(req->dp, send404); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, sendHTTP, (void *)req); + pthread_attr_destroy(&attr); + return; + } +} + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "bugprone-branch-clone" +void sendStatus(data19 *req) { + char ipbuff[16]; + char extbuff[16]; + char logBuff[512]; + char tempbuff[512]; + + dhcpMap::iterator p; + MYDWORD iip = 0; + data7 *dhcpEntry = nullptr; + //data7 *cache = nullptr; + //sprintf(tempbuff, "%d=%d", dhcpCache.size(), cfig.dhcpSize); + req->memSize = (int)(2048 + (135 * dhcpCache.size()) + (cfig.dhcpSize * 26)); + req->dp = (char *)calloc(1, req->memSize); + + if (!req->dp) { + sprintf(logBuff, "Memory Error"); + logDHCPMess(logBuff, 1); + closesocket(req->sock); + free(req); + return; + } + + char *fp = req->dp; + char *maxData = req->dp + (req->memSize - 512); + //tm *ttm = gmtime(&t); + //strftime(tempbuff, sizeof(tempbuff), "%a, %d %b %Y %H:%M:%S GMT", ttm); + //fp += sprintf(fp, send200, tempbuff, tempbuff); + //fp += sprintf(fp, send200); + //char *contentStart = fp; + fp += sprintf(fp, htmlStart, htmlTitle); + + //const char bodyStart[] = "
\n
%s
Server Name: %s%shttp://dhcp-dns-server.sourceforge.net
"; + + if (cfig.replication == 1) + fp += sprintf(fp, bodyStart, sVersion, cfig.servername, "(Primary)", MY_EXE_SIZE); + else if (cfig.replication == 2) + fp += sprintf(fp, bodyStart, sVersion, cfig.servername, "(Secondary)", MY_EXE_SIZE); + else + fp += sprintf(fp, bodyStart, sVersion, cfig.servername, "", MY_EXE_SIZE); + + //fp += sprintf(fp, bodyStart, sVersion, cfig.servername); + fp += sprintf(fp, "\n\n"); + + if (cfig.dhcpRepl > t) { + fp += sprintf(fp, "\n"); + fp += sprintf(fp, + "\n"); + } else { + fp += sprintf(fp, "\n"); + fp += sprintf( + fp, "\n"); + } + + for (p = dhcpCache.begin(); kRunning && p != dhcpCache.end() && fp < maxData; p++) { + //if ((dhcpEntry = p->second) && dhcpEntry->display) + if ((dhcpEntry = p->second) && dhcpEntry->display && dhcpEntry->expiry >= t) { + fp += sprintf(fp, ""); + fp += sprintf(fp, td200, dhcpEntry->mapname); + fp += sprintf(fp, td200, IP2String(tempbuff, dhcpEntry->ip)); + + if (dhcpEntry->expiry >= MY_MAX_TIME) + fp += sprintf(fp, td200, "Infinity"); + else { + tm *ttm = localtime(&dhcpEntry->expiry); + strftime(tempbuff, sizeof(tempbuff), "%d-%b-%y %X", ttm); + fp += sprintf(fp, tdnowrap200, tempbuff); + } + + if (dhcpEntry->hostname[0]) { + strcpy(tempbuff, dhcpEntry->hostname); + tempbuff[20] = 0; + fp += sprintf(fp, td200, tempbuff); + } else + fp += sprintf(fp, td200, " "); + + if (cfig.dhcpRepl > t) { + if (dhcpEntry->local && cfig.replication == 1) + fp += sprintf(fp, td200, "Primary"); + else if (dhcpEntry->local && cfig.replication == 2) + fp += sprintf(fp, td200, "Secondary"); + else if (cfig.replication == 1) + fp += sprintf(fp, td200, "Secondary"); + else + fp += sprintf(fp, td200, "Primary"); + } + + fp += sprintf(fp, "\n"); + } + } + + fp += sprintf(fp, "
Active Leases
Mac AddressIPLease ExpiryHostname (first 20 " + "chars)Server
Active Leases
Mac AddressIPLease ExpiryHostname (first 20 chars)
\n
\n\n"); + fp += sprintf(fp, "\n"); + fp += sprintf(fp, + "\n"); + + for (char rangeInd = 0; kRunning && rangeInd < cfig.rangeCount && fp < maxData; rangeInd++) { + MYWORD ipused = 0; + MYWORD ipfree = 0; + MYWORD ind = 0; + + for (MYDWORD k = cfig.dhcpRanges[rangeInd].rangeStart; k <= cfig.dhcpRanges[rangeInd].rangeEnd; k++, ind++) { + if (cfig.dhcpRanges[rangeInd].expiry[ind] != MY_MAX_TIME) { + if (cfig.dhcpRanges[rangeInd].expiry[ind] < t) + ipfree++; + else + ipused++; + } + } + + IP2String(tempbuff, ntohl(cfig.dhcpRanges[rangeInd].rangeStart)); + IP2String(ipbuff, ntohl(cfig.dhcpRanges[rangeInd].rangeEnd)); + IP2String(extbuff, cfig.dhcpRanges[rangeInd].mask); + fp += sprintf(fp, + "\n", + tempbuff, + ipbuff, + extbuff, + (ipused + ipfree), + ipfree); + } + + fp += sprintf(fp, "
Free Dynamic Leases
DHCP RangeMaskAvailable " + "LeasesFree Leases
%s - %s%s%i%i
\n
\n\n"); + fp += sprintf(fp, "\n"); + fp += sprintf(fp, "\n"); + + MYBYTE colNum = 0; + + for (p = dhcpCache.begin(); kRunning && p != dhcpCache.end() && fp < maxData; p++) { + if ((dhcpEntry = p->second) && dhcpEntry->fixed && dhcpEntry->expiry < t) { + if (!colNum) { + fp += sprintf(fp, ""); + colNum = 1; + } else if (colNum == 1) { + colNum = 2; + } else if (colNum == 2) { + fp += sprintf(fp, "\n"); + colNum = 1; + } + + fp += sprintf(fp, td200, dhcpEntry->mapname); + fp += sprintf(fp, td200, IP2String(tempbuff, dhcpEntry->ip)); + } + } + + if (colNum) + fp += sprintf(fp, "\n"); + + fp += sprintf(fp, "
Free Static Leases
Mac AddressIPMac AddressIP
\n\n"); + //MYBYTE x = sprintf(tempbuff, "%u", (fp - contentStart)); + //memcpy((contentStart - 12), tempbuff, x); + strcpy(req->contentType, "text/html"); + req->bytes = (int)(fp - req->dp); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, sendHTTP, (void *)req); + pthread_attr_destroy(&attr); +} +#pragma clang diagnostic pop + +/* +void sendScopeStatus(data19 *req) +{ + + MYBYTE rangeCount = 0; + req->memSize = 1536 + (150 * cfig.rangeCount); + req->dp = (char*)calloc(1, req->memSize); + + if (!req->dp) + { + sprintf(logBuff, "Memory Error"); + logDHCPMess(logBuff, 1); + closesocket(req->sock); + free(req); + return; + } + + char *fp = req->dp; + char *maxData = req->dp + (req->memSize - 512); + tm *ttm = gmtime(&t); + strftime(tempbuff, sizeof(tempbuff), "%a, %d %b %Y %H:%M:%S GMT", ttm); + fp += sprintf(fp, send200, tempbuff, tempbuff); + char *contentStart = fp; + fp += sprintf(fp, htmlStart, htmlTitle); + fp += sprintf(fp, bodyStart, sVersion); + fp += sprintf(fp, "\n"); + fp += sprintf(fp, "\n"); + fp += sprintf(fp, "\n"); + MYBYTE colNum = 0; + + for (char rangeInd = 0; kRunning && rangeInd < cfig.rangeCount && fp < maxData; rangeInd++) + { + float ipused = 0; + float ipfree = 0; + int ind = 0; + + for (MYDWORD iip = cfig.dhcpRanges[rangeInd].rangeStart; iip <= cfig.dhcpRanges[rangeInd].rangeEnd; iip++, ind++) + { + if (cfig.dhcpRanges[rangeInd].expiry[ind] > t) + ipused++; + else + ipfree++; + } + + IP2String(tempbuff, ntohl(cfig.dhcpRanges[rangeInd].rangeStart)); + IP2String(extbuff, ntohl(cfig.dhcpRanges[rangeInd].rangeEnd)); + fp += sprintf(fp, "\n", tempbuff, extbuff, ipused, ipfree, ((ipfree * 100)/(ipused + ipfree))); + } + + fp += sprintf(fp, "
Scope Status
DHCP RangeIPs UsedIPs Free%% Free
%s - %s%5.0f%5.0f%2.2f
\n\n"); + memcpy((contentStart - 12), tempbuff, sprintf(tempbuff, "%u", (fp - contentStart))); + req->bytes = fp - req->dp; + + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, sendHTTP, (void*)req); + pthread_attr_destroy(&attr); + return; +} +*/ + +void *sendHTTP(void *lpParam) { + auto *req = (data19 *)lpParam; + + //char logBuff[512]; + //sprintf(logBuff, "sendHTTP memsize=%d bytes=%d", req->memSize, req->bytes); + + char *dp = req->dp; + timeval tv1{}; + fd_set writefds1; + int sent = 0; + bool sendheader = true; + + while (kRunning && req->bytes > 0) { + tv1.tv_sec = 5; + tv1.tv_usec = 0; + FD_ZERO(&writefds1); + FD_SET(req->sock, &writefds1); + + if (select((req->sock + 1), nullptr, &writefds1, nullptr, &tv1)) { + if (sendheader) { + char header[256]; + sprintf(header, send200, req->contentType, req->bytes); + send(req->sock, header, strlen(header), 0); + sendheader = false; + } else if (req->bytes > 1024) + sent = (int)send(req->sock, dp, 1024, 0); + else if (req->bytes > 0) + sent = (int)send(req->sock, dp, req->bytes, 0); + else + break; + + //errno = WSAGetLastError(); + + if (errno || sent < 0) + break; + + dp += sent; + req->bytes -= sent; + } else + break; + } + //Sleep(10*1000); + //shutdown(req->sock, 2); + closesocket(req->sock); + free(req->dp); + free(req); + pthread_exit(nullptr); +} + +void procTCP(data5 *req) { + //debug("procTCP"); + + char logBuff[512]; + req->ling.l_onoff = 1; //0 = off (l_linger ignored), nonzero = on + req->ling.l_linger = 10;//0 = discard data, nonzero = wait for data sent + setsockopt(req->sock, SOL_SOCKET, SO_LINGER, (const char *)&req->ling, sizeof(req->ling)); + + errno = 0; + req->bytes = recvTcpDnsMess(req->raw, req->sock, sizeof(req->raw)); + //printf("%u\n",req->bytes); + + if (req->bytes < 2) { + sprintf(logBuff, "Error Getting TCP DNS Message"); + logDNSMess(logBuff, 1); + closesocket(req->sock); + return; + } + + MYWORD pktSize = fUShort(req->raw); + req->dp = req->raw + 2; + req->dnsp = (dnsPacket *)(req->dp); + + if (req->dnsp->header.qr) + return; + + req->dp = &req->dnsp->data; + MYDWORD clientIP = req->remote.sin_addr.s_addr; + + if (!findServer(network.allServers, MAX_SERVERS, clientIP) + && !findServer(cfig.zoneServers, MAX_TCP_CLIENTS, clientIP) + && !findServer(&cfig.zoneServers[2], MAX_TCP_CLIENTS - 2, clientIP)) { + sprintf(logBuff, "DNS TCP Query, Access Denied"); + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_REFUSED); + sendTCPmess(req); + closesocket(req->sock); + return; + } + + if (ntohs(req->dnsp->header.qdcount) != 1 || ntohs(req->dnsp->header.ancount)) { + sprintf(logBuff, "DNS Query Format Error"); + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_FORMATERROR); + sendTCPmess(req); + closesocket(req->sock); + return; + } + + if (req->dnsp->header.opcode != OPCODE_STANDARD_QUERY) { + switch (req->dnsp->header.opcode) { + case OPCODE_INVERSE_QUERY: + sprintf(logBuff, "Inverse query not supported"); + break; + + case OPCODE_SRVR_STAT_REQ: + sprintf(logBuff, "Server Status Request not supported"); + break; + + case OPCODE_NOTIFY: + sprintf(logBuff, "Notify not supported"); + break; + + case OPCODE_DYNAMIC_UPDATE: + sprintf(logBuff, "Dynamic Update not needed/supported by Dual Server"); + break; + + default: + sprintf(logBuff, "OpCode %u not supported", req->dnsp->header.opcode); + } + + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_NOTIMPL); + sendTCPmess(req); + closesocket(req->sock); + return; + } + + for (int i = 1; i <= ntohs(req->dnsp->header.qdcount); i++) { + req->dp += fQu(req->query, req->dnsp, req->dp); + req->dnsType = fUShort(req->dp); + req->dp += 2; + req->qclass = fUShort(req->dp); + req->dp += 2; + } + + if (req->qclass != DNS_CLASS_IN) { + sprintf(logBuff, "DNS Class %u not supported", req->qclass); + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_NOTIMPL); + sendTCPmess(req); + closesocket(req->sock); + return; + } + + if (!req->dnsType) { + sprintf(logBuff, "missing query type"); + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_FORMATERROR); + sendTCPmess(req); + closesocket(req->sock); + return; + } + + strcpy(req->cname, req->query); + strcpy(req->mapname, req->query); + myLower(req->mapname); + req->qLen = strlen(req->cname); + req->qType = makeLocal(req->mapname); + + if (req->qType == QTYPE_A_EXT && req->qLen > cfig.zLen) { + char *dp = req->cname + (req->qLen - cfig.zLen); + + if (!strcasecmp(dp, cfig.zone)) + req->qType = QTYPE_CHILDZONE; + } + + if (req->dnsType != DNS_TYPE_NS && req->dnsType != DNS_TYPE_SOA && req->dnsType != DNS_TYPE_AXFR + && req->dnsType != DNS_TYPE_IXFR) { + addRRError(req, RCODE_NOTIMPL); + sendTCPmess(req); + sprintf(logBuff, "%s, Query Type not supported", strquery(req)); + logTCPMess(req, logBuff, 1); + closesocket(req->sock); + return; + } else if (!cfig.authorized + || (req->qType != QTYPE_A_ZONE && req->qType != QTYPE_A_LOCAL && req->qType != QTYPE_P_ZONE + && req->qType != QTYPE_P_LOCAL)) { + addRRError(req, RCODE_NOTAUTH); + sendTCPmess(req); + sprintf(logBuff, "Server is not authority for zone %s", req->query); + logTCPMess(req, logBuff, 1); + } else if (cfig.expireTime < t) { + addRRError(req, RCODE_NOTZONE); + sendTCPmess(req); + sprintf(logBuff, "Zone %s expired", req->query); + logTCPMess(req, logBuff, 1); + } else { + switch (req->dnsType) { + case DNS_TYPE_SOA: + addRRNone(req); + addRRSOA(req); + sendTCPmess(req); + + if (req->dnsp->header.ancount) + sprintf(logBuff, "SOA Sent for zone %s", req->query); + else + sprintf(logBuff, "%s not found", strquery(req)); + + logTCPMess(req, logBuff, 2); + break; + + case DNS_TYPE_NS: + addRRNone(req); + addRRNS(req); + addRRAd(req); + sendTCPmess(req); + + if (req->dnsp->header.ancount) + sprintf(logBuff, "NS Sent for zone %s", req->query); + else + sprintf(logBuff, "%s not found", strquery(req)); + + logTCPMess(req, logBuff, 2); + break; + + case DNS_TYPE_AXFR: + case DNS_TYPE_IXFR: + + if (req->qType == QTYPE_A_ZONE) { + MYWORD records = 0; + + addRREmpty(req); + addRRSOA(req); + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + + addRREmpty(req); + addRRNS(req); + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + + req->iterBegin = dnsCache[currentInd].begin(); + + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + //char tempbuff[256]; + //sprintf(tempbuff, "%s=%d=%u",req->iterBegin->second->mapname, req->iterBegin->second->cacheType, req->iterBegin->second->expiry); + //debug(tempbuff); + + if (req->iterBegin->second->expiry > t) { + switch (req->iterBegin->second->cacheType) { + case CTYPE_LOCAL_A: + addRREmpty(req); + addRRAOne(req); + break; + + case CTYPE_SERVER_A_AUTH: + case CTYPE_STATIC_A_AUTH: + addRREmpty(req); + addRRSTAOne(req); + break; + + case CTYPE_LOCAL_CNAME: + case CTYPE_EXT_CNAME: + addRREmpty(req); + addRRCNOne(req); + break; + + default: + continue; + } + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + } + } + + for (int m = 0; m < cfig.mxCount[currentInd]; m++) { + addRREmpty(req); + addRRMXOne(req, m); + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + } + + addRREmpty(req); + addRRSOA(req); + + if (sendTCPmess(req)) { + records++; + sprintf(logBuff, "Zone %s with %d RRs Sent", req->query, records); + logTCPMess(req, logBuff, 2); + } + } else if (req->qType == QTYPE_P_ZONE) { + MYWORD records = 0; + + addRREmpty(req); + addRRSOA(req); + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + + addRREmpty(req); + addRRNS(req); + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + + req->iterBegin = dnsCache[currentInd].begin(); + + for (; req->iterBegin != dnsCache[currentInd].end(); req->iterBegin++) { + addRREmpty(req); + + if (req->iterBegin->second->expiry > t) { + switch (req->iterBegin->second->cacheType) { + case CTYPE_LOCAL_PTR_AUTH: + case CTYPE_STATIC_PTR_AUTH: + case CTYPE_SERVER_PTR_AUTH: + addRRPtrOne(req); + break; + + default: + continue; + } + + if (!sendTCPmess(req)) { + closesocket(req->sock); + return; + } else + records++; + } + } + + addRREmpty(req); + addRRSOA(req); + + if (sendTCPmess(req)) { + records++; + sprintf(logBuff, "Zone %s with %d RRs Sent", req->query, records); + logTCPMess(req, logBuff, 2); + } + } else { + addRRNone(req); + req->dnsp->header.rcode = RCODE_NOTAUTH; + sendTCPmess(req); + sprintf(logBuff, "Server is not authority for zone %s", req->query); + logTCPMess(req, logBuff, 1); + } + break; + + default: + sprintf(logBuff, "%s Query type not supported", strquery(req)); + logTCPMess(req, logBuff, 1); + addRRError(req, RCODE_NOTIMPL); + sendTCPmess(req); + } + } + + closesocket(req->sock); +} + +bool sendTCPmess(data5 *req) { + char logBuff[256]; + + if (req->dp == &req->dnsp->data) + return true; + + timeval tv1 {}; + fd_set writefds; + + FD_ZERO(&writefds); + FD_SET(req->sock, &writefds); + tv1.tv_sec = 5; + tv1.tv_usec = 0; + + if (select((req->sock + 1), nullptr, &writefds, nullptr, &tv1) > 0) { + errno = 0; + req->dnsp->header.ra = 0; + req->bytes = (int)(req->dp - req->raw); + pUShort(req->raw, req->bytes - 2); + + if (req->bytes == send(req->sock, req->raw, req->bytes, 0) && !errno) + return true; + } + + if (verbatim || cfig.dnsLogLevel >= 1) { + sprintf(logBuff, "Failed to send %s", strquery(req)); + logTCPMess(req, logBuff, 1); + } + + return false; +} + +MYWORD gdnmess(data5 *req, MYBYTE sockInd) { + char logBuff[256]; + memset(req, 0, sizeof(data5)); + req->sockLen = sizeof(req->remote); + errno = 0; + + req->bytes = (int)recvfrom( + network.dnsUdpConn[sockInd].sock, req->raw, sizeof(req->raw), 0, (sockaddr *)&req->remote, &req->sockLen); + + //errno = WSAGetLastError(); + + if (errno || req->bytes <= 0) + return 0; + + req->sockInd = sockInd; + req->dnsp = (dnsPacket *)req->raw; + + if (req->dnsp->header.qr) + return 0; + + if (req->dnsp->header.opcode != OPCODE_STANDARD_QUERY) { + if (verbatim || cfig.dnsLogLevel >= 1) { + switch (req->dnsp->header.opcode) { + case OPCODE_INVERSE_QUERY: + sprintf(logBuff, "Inverse query not supported"); + break; + + case OPCODE_SRVR_STAT_REQ: + sprintf(logBuff, "Server Status Request not supported"); + break; + + case OPCODE_NOTIFY: + sprintf(logBuff, "Notify not supported"); + break; + + case OPCODE_DYNAMIC_UPDATE: + sprintf(logBuff, "Dynamic Update not needed/supported by Dual Server"); + break; + + default: + sprintf(logBuff, "OpCode %d not supported", req->dnsp->header.opcode); + } + + logDNSMess(req, logBuff, 1); + } + + addRRError(req, RCODE_NOTIMPL); + return 0; + } + + if (ntohs(req->dnsp->header.qdcount) != 1 || ntohs(req->dnsp->header.ancount)) { + if (verbatim || cfig.dnsLogLevel >= 1) { + sprintf(logBuff, "DNS Query Format Error"); + logDNSMess(req, logBuff, 1); + } + + addRRError(req, RCODE_FORMATERROR); + return 0; + } + + req->dp = &req->dnsp->data; + + for (int i = 1; i <= ntohs(req->dnsp->header.qdcount); i++) { + req->dp += fQu(req->query, req->dnsp, req->dp); + req->dnsType = fUShort(req->dp); + req->dp += 2; + req->qclass = fUShort(req->dp); + req->dp += 2; + } + + if (req->qclass != DNS_CLASS_IN) { + if (verbatim || cfig.dnsLogLevel >= 1) { + sprintf(logBuff, "DNS Class %d not supported", req->qclass); + logDNSMess(req, logBuff, 1); + } + addRRError(req, RCODE_NOTIMPL); + return 0; + } + + if (!req->dnsType) { + if (verbatim || cfig.dnsLogLevel >= 1) { + sprintf(logBuff, "missing query type"); + logDNSMess(req, logBuff, 1); + } + + addRRError(req, RCODE_FORMATERROR); + return 0; + } + + MYDWORD ip = req->remote.sin_addr.s_addr; + MYDWORD iip = ntohl(ip); + + for (int i = 0; i < MAX_DNS_RANGES && cfig.dnsRanges[i].rangeStart; i++) { + if (iip >= cfig.dnsRanges[i].rangeStart && iip <= cfig.dnsRanges[i].rangeEnd) + return req->bytes; + } + + if (isLocal(ip)) + return req->bytes; + + if (getRangeInd(ip) >= 0) + return req->bytes; + + if (findDNSEntry(IP2String(req->cname, iip), DNS_TYPE_PTR, CTYPE_LOCAL_PTR_NAUTH)) + return req->bytes; + + if (findServer(network.allServers, MAX_SERVERS, ip)) + return req->bytes; + + if (verbatim || cfig.dnsLogLevel >= 1) { + sprintf(logBuff, "DNS UDP Query, Access Denied"); + logDNSMess(req, logBuff, 1); + } + + addRRError(req, RCODE_REFUSED); + return 0; +} + +MYWORD scanloc(data5 *req) { + char logBuff[512]; + + if (!req->query[0]) + return 0; + + strcpy(req->mapname, req->query); + myLower(req->mapname); + req->qType = makeLocal(req->mapname); + //MYDWORD ip = req->remote.sin_addr.s_addr; + //sprintf(logBuff, "qType=%u dnsType=%u query=%s mapname=%s", req->qType, req->dnsType, req->query, req->mapname); + //logMess(logBuff, 2); + + //strcpy(req->cname, req->query); + if (req->qType == QTYPE_A_BARE) + sprintf(req->cname, "%s.%s", req->query, cfig.zone); + else + strcpy(req->cname, req->query); + + switch (req->qType) { + case QTYPE_P_EXT: + case QTYPE_A_EXT: + + break; + + case QTYPE_A_BARE: + case QTYPE_P_LOCAL: + case QTYPE_A_LOCAL: + case QTYPE_A_ZONE: + case QTYPE_P_ZONE: + + switch (req->dnsType) { + case DNS_TYPE_A: + case DNS_TYPE_PTR: + break; + + case DNS_TYPE_MX: { + if (!strcasecmp(req->query, cfig.zone) + && (cfig.authorized || cfig.mxServers[currentInd][0].hostname[0])) { + addRRNone(req); + addRRMX(req); + addRRNS(req); + addRRAd(req); + return 1; + } + break; + } + case DNS_TYPE_NS: { + if (cfig.authorized + && (req->qType == QTYPE_A_ZONE || req->qType == QTYPE_P_ZONE || req->qType == QTYPE_A_BARE)) { + addRRNone(req); + addRRNS(req); + addRRAd(req); + return 1; + } + break; + } + case DNS_TYPE_SOA: { + if (cfig.authorized) { + if (req->qType == QTYPE_P_ZONE) { + if (cfig.replication == 1 && req->remote.sin_addr.s_addr == cfig.zoneServers[1] + && (t - cfig.dnsCheck) < 2) { + if (cfig.refresh > (MYDWORD)(MY_MAX_TIME - t)) + cfig.dnsRepl = MY_MAX_TIME; + else + cfig.dnsRepl = t + cfig.refresh + cfig.retry + cfig.retry; + } + + cfig.dnsCheck = 0; + addRRNone(req); + addRRSOA(req); + return 1; + } else if (req->qType == QTYPE_A_ZONE) { + if (cfig.replication == 1 && req->remote.sin_addr.s_addr == cfig.zoneServers[1]) + cfig.dnsCheck = t; + + addRRNone(req); + addRRSOA(req); + return 1; + } else if (req->qType == QTYPE_A_BARE) { + addRRNone(req); + addRRSOA(req); + return 1; + } + } + break; + } + case DNS_TYPE_ANY: { + addRRAny(req); + return 1; + } + default: { + if (cfig.authorized) { + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, "%s, DNS Query Type not supported", strquery(req)); + logDNSMess(req, logBuff, 1); + } + addRRNone(req); + addRRNS(req); + addRRAd(req); + req->dnsp->header.rcode = RCODE_NOTIMPL; + return 1; + } else + return 0; + + break; + } + } + } + + for (int m = 0; m < 3; m++) { + req->iterBegin = dnsCache[currentInd].find(setMapName(req->tempname, req->mapname, req->dnsType)); + + if (req->iterBegin == dnsCache[currentInd].end()) + break; + + data7 *cache = req->iterBegin->second; + + if (cache->expiry < t && cache->cacheType != CTYPE_CACHED) + break; + + req->cacheType = cache->cacheType; + + switch (req->cacheType) { + case CTYPE_LOCAL_A: + case CTYPE_STATIC_A_AUTH: + addRRNone(req); + addRRA(req); + addRRNS(req); + addRRAd(req); + return 1; + + case CTYPE_LOCAL_PTR_AUTH: + case CTYPE_STATIC_PTR_AUTH: + case CTYPE_SERVER_PTR_AUTH: + addRRNone(req); + addRRPtr(req); + addRRNS(req); + addRRAd(req); + return 1; + + case CTYPE_LOCALHOST_A: + addRRNone(req); + addRRLocalhostA(req, cache); + return 1; + + case CTYPE_LOCALHOST_PTR: + addRRNone(req); + addRRLocalhostPtr(req, cache); + return 1; + + case CTYPE_STATIC_A_NAUTH: + addRRNone(req); + addRRA(req); + return 1; + + case CTYPE_LOCAL_PTR_NAUTH: + case CTYPE_SERVER_PTR_NAUTH: + case CTYPE_STATIC_PTR_NAUTH: + addRRNone(req); + addRRPtr(req); + return 1; + + case CTYPE_SERVER_A_AUTH: + addRRNone(req); + addRRServerA(req); + addRRNS(req); + addRRAd(req); + return 1; + + case CTYPE_CACHED: + addRRNone(req); + addRRCache(req, cache); + return 1; + + case CTYPE_LOCAL_CNAME: + case CTYPE_EXT_CNAME: + + if (!cache->hostname[0]) + strcpy(req->cname, cfig.zone); + else if (strchr(cache->hostname, '.')) + strcpy(req->cname, cache->hostname); + else + sprintf(req->cname, "%s.%s", cache->hostname, cfig.zone); + + //sprintf(logBuff, "cacheType=%u, cache->name=%s, cname=%s, hostname=%s", cache->cacheType, cache->name, req->cname, cache->hostname); + //logMess(logBuff, 2); + + strcpy(req->mapname, cache->hostname); + myLower(req->mapname); + continue; + + default: + break; + } + } + + //sprintf(logBuff, "cacheType=%u,dnsType=%u,query=%s,cname=%s", req->cacheType, req->dnsType, req->query, req->cname); + //logMess(logBuff, 2); + + if (req->dnsType == DNS_TYPE_A && cfig.wildHosts[0].wildcard[0]) { + for (MYWORD i = 0; i < MAX_WILD_HOSTS && cfig.wildHosts[i].wildcard[0]; i++) { + if (wildcmp(req->mapname, cfig.wildHosts[i].wildcard)) { + addRRNone(req); + + if (cfig.wildHosts[i].ip) + addRRWildA(req, cfig.wildHosts[i].ip); + + return 1; + } + } + } + + if (req->cacheType == CTYPE_EXT_CNAME) { + req->qType = makeLocal(req->cname); + req->dp = &req->dnsp->data; + req->dp += pQu(req->dp, req->cname); + req->dp += pUShort(req->dp, DNS_TYPE_A); + req->dp += pUShort(req->dp, DNS_CLASS_IN); + req->bytes = (int)(req->dp - req->raw); + return 0; + } else if (req->qType == QTYPE_A_BARE || req->qType == QTYPE_A_ZONE || req->qType == QTYPE_P_ZONE) { + addRRNone(req); + addRRA(req); + addRRNS(req); + addRRAd(req); + return 1; + } + + return 0; +} + +MYWORD fdnmess(data5 *req) { + //printf("before qType=%d %d\n", req->qType, QTYPE_A_SUBZONE); + char ipbuff[32]; + char logBuff[256]; + req->qLen = strlen(req->cname); + MYBYTE zoneDNS; + int nRet = -1; + + char mapname[8]; + sprintf(mapname, "%u", req->dnsp->header.xid); + data7 *queue = findQueue(mapname); + + for (zoneDNS = 0; zoneDNS < MAX_COND_FORW && cfig.dnsRoutes[zoneDNS].zLen; zoneDNS++) { + if (req->qLen == cfig.dnsRoutes[zoneDNS].zLen && !strcasecmp(req->cname, cfig.dnsRoutes[zoneDNS].zone)) + req->qType = QTYPE_CHILDZONE; + else if (req->qLen > cfig.dnsRoutes[zoneDNS].zLen) { + char *dp = req->cname + (req->qLen - cfig.dnsRoutes[zoneDNS].zLen - 1); + + if (*dp == '.' && !strcasecmp(dp + 1, cfig.dnsRoutes[zoneDNS].zone)) + req->qType = QTYPE_CHILDZONE; + } + + if (req->qType == QTYPE_CHILDZONE) { + if (queue && cfig.dnsRoutes[zoneDNS].dns[1]) + cfig.dnsRoutes[zoneDNS].currentDNS = 1 - cfig.dnsRoutes[zoneDNS].currentDNS; + + if (req->remote.sin_addr.s_addr != cfig.dnsRoutes[zoneDNS].dns[cfig.dnsRoutes[zoneDNS].currentDNS]) { + req->addr.sin_family = AF_INET; + req->addr.sin_addr.s_addr = cfig.dnsRoutes[zoneDNS].dns[cfig.dnsRoutes[zoneDNS].currentDNS]; + req->addr.sin_port = htons(IPPORT_DNS); + errno = 0; + + nRet = (int)sendto( + network.forwConn.sock, req->raw, req->bytes, 0, (sockaddr *)&req->addr, sizeof(req->addr)); + + //errno = WSAGetLastError(); + + if (errno || nRet <= 0) { + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, + "Error Forwarding UDP DNS Message to Conditional Forwarder %s", + IP2String(ipbuff, req->addr.sin_addr.s_addr)); + logDNSMess(req, logBuff, 1); + addRRNone(req); + req->dnsp->header.rcode = RCODE_SERVERFAIL; + } + + if (cfig.dnsRoutes[zoneDNS].dns[1]) + cfig.dnsRoutes[zoneDNS].currentDNS = 1 - cfig.dnsRoutes[zoneDNS].currentDNS; + + return 0; + } else { + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, + "%s forwarded to Conditional Forwarder %s", + strquery(req), + IP2String(ipbuff, cfig.dnsRoutes[zoneDNS].dns[cfig.dnsRoutes[zoneDNS].currentDNS])); + logDNSMess(req, logBuff, 2); + } + } + } + + break; + } + } + + if (req->qType != QTYPE_CHILDZONE) { + //sprintf(logBuff, "after qType=%d %d", req->qType, QTYPE_CHILDZONE); + //logMess(logBuff, 2); + + if (cfig.authorized && (req->qType == QTYPE_A_LOCAL || req->qType == QTYPE_P_LOCAL)) { + switch (req->dnsType) { + case DNS_TYPE_A: + addRRNone(req); + addRRA(req); + addRRNS(req); + addRRAd(req); + return 0; + + case DNS_TYPE_SOA: + addRRNone(req); + addRRSOA(req); + return 0; + + default: + addRRNone(req); + addRRNS(req); + addRRAd(req); + return 0; + } + } + + if (!req->dnsp->header.rd) { + addRRNone(req); + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, "%s is not found (recursion not desired)", strquery(req)); + logDNSMess(req, logBuff, 2); + } + return 0; + } + + if (!network.dns[0]) { + addRRNone(req); + req->dnsp->header.ra = 0; + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, "%s not found (recursion not available)", strquery(req)); + logDNSMess(req, logBuff, 2); + } + return 0; + } + + if (queue && network.dns[1] && queue->dnsIndex < MAX_SERVERS && network.currentDNS == queue->dnsIndex) { + network.currentDNS++; + + if (network.currentDNS >= MAX_SERVERS || !network.dns[network.currentDNS]) + network.currentDNS = 0; + } + + if (req->remote.sin_addr.s_addr != network.dns[network.currentDNS]) { + req->addr.sin_family = AF_INET; + req->addr.sin_addr.s_addr = network.dns[network.currentDNS]; + req->addr.sin_port = htons(IPPORT_DNS); + errno = 0; + + nRet = (int)sendto( + network.forwConn.sock, req->raw, req->bytes, 0, (sockaddr *)&req->addr, sizeof(req->addr)); + + //errno = WSAGetLastError(); + + if (errno || nRet <= 0) { + if (verbatim || cfig.dnsLogLevel) { + sprintf(logBuff, + "Error forwarding UDP DNS Message to Forwarding Server %s", + IP2String(ipbuff, network.dns[network.currentDNS])); + logDNSMess(req, logBuff, 1); + addRRNone(req); + req->dnsp->header.rcode = RCODE_SERVERFAIL; + } + + if (network.dns[1]) { + network.currentDNS++; + + if (network.currentDNS >= MAX_SERVERS || !network.dns[network.currentDNS]) + network.currentDNS = 0; + } + + return 0; + } else { + if (verbatim || cfig.dnsLogLevel >= 2) { + sprintf(logBuff, + "%s forwarded to Forwarding Server %s", + strquery(req), + IP2String(ipbuff, network.dns[network.currentDNS])); + logDNSMess(req, logBuff, 2); + } + } + } + } + + if (!queue) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.dnsType = req->dnsType; + g_lump.cacheType = CTYPE_QUEUE; + g_lump.mapname = mapname; + g_lump.addr = &req->remote; + g_lump.query = req->query; + queue = createCache(&g_lump); + + if (queue) { + queue->expiry = 2 + t; + addDNSEntry(queue); + } else + return 0; + } else { + queue->expiry = 2 + t; + memcpy(queue->addr, &req->remote, sizeof(req->remote)); + } + + queue->sockInd = req->sockInd; + + if (req->qType == QTYPE_CHILDZONE) + queue->dnsIndex = 128 + (2 * zoneDNS) + cfig.dnsRoutes[zoneDNS].currentDNS; + else + queue->dnsIndex = network.currentDNS; + + //sprintf(logBuff, "queue created for %s", req->query); + + return (nRet); +} + +MYWORD frdnmess(data5 *req) { + char tempbuff[512]; + memset(req, 0, sizeof(data5)); + req->sockLen = sizeof(req->remote); + errno = 0; + MYBYTE dnsType = 0; + + req->bytes = (int)recvfrom( + network.forwConn.sock, req->raw, sizeof(req->raw), 0, (sockaddr *)&req->remote, &req->sockLen); + + //errno = WSAGetLastError(); + + if (errno || req->bytes <= 0) + return 0; + + req->dnsp = (dnsPacket *)req->raw; + req->dp = &req->dnsp->data; + + for (int i = 1; i <= ntohs(req->dnsp->header.qdcount); i++) { + req->dp += fQu(req->cname, req->dnsp, req->dp); + strcpy(req->mapname, req->cname); + dnsType = fUShort(req->dp); + req->dp += 4;//type and class + + if (dnsType == DNS_TYPE_PTR) { + myLower(req->mapname); + char *dp = strstr(req->mapname, arpa); + + if (dp && !strcasecmp(dp, arpa)) + *dp = 0; + } else { + strcpy(req->mapname, req->cname); + myLower(req->mapname); + } + } + + if ((dnsType == DNS_TYPE_A || dnsType == DNS_TYPE_ANY || dnsType == DNS_TYPE_AAAA || dnsType == DNS_TYPE_PTR) + && !req->dnsp->header.rcode && !req->dnsp->header.tc && req->dnsp->header.ancount) { + time_t expiry = 0; + bool resultFound = false; + + for (int i = 1; i <= ntohs(req->dnsp->header.ancount); i++) { + resultFound = true; + req->dp += fQu(tempbuff, req->dnsp, req->dp); + //dnsType = fUShort(req->dp); + + //logDNSMess(tempbuff, 2); + req->dp += 4;//type and class + + if (!expiry || fUInt(req->dp) < (MYDWORD)expiry) + expiry = fUInt(req->dp); + + req->dp += 4;//ttl + int zLen = fUShort(req->dp); + req->dp += 2;//datalength + req->dp += zLen; + } + + if (resultFound) { + MYWORD cacheSize = req->dp - req->raw; + + if (cfig.minCache && expiry < cfig.minCache) + expiry = cfig.minCache; + + if (cfig.maxCache && expiry > cfig.maxCache) + expiry = cfig.maxCache; + + if (expiry < MY_MAX_TIME - t) + expiry += t; + else + expiry = MY_MAX_TIME; + + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_CACHED; + g_lump.dnsType = dnsType; + g_lump.mapname = req->mapname; + g_lump.bytes = req->bytes; + g_lump.response = (MYBYTE *)req->dnsp; + data7 *cache = createCache(&g_lump); + + if (cache) { + cache->expiry = expiry; + addDNSEntry(cache); + } + } + } + + char mapname[8]; + sprintf(mapname, "%u", req->dnsp->header.xid); + data7 *queue = findQueue(mapname); + + if (queue && queue->expiry) { + queue->expiry = 0; + + if (queue->dnsIndex < MAX_SERVERS) { + if (req->remote.sin_addr.s_addr != network.dns[network.currentDNS]) { + for (MYBYTE i = 0; i < MAX_SERVERS && network.dns[i]; i++) { + if (network.dns[i] == req->remote.sin_addr.s_addr) { + network.currentDNS = i; + break; + } + } + } + } else if (queue->dnsIndex >= 128 && queue->dnsIndex < 192) { + MYBYTE rid = (queue->dnsIndex - 128) / 2; + data10 *dnsRoute = &cfig.dnsRoutes[rid]; + + if (dnsRoute->dns[0] == req->remote.sin_addr.s_addr) + dnsRoute->currentDNS = 0; + else if (dnsRoute->dns[1] == req->remote.sin_addr.s_addr) + dnsRoute->currentDNS = 1; + } + + memcpy(&req->remote, queue->addr, sizeof(req->remote)); + strcpy(req->query, queue->query); + req->sockInd = queue->sockInd; + req->dnsIndex = queue->dnsIndex; + req->dnsType = queue->dnsType; + addRRExt(req); + return 1; + } + + return 0; +} + +MYWORD sdnmess(data5 *req) { + + errno = 0; + req->bytes = (int)(req->dp - req->raw); + req->bytes = (int)sendto( + network.dnsUdpConn[req->sockInd].sock, req->raw, req->bytes, 0, (sockaddr *)&req->remote, sizeof(req->remote)); + + //errno = WSAGetLastError(); + + if (errno || req->bytes <= 0) + return 0; + else + return req->bytes; +} + +void add2Cache(char *hostname, MYDWORD ip, time_t expiry, MYBYTE aType, MYBYTE pType) { + //char logBuff[256]; + //char ipbuff[256]; + //sprintf(logBuff, "Adding %s=%s %u", hostname, IP2String(ipbuff, ip), expiry - t); + //debug(logBuff); + + //memset(&g_lump, 0, sizeof(data71)); + + char tempbuff[512]; + + if (!hostname || !ip) + return; + + data7 *cache = nullptr; + hostMap::iterator p; + + if (pType) { + IP2String(tempbuff, htonl(ip), DNS_TYPE_PTR); + p = dnsCache[currentInd].find(tempbuff); + + for (; p != dnsCache[currentInd].end(); p++) { + if (strcasecmp(p->second->mapname, tempbuff) != 0) + break; + + if (!strcasecmp(p->second->hostname, hostname)) { + cache = p->second; + break; + } + } + + if (!cache) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = pType; + g_lump.dnsType = DNS_TYPE_PTR; + g_lump.mapname = IP2String(tempbuff, htonl(ip)); + g_lump.hostname = hostname; + cache = createCache(&g_lump); + + if (cache) { + cache->expiry = expiry; + addDNSEntry(cache); + + if (cfig.replication != 2 && (pType == CTYPE_LOCAL_PTR_AUTH || pType == CTYPE_SERVER_PTR_AUTH)) + cfig.serial2 = t; + } + } else if (cache->expiry < expiry) { + cache->cacheType = pType; + cache->expiry = expiry; + } + //printf("Added %s=%s\n", IP2String(ipbuff, ip), hostname); + } + + if (aType) { + cache = nullptr; + setMapName(tempbuff, hostname, DNS_TYPE_A); + + p = dnsCache[currentInd].find(tempbuff); + + for (; p != dnsCache[currentInd].end(); p++) { + if (strcasecmp(p->second->mapname, tempbuff) != 0) + break; + + if (p->second->ip == ip) { + cache = p->second; + break; + } + } + + if (!cache) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = aType; + g_lump.dnsType = DNS_TYPE_A; + g_lump.mapname = hostname; + cache = createCache(&g_lump); + + if (cache) { + cache->ip = ip; + cache->expiry = expiry; + addDNSEntry(cache); + + if (cfig.replication != 2 && (aType == CTYPE_LOCAL_A || aType == CTYPE_SERVER_A_AUTH)) + cfig.serial1 = t; + } + } else if (cache->expiry < expiry) { + cache->cacheType = aType; + cache->expiry = expiry; + } + } +} + +void expireEntry(MYDWORD ip) { + char ipbuff[32]; + + if (!ip) + return; + + IP2String(ipbuff, htonl(ip)); + data7 *cache = findDNSEntry(ipbuff, DNS_TYPE_PTR, CTYPE_LOCAL_PTR_AUTH); + + if (!cache) + cache = findDNSEntry(ipbuff, DNS_TYPE_PTR, CTYPE_LOCAL_PTR_NAUTH); + + if (cache && cache->hostname[0] && cache->expiry < MY_MAX_TIME) { + data7 *cache1 = findDNSEntry(cache->hostname, DNS_TYPE_A, CTYPE_LOCAL_A); + + if (cache1 && cache1->ip == ip && cache1->expiry < MY_MAX_TIME) { + cache->expiry = 0; + cache1->expiry = 0; + } + } +} + +void addHostNotFound(char *hostname) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_STATIC_A_NAUTH; + g_lump.dnsType = DNS_TYPE_A; + g_lump.mapname = hostname; + data7 *cache = createCache(&g_lump); + /* + data7 *cache = (data7*)calloc(1, sizeof(data7)); + + if (cache) + { + cache->mapname = myLower(cloneString(hostname)); + + if (!cache->mapname) + { + sprintf(logBuff, "Memory Allocation Error"); + free(cache); + logDNSMess(logBuff, 1); + return; + } + + cache->ip = 0; + cache->cacheType = CTYPE_STATIC_A_NAUTH; + cache->expiry = MY_MAX_TIME; + addDNSEntry(cache); + } +*/ + if (cache) { + cache->ip = 0; + cache->cacheType = CTYPE_STATIC_A_NAUTH; + cache->expiry = MY_MAX_TIME; + addDNSEntry(cache); + } +} + +char *getResult(data5 *req) { + char buff[256]; + + req->tempname[0] = 0; + char *raw = &req->dnsp->data; + MYWORD queueIndex; + + for (int i = 1; i <= ntohs(req->dnsp->header.qdcount); i++) { + raw += fQu(buff, req->dnsp, raw); + raw += 4; + } + + for (int i = 1; i <= ntohs(req->dnsp->header.ancount); i++) { + raw += fQu(buff, req->dnsp, raw); + int type = fUShort(raw); + raw += 2;//type + raw += 2;//class + raw += 4;//ttl + int zLen = fUShort(raw); + raw += 2;//datalength + + if (type == DNS_TYPE_A) + return IP2String(req->tempname, fIP(raw)); + else if (type == DNS_TYPE_AAAA) + return IP62String(req->tempname, (MYBYTE *)raw); + else if (type == DNS_TYPE_PTR) { + fQu(req->tempname, req->dnsp, raw); + return req->tempname; + } else if (type == DNS_TYPE_MX) + fQu(req->tempname, req->dnsp, (raw + 2)); + else if (type == DNS_TYPE_CNAME) + fQu(req->tempname, req->dnsp, raw); + else if (type == DNS_TYPE_NS) + fQu(req->tempname, req->dnsp, raw); + + raw += zLen; + } + + if (req->tempname[0]) + return req->tempname; + else + return nullptr; +} + +bool checkRange(data17 *rangeData, char rangeInd) { + + if (!cfig.hasFilter) + return true; + + MYBYTE rangeSetInd = cfig.dhcpRanges[rangeInd].rangeSetInd; + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + //printf("checkRange entering, rangeInd=%i rangeSetInd=%i\n", rangeInd, rangeSetInd); + //printf("checkRange entered, macFound=%i vendFound=%i userFound=%i\n", macFound, vendFound, userFound); + + if ((!rangeData->macFound && !rangeSet->macSize[0]) || (rangeData->macFound && rangeData->macArray[rangeSetInd])) + if ((!rangeData->vendFound && !rangeSet->vendClassSize[0]) + || (rangeData->vendFound && rangeData->vendArray[rangeSetInd])) + if ((!rangeData->userFound && !rangeSet->userClassSize[0]) + || (rangeData->userFound && rangeData->userArray[rangeSetInd])) + if ((!rangeData->subnetFound && !rangeSet->subnetIP[0]) + || (rangeData->subnetFound && rangeData->subnetArray[rangeSetInd])) + return true; + + //printf("checkRange, returning false rangeInd=%i rangeSetInd=%i\n", rangeInd, rangeSetInd); + return false; +} + +bool checkIP(data9 *req, data17 *rangeData, MYDWORD ip) { + MYDWORD rangeStart; + MYDWORD rangeEnd; + + char rangeInd = getRangeInd(ip); + + if (rangeInd < 0) + return false; + + if (!checkRange(rangeData, rangeInd)) + return false; + + MYWORD ind = getIndex(rangeInd, ip); + data13 *range = &cfig.dhcpRanges[rangeInd]; + data7 *dhcpEntry = range->dhcpEntry[ind]; + + if ((req->dhcpEntry != dhcpEntry && range->expiry[ind] > t) or range->expiry[ind] == MY_MAX_TIME) + return false; + + if (req->subnetIP) { + if (cfig.rangeSet[range->rangeSetInd].subnetIP[0]) { + rangeStart = range->rangeStart; + rangeEnd = range->rangeEnd; + } else { + calcRangeLimits(req->subnetIP, range->mask, &rangeStart, &rangeEnd); + + if (rangeStart < range->rangeStart) + rangeStart = range->rangeStart; + + if (rangeEnd > range->rangeEnd) + rangeEnd = range->rangeEnd; + } + + if (htonl(ip) >= rangeStart && htonl(ip) <= rangeEnd) + return true; + } else { + calcRangeLimits(network.dhcpConn[req->sockInd].server, range->mask, &rangeStart, &rangeEnd); + + if (rangeStart < range->rangeStart) + rangeStart = range->rangeStart; + + if (rangeEnd > range->rangeEnd) + rangeEnd = range->rangeEnd; + + if (htonl(ip) >= rangeStart && htonl(ip) <= rangeEnd) + return true; + } + return false; +} + +MYDWORD resad(data9 *req) { + char logBuff[512]; + char tempbuff[512]; + + if (req->dhcpp.header.bp_giaddr) { + lockIP(req->dhcpp.header.bp_giaddr); + lockIP(req->remote.sin_addr.s_addr); + } + + req->dhcpEntry = findDHCPEntry(req->chaddr); + + if (req->dhcpEntry && req->dhcpEntry->fixed) { + if (req->dhcpEntry->ip) { + setTempLease(req->dhcpEntry); + return req->dhcpEntry->ip; + } else { + if (verbatim || cfig.dhcpLogLevel) { + sprintf( + logBuff, "Static DHCP Host %s (%s) has No IP, DHCPDISCOVER ignored", req->chaddr, req->hostname); + logDHCPMess(logBuff, 1); + } + return 0; + } + } + + MYDWORD rangeStart = 0; + MYDWORD rangeEnd = 0; + MYDWORD iipNew = 0; + MYDWORD iipExp = 0; + bool rangeFound = false; + data17 rangeData {}; + memset(&rangeData, 0, sizeof(data17)); + + if (cfig.hasFilter) { + for (MYBYTE rangeSetInd = 0; rangeSetInd < MAX_RANGE_SETS && cfig.rangeSet[rangeSetInd].active; rangeSetInd++) { + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && rangeSet->macSize[i]; i++) { + //printf("%s\n", hex2String(tempbuff, rangeSet->macStart[i], rangeSet->macSize[i])); + //printf("%s\n", hex2String(tempbuff, rangeSet->macEnd[i], rangeSet->macSize[i])); + + if (memcmp(req->dhcpp.header.bp_chaddr, rangeSet->macStart[i], rangeSet->macSize[i]) >= 0 + && memcmp(req->dhcpp.header.bp_chaddr, rangeSet->macEnd[i], rangeSet->macSize[i]) <= 0) { + rangeData.macArray[rangeSetInd] = 1; + rangeData.macFound = true; + //printf("mac Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->vendClass.size && rangeSet->vendClassSize[i]; i++) { + if (rangeSet->vendClassSize[i] == req->vendClass.size + && !memcmp(req->vendClass.value, rangeSet->vendClass[i], rangeSet->vendClassSize[i])) { + rangeData.vendArray[rangeSetInd] = 1; + rangeData.vendFound = true; + //printf("vend Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->userClass.size && rangeSet->userClassSize[i]; i++) { + if (rangeSet->userClassSize[i] == req->userClass.size + && !memcmp(req->userClass.value, rangeSet->userClass[i], rangeSet->userClassSize[i])) { + rangeData.userArray[rangeSetInd] = 1; + rangeData.userFound = true; + //printf("user Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->subnetIP && rangeSet->subnetIP[i]; i++) { + if (req->subnetIP == rangeSet->subnetIP[i]) { + rangeData.subnetArray[rangeSetInd] = 1; + rangeData.subnetFound = true; + //printf("subnet Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + } + } + + // printArray("macArray", (char*)cfig.macArray); + // printArray("vendArray", (char*)cfig.vendArray); + // printArray("userArray", (char*)cfig.userArray); + + if (!iipNew && req->reqIP && checkIP(req, &rangeData, req->reqIP)) + iipNew = ntohl(req->reqIP); + + if (!iipNew && req->dhcpEntry && req->dhcpEntry->ip && checkIP(req, &rangeData, req->dhcpEntry->ip)) + iipNew = ntohl(req->dhcpEntry->ip); + + if (!iipNew && dnsService && req->hostname[0]) { + char hostname[128]; + strcpy(hostname, req->hostname); + myLower(hostname); + auto it = dnsCache[currentInd].find(hostname); + + for (; it != dnsCache[currentInd].end(); it++) { + data7 *cache = it->second; + + //printf("%u\n", cache->mapname); + + if (!cache || strcasecmp(cache->mapname, hostname) != 0) + break; + + if (cache->ip && checkIP(req, &rangeData, cache->ip)) + iipNew = ntohl(cache->ip); + } + } + + for (char k = 0; !iipNew && k < cfig.rangeCount; k++) { + data13 *range = &cfig.dhcpRanges[k]; + + if (checkRange(&rangeData, k)) { + if (!cfig.rangeSet[range->rangeSetInd].subnetIP[0]) { + if (req->subnetIP) + calcRangeLimits(req->subnetIP, range->mask, &rangeStart, &rangeEnd); + else + calcRangeLimits(network.dhcpConn[req->sockInd].server, + network.dhcpConn[req->sockInd].mask, + &rangeStart, + &rangeEnd); + + if (rangeStart < range->rangeStart) + rangeStart = range->rangeStart; + + if (rangeEnd > range->rangeEnd) + rangeEnd = range->rangeEnd; + } else { + rangeStart = range->rangeStart; + rangeEnd = range->rangeEnd; + } + + if (rangeStart <= rangeEnd) { + //sprintf(logBuff, "Start=%u End=%u", rangeStart, rangeEnd); + //logMess(logBuff, 1); + rangeFound = true; + + if (cfig.replication == 2) { + for (MYDWORD m = rangeEnd; m >= rangeStart; m--) { + int ind = (int)(m - range->rangeStart); + + if (!range->expiry[ind]) { + iipNew = m; + break; + } else if (!iipExp && range->expiry[ind] < t) { + iipExp = m; + } + } + } else { + for (MYDWORD m = rangeStart; m <= rangeEnd; m++) { + int ind = (int)(m - range->rangeStart); + + //sprintf(logBuff, "Ind=%u Exp=%u", m, range->expiry[ind]); + //logMess(logBuff, 1); + + if (!range->expiry[ind]) { + iipNew = m; + break; + } else if (!iipExp && range->expiry[ind] < t) { + iipExp = m; + } + } + } + } + } + } + + //sprintf(logBuff, "New=%u Old=%u", iipNew, iipExp); + //logMess(logBuff, 1); + + if (!iipNew && iipExp) + iipNew = iipExp; + + if (iipNew) { + if (!req->dhcpEntry) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_DHCP_ENTRY; + g_lump.mapname = req->chaddr; + g_lump.hostname = req->hostname; + req->dhcpEntry = createCache(&g_lump); + + if (!req->dhcpEntry) + return 0; + + dhcpCache[req->dhcpEntry->mapname] = req->dhcpEntry; + } + + char idx = getRangeInd(req->dhcpEntry->ip); + + req->dhcpEntry->ip = htonl(iipNew); + req->dhcpEntry->rangeInd = idx < 0 ? -1 : (int)idx; + req->dhcpEntry->subnetFlg = !!req->subnetIP; + setTempLease(req->dhcpEntry); + return req->dhcpEntry->ip; + } + + if (verbatim || cfig.dhcpLogLevel) { + if (rangeFound) { + if (req->dhcpp.header.bp_giaddr) + sprintf(logBuff, + "No free leases for DHCPDISCOVER for %s (%s) from RelayAgent %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_giaddr)); + else + sprintf(logBuff, + "No free leases for DHCPDISCOVER for %s (%s) from interface %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, network.dhcpConn[req->sockInd].server)); + } else { + if (req->dhcpp.header.bp_giaddr) + sprintf(logBuff, + "No Matching DHCP Range for DHCPDISCOVER for %s (%s) from RelayAgent %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_giaddr)); + else + sprintf(logBuff, + "No Matching DHCP Range for DHCPDISCOVER for %s (%s) from interface %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, network.dhcpConn[req->sockInd].server)); + } + logDHCPMess(logBuff, 1); + } + return 0; +} + +MYDWORD chkaddr(data9 *req) { + + req->dhcpEntry = findDHCPEntry(req->chaddr); + + if (!req->dhcpEntry || !req->dhcpEntry->ip) + return 0; + + char idx = getRangeInd(req->dhcpEntry->ip); + req->dhcpEntry->rangeInd = idx < 0 ? -1 : (int)idx; + + if (req->dhcpEntry->fixed) + return req->dhcpEntry->ip; + + MYDWORD rangeStart = 0; + MYDWORD rangeEnd = 0; + + if (req->dhcpEntry->rangeInd >= 0) { + data17 rangeData {}; + memset(&rangeData, 0, sizeof(data17)); + data13 *range = &cfig.dhcpRanges[req->dhcpEntry->rangeInd]; + int ind = getIndex((char)(req->dhcpEntry->rangeInd), req->dhcpEntry->ip); + bool rangeOK = true; + + if (cfig.hasFilter) { + for (MYBYTE rangeSetInd = 0; rangeSetInd < MAX_RANGE_SETS && cfig.rangeSet[rangeSetInd].active; + rangeSetInd++) { + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && rangeSet->macSize[i]; i++) { + //printf("%s\n", hex2String(tempbuff, rangeSet->macStart[i], rangeSet->macSize[i])); + //printf("%s\n", hex2String(tempbuff, rangeSet->macEnd[i], rangeSet->macSize[i])); + + if (memcmp(req->dhcpp.header.bp_chaddr, rangeSet->macStart[i], rangeSet->macSize[i]) >= 0 + && memcmp(req->dhcpp.header.bp_chaddr, rangeSet->macEnd[i], rangeSet->macSize[i]) <= 0) { + rangeData.macArray[rangeSetInd] = 1; + rangeData.macFound = true; + //printf("mac Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->vendClass.size && rangeSet->vendClassSize[i]; i++) { + if (rangeSet->vendClassSize[i] == req->vendClass.size + && !memcmp(req->vendClass.value, rangeSet->vendClass[i], rangeSet->vendClassSize[i])) { + rangeData.vendArray[rangeSetInd] = 1; + rangeData.vendFound = true; + //printf("vend Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->userClass.size && rangeSet->userClassSize[i]; i++) { + if (rangeSet->userClassSize[i] == req->userClass.size + && !memcmp(req->userClass.value, rangeSet->userClass[i], rangeSet->userClassSize[i])) { + rangeData.userArray[rangeSetInd] = 1; + rangeData.userFound = true; + //printf("user Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + + for (MYBYTE i = 0; i < MAX_RANGE_FILTERS && req->subnetIP && rangeSet->subnetIP[i]; i++) { + if (req->subnetIP == rangeSet->subnetIP[i]) { + rangeData.subnetArray[rangeSetInd] = 1; + rangeData.subnetFound = true; + //printf("subnet Found, rangeSetInd=%i\n", rangeSetInd); + break; + } + } + } + + MYBYTE rangeSetInd = range->rangeSetInd; + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + rangeOK = false; + + if ((!rangeData.macFound && !rangeSet->macSize[0]) + || (rangeData.macFound && rangeData.macArray[rangeSetInd])) + if ((!rangeData.vendFound && !rangeSet->vendClassSize[0]) + || (rangeData.vendFound && rangeData.vendArray[rangeSetInd])) + if ((!rangeData.userFound && !rangeSet->userClassSize[0]) + || (rangeData.userFound && rangeData.userArray[rangeSetInd])) + rangeOK = true; + } + + if (range->dhcpEntry[ind] == req->dhcpEntry && rangeOK) { + if (rangeData.subnetFound) { + if (rangeData.subnetArray[range->rangeSetInd]) + return req->dhcpEntry->ip; + else + return 0; + } else if (req->subnetIP) { + calcRangeLimits(req->subnetIP, range->mask, &rangeStart, &rangeEnd); + + if (rangeStart < range->rangeStart) + rangeStart = range->rangeStart; + + if (rangeEnd > range->rangeEnd) + rangeEnd = range->rangeEnd; + + if (htonl(req->dhcpEntry->ip) >= rangeStart && htonl(req->dhcpEntry->ip) <= rangeEnd) + return req->dhcpEntry->ip; + } else if (!req->dhcpEntry->subnetFlg && !cfig.rangeSet[range->rangeSetInd].subnetIP[0]) { + calcRangeLimits(network.dhcpConn[req->sockInd].server, range->mask, &rangeStart, &rangeEnd); + + if (rangeStart < range->rangeStart) + rangeStart = range->rangeStart; + + if (rangeEnd > range->rangeEnd) + rangeEnd = range->rangeEnd; + + if (htonl(req->dhcpEntry->ip) >= rangeStart && htonl(req->dhcpEntry->ip) <= rangeEnd) + return req->dhcpEntry->ip; + } else if (req->dhcpEntry->subnetFlg) + return req->dhcpEntry->ip; + } + } + + return 0; +} + +MYDWORD sdmess(data9 *req) { + //sprintf(logBuff, "sdmess, Request Type = %u",req->req_type); + char tempbuff[512]; + char logBuff[256]; + + if (req->req_type == DHCP_MESS_NONE) { + req->dhcpp.header.bp_yiaddr = chkaddr(req); + + if (req->dhcpp.header.bp_yiaddr && req->dhcpEntry && req->dhcpEntry->fixed) + req->lease = UINT_MAX; + else { + if (verbatim || cfig.dhcpLogLevel) { + sprintf(logBuff, "No Static Entry found for BOOTPREQUEST from Host %s", req->chaddr); + logDHCPMess(logBuff, 1); + } + + return 0; + } + } else if (req->req_type == DHCP_MESS_DECLINE) { + /* Thanks to Timo for fixing issue here */ + if (req->reqIP && chkaddr(req) == req->reqIP) { + lockIP(req->reqIP); + req->dhcpEntry->ip = 0; + req->dhcpEntry->expiry = MY_MAX_TIME; + req->dhcpEntry->display = false; + req->dhcpEntry->local = false; + + if (verbatim || cfig.dhcpLogLevel) { + sprintf(logBuff, + "IP Address %s declined by Host %s (%s), locked", + IP2String(tempbuff, req->reqIP), + req->chaddr, + req->dhcpEntry->hostname); + logDHCPMess(logBuff, 1); + } + } + + return 0; + } else if (req->req_type == DHCP_MESS_RELEASE) { + if (req->dhcpp.header.bp_ciaddr && chkaddr(req) == req->dhcpp.header.bp_ciaddr) { + req->dhcpEntry->display = false; + req->dhcpEntry->local = false; + setLeaseExpiry(req->dhcpEntry, 0); + + //_beginthread(updateStateFile, 0, (void*)req->dhcpEntry); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, updateStateFile, req->dhcpEntry); + pthread_attr_destroy(&attr); + + if (verbatim || cfig.dhcpLogLevel) { + sprintf(logBuff, + "IP Address %s released by Host %s (%s)", + IP2String(tempbuff, req->dhcpp.header.bp_ciaddr), + req->chaddr, + req->hostname); + logDHCPMess(logBuff, 1); + } + } + + return 0; + } else if (req->req_type == DHCP_MESS_INFORM) { + //printf("repl0=%s\n", IP2String(tempbuff, cfig.zoneServers[0])); + //printf("repl1=%s\n", IP2String(tempbuff, cfig.zoneServers[1])); + //printf("IP=%s bytes=%u replication=%i\n", IP2String(tempbuff, req->remote.sin_addr.s_addr), req->bytes, cfig.replication); + + if ((cfig.replication == 1 && req->remote.sin_addr.s_addr == cfig.zoneServers[1]) + || (cfig.replication == 2 && req->remote.sin_addr.s_addr == cfig.zoneServers[0])) + recvRepl(req); + + return 0; + } + //else if (req->req_type == DHCP_MESS_DISCOVER && strcasecmp(req->hostname, cfig.servername)) + else if (req->req_type == DHCP_MESS_DISCOVER) { + req->dhcpp.header.bp_yiaddr = resad(req); + + if (!req->dhcpp.header.bp_yiaddr) + return 0; + + req->resp_type = DHCP_MESS_OFFER; + } else if (req->req_type == DHCP_MESS_REQUEST) { + //printf("%s\n", IP2String(tempbuff, req->dhcpp.header.bp_ciaddr)); + + if (req->server) { + if (req->server == network.dhcpConn[req->sockInd].server) { + if (req->reqIP && req->reqIP == chkaddr(req) && req->dhcpEntry->expiry > t) { + req->resp_type = DHCP_MESS_ACK; + req->dhcpp.header.bp_yiaddr = req->reqIP; + } else if (req->dhcpp.header.bp_ciaddr && req->dhcpp.header.bp_ciaddr == chkaddr(req) + && req->dhcpEntry->expiry > t) { + req->resp_type = DHCP_MESS_ACK; + req->dhcpp.header.bp_yiaddr = req->dhcpp.header.bp_ciaddr; + req->dhcpp.header.bp_ciaddr = 0; + } else { + req->resp_type = DHCP_MESS_NAK; + req->dhcpp.header.bp_yiaddr = 0; + + if (verbatim || cfig.dhcpLogLevel) { + sprintf(logBuff, + "DHCPREQUEST from Host %s (%s) without Discover, NAKed", + req->chaddr, + req->hostname); + logDHCPMess(logBuff, 1); + } + } + } else + return 0; + } else if (req->dhcpp.header.bp_ciaddr && req->dhcpp.header.bp_ciaddr == chkaddr(req) + && req->dhcpEntry->expiry > t) { + req->resp_type = DHCP_MESS_ACK; + req->dhcpp.header.bp_yiaddr = req->dhcpp.header.bp_ciaddr; + req->dhcpp.header.bp_ciaddr = 0; + } else if (req->reqIP && req->reqIP == chkaddr(req) && req->dhcpEntry->expiry > t) { + req->resp_type = DHCP_MESS_ACK; + req->dhcpp.header.bp_yiaddr = req->reqIP; + } else { + req->resp_type = DHCP_MESS_NAK; + req->dhcpp.header.bp_yiaddr = 0; + + if (verbatim || cfig.dhcpLogLevel) { + sprintf(logBuff, "DHCPREQUEST from Host %s (%s) without Discover, NAKed", req->chaddr, req->hostname); + logDHCPMess(logBuff, 1); + } + } + } else + return 0; + + addOptions(req); + int packSize = (int)(req->vp - (MYBYTE *)&req->dhcpp); + packSize++; + + if (req->req_type == DHCP_MESS_NONE) + packSize = req->messsize; + + if (req->subnetIP && req->dhcpEntry && req->dhcpEntry->rangeInd >= 0) { + MYBYTE rangeSetInd = cfig.dhcpRanges[req->dhcpEntry->rangeInd].rangeSetInd; + req->targetIP = cfig.rangeSet[rangeSetInd].targetIP; + } + + if (req->targetIP) { + req->remote.sin_port = htons(IPPORT_DHCPS); + req->remote.sin_addr.s_addr = req->targetIP; + } else if (req->dhcpp.header.bp_giaddr) { + req->remote.sin_port = htons(IPPORT_DHCPS); + req->remote.sin_addr.s_addr = req->dhcpp.header.bp_giaddr; + } else if (req->dhcpp.header.bp_broadcast || !req->remote.sin_addr.s_addr) { + req->remote.sin_port = htons(IPPORT_DHCPC); + req->remote.sin_addr.s_addr = INADDR_BROADCAST; + } else { + req->remote.sin_port = htons(IPPORT_DHCPC); + } + + req->dhcpp.header.bp_op = BOOTP_REPLY; + errno = 0; + + if (req->req_type == DHCP_MESS_DISCOVER && !req->remote.sin_addr.s_addr) { + req->bytes = (int)sendto(network.dhcpConn[req->sockInd].sock, + req->raw, + packSize, + MSG_DONTROUTE, + (sockaddr *)&req->remote, + sizeof(req->remote)); + } else { + req->bytes = (int)sendto( + network.dhcpConn[req->sockInd].sock, req->raw, packSize, 0, (sockaddr *)&req->remote, sizeof(req->remote)); + } + + if (errno || req->bytes <= 0) + return 0; + + //printf("goes=%s %i\n",IP2String(tempbuff, req->dhcpp.header.bp_yiaddr),req->sockInd); + return req->dhcpp.header.bp_yiaddr; +} + +MYDWORD alad(data9 *req) { + //printf("in alad hostname=%s\n", req->hostname); + char tempbuff[512]; + char logBuff[256]; + + if (req->dhcpEntry && (req->req_type == DHCP_MESS_NONE || req->resp_type == DHCP_MESS_ACK)) { + MYDWORD hangTime = req->lease; + + if (req->rebind > req->lease) + hangTime = req->rebind; + + req->dhcpEntry->display = true; + req->dhcpEntry->local = true; + setLeaseExpiry(req->dhcpEntry, hangTime); + + if (dnsService && cfig.replication != 2) + updateDNS(req); + + //_beginthread(updateStateFile, 0, (void*)req->dhcpEntry); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, updateStateFile, req->dhcpEntry); + pthread_attr_destroy(&attr); + + if (verbatim || cfig.dhcpLogLevel >= 1) { + if (req->lease && req->reqIP) { + sprintf(logBuff, + "Host %s (%s) allotted %s for %u seconds", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_yiaddr), + req->lease); + } else if (req->req_type) { + sprintf(logBuff, + "Host %s (%s) renewed %s for %u seconds", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_yiaddr), + req->lease); + } else { + sprintf(logBuff, + "BOOTP Host %s (%s) allotted %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_yiaddr)); + } + logDHCPMess(logBuff, 1); + } + + if (cfig.replication && cfig.dhcpRepl > t) + sendRepl(req); + + return req->dhcpEntry->ip; + } else if ((verbatim || cfig.dhcpLogLevel >= 2) && req->resp_type == DHCP_MESS_OFFER) { + sprintf(logBuff, + "Host %s (%s) offered %s", + req->chaddr, + req->hostname, + IP2String(tempbuff, req->dhcpp.header.bp_yiaddr)); + logDHCPMess(logBuff, 2); + } + //printf("%u=out\n", req->resp_type); + return 0; +} + +void addOptions(data9 *req) { + + data3 op {}; + int i; + + if (req->req_type && req->resp_type) { + op.opt_code = DHCP_OPTION_MESSAGETYPE; + op.size = 1; + op.value[0] = req->resp_type; + pvdata(req, &op); + } + + if (req->dhcpEntry && req->resp_type != DHCP_MESS_DECLINE && req->resp_type != DHCP_MESS_NAK) { + strcpy(req->dhcpp.header.bp_sname, cfig.servername); + + if (req->dhcpEntry->fixed) { + //printf("%u,%u\n", req->dhcpEntry->options, *req->dhcpEntry->options); + MYBYTE *opPointer = req->dhcpEntry->options; + + if (opPointer) { + MYBYTE requestedOnly = *opPointer; + opPointer++; + + while (*opPointer && *opPointer != DHCP_OPTION_END) { + op.opt_code = *opPointer; + opPointer++; + op.size = *opPointer; + opPointer++; + + if (!requestedOnly || req->paramreqlist[*opPointer]) { + memcpy(op.value, opPointer, op.size); + pvdata(req, &op); + } + opPointer += op.size; + } + } + } + + if (req->req_type && req->resp_type) { + if (req->dhcpEntry->rangeInd >= 0) { + MYBYTE *opPointer = cfig.dhcpRanges[req->dhcpEntry->rangeInd].options; + //printf("Range=%i Pointer=%u\n", req->dhcpEntry->rangeInd,opPointer); + + if (opPointer) { + MYBYTE requestedOnly = *opPointer; + opPointer++; + + while (*opPointer && *opPointer != DHCP_OPTION_END) { + op.opt_code = *opPointer; + opPointer++; + op.size = *opPointer; + opPointer++; + + if (!requestedOnly || req->paramreqlist[*opPointer]) { + memcpy(op.value, opPointer, op.size); + pvdata(req, &op); + } + opPointer += op.size; + } + } + } + + MYBYTE *opPointer = cfig.options; + + if (opPointer) { + MYBYTE requestedOnly = *opPointer; + + opPointer++; + while (*opPointer && *opPointer != DHCP_OPTION_END) { + op.opt_code = *opPointer; + opPointer++; + op.size = *opPointer; + opPointer++; + + if (!requestedOnly || req->paramreqlist[*opPointer]) { + memcpy(op.value, opPointer, op.size); + pvdata(req, &op); + } + opPointer += op.size; + } + } + + op.opt_code = DHCP_OPTION_SERVERID; + op.size = 4; + pIP(op.value, network.dhcpConn[req->sockInd].server); + pvdata(req, &op); + + op.opt_code = DHCP_OPTION_DOMAINNAME; + op.size = strlen(cfig.zone) + 1; + memcpy(op.value, cfig.zone, op.size); + pvdata(req, &op); + + if (!req->opAdded[DHCP_OPTION_IPADDRLEASE]) { + op.opt_code = DHCP_OPTION_IPADDRLEASE; + op.size = 4; + pUInt(op.value, cfig.lease); + pvdata(req, &op); + } + + if (!req->opAdded[DHCP_OPTION_NETMASK]) { + op.opt_code = DHCP_OPTION_NETMASK; + op.size = 4; + + if (req->dhcpEntry->rangeInd >= 0) + pIP(op.value, cfig.dhcpRanges[req->dhcpEntry->rangeInd].mask); + else + pIP(op.value, cfig.mask); + + pvdata(req, &op); + } + + /* + if (!req->opAdded[DHCP_OPTION_ROUTER]) + { + op.opt_code = DHCP_OPTION_ROUTER; + op.size = 4; + pIP(op.value, network.dhcpConn[req->sockInd].server); + pvdata(req, &op); + } +*/ + /* + if (!req->opAdded[DHCP_OPTION_DNS]) + { + if (dnsService) + { + op.opt_code = DHCP_OPTION_DNS; + + if (cfig.dhcpRepl > t && cfig.dnsRepl > t) + { + if (cfig.replication == 1) + { + op.size = 8; + pIP(op.value, cfig.zoneServers[0]); + pIP(op.value + 4, cfig.zoneServers[1]); + pvdata(req, &op); + } + else + { + op.size = 8; + pIP(op.value, cfig.zoneServers[1]); + pIP(op.value + 4, cfig.zoneServers[0]); + pvdata(req, &op); + } + } + else if (cfig.dnsRepl > t) + { + op.size = 8; + pIP(op.value, cfig.zoneServers[1]); + pIP(op.value + 4, cfig.zoneServers[0]); + pvdata(req, &op); + } + else + { + op.size = 4; + pIP(op.value, network.dhcpConn[req->sockInd].server); + pvdata(req, &op); + } + } + else if (cfig.dnsRepl > t && cfig.replication == 2) + { + op.opt_code = DHCP_OPTION_DNS; + op.size = 4; + pIP(op.value, cfig.zoneServers[0]); + pvdata(req, &op); + } + } +*/ + if (!req->opAdded[DHCP_OPTION_DNS] && dnsService) { + op.opt_code = DHCP_OPTION_DNS; + + if (cfig.dnsRepl > t) { + op.size = 8; + pIP(op.value, cfig.zoneServers[0]); + pIP(op.value + 4, cfig.zoneServers[1]); + pvdata(req, &op); + } else { + op.size = 4; + pIP(op.value, network.dhcpConn[req->sockInd].server); + pvdata(req, &op); + } + } + /* + if (req->clientId.opt_code == DHCP_OPTION_CLIENTID) + pvdata(req, &req->clientId); +*/ + if (req->subnet.opt_code == DHCP_OPTION_SUBNETSELECTION) + pvdata(req, &req->subnet); + + if (req->agentOption.opt_code == DHCP_OPTION_RELAYAGENTINFO) + pvdata(req, &req->agentOption); + } + + if (req->hostname[0]) + strcpy(req->dhcpEntry->hostname, req->hostname); + else if (req->dhcpEntry->hostname[0]) + strcpy(req->hostname, req->dhcpEntry->hostname); + else { + genHostName(req->hostname, req->dhcpp.header.bp_chaddr, req->dhcpp.header.bp_hlen); + strcpy(req->dhcpEntry->hostname, req->hostname); + } + } + + *(req->vp) = DHCP_OPTION_END; +} + +void pvdata(data9 *req, data3 *op) { + MYBYTE opsize = op->size; + + if (!req->opAdded[op->opt_code] && ((req->vp - (MYBYTE *)&req->dhcpp) + opsize < req->messsize)) { + if (op->opt_code == DHCP_OPTION_NEXTSERVER) + req->dhcpp.header.bp_siaddr = fIP(op->value); + else if (op->opt_code == DHCP_OPTION_BP_FILE) { + if (opsize <= 128) + memcpy(req->dhcpp.header.bp_file, op->value, opsize); + } else if (opsize) { + if (op->opt_code == DHCP_OPTION_IPADDRLEASE) { + if (!req->lease || req->lease > fUInt(op->value)) + req->lease = fUInt(op->value); + + if (req->lease >= MY_MAX_TIME) + req->lease = UINT_MAX; + + pUInt(op->value, req->lease); + } else if (op->opt_code == DHCP_OPTION_REBINDINGTIME) + req->rebind = fUInt(op->value); + else if (op->opt_code == DHCP_OPTION_HOSTNAME) { + memcpy(req->hostname, op->value, opsize); + req->hostname[opsize] = 0; + req->hostname[64] = 0; + + if (char *ptr = strchr(req->hostname, '.')) + *ptr = 0; + + opsize = strlen(req->hostname) + 1; + memcpy(op->value, req->hostname, opsize); + } + + opsize += 2; + memcpy(req->vp, op, opsize); + (req->vp) += opsize; + } + req->opAdded[op->opt_code] = true; + } +} + +void updateDNS(data9 *req) { + if (req->dhcpEntry && cfig.replication != 2) { + MYDWORD expiry = MY_MAX_TIME; + + if (req->lease < (MYDWORD)(MY_MAX_TIME - t)) + expiry = t + req->lease; + + //printf("Update DNS t=%d exp=%d\n", t, req->dhcpEntry->expiry); + if (isLocal(req->dhcpEntry->ip)) + add2Cache(req->hostname, req->dhcpEntry->ip, expiry, CTYPE_LOCAL_A, CTYPE_LOCAL_PTR_AUTH); + else + add2Cache(req->hostname, req->dhcpEntry->ip, expiry, CTYPE_LOCAL_A, CTYPE_LOCAL_PTR_NAUTH); + } +} + +void setTempLease(data7 *dhcpEntry) { + if (dhcpEntry && dhcpEntry->ip) { + dhcpEntry->display = false; + dhcpEntry->local = false; + dhcpEntry->expiry = t + 20; + + int ind = getIndex((char)(dhcpEntry->rangeInd), dhcpEntry->ip); + + if (ind >= 0) { + if (cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] != MY_MAX_TIME) + cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] = dhcpEntry->expiry; + + cfig.dhcpRanges[dhcpEntry->rangeInd].dhcpEntry[ind] = dhcpEntry; + } + } +} + +void setLeaseExpiry(data7 *dhcpEntry, MYDWORD lease) { + //printf("%d=%d\n", t, lease); + if (dhcpEntry && dhcpEntry->ip) { + if (lease > (MYDWORD)(MY_MAX_TIME - t)) + dhcpEntry->expiry = MY_MAX_TIME; + else + dhcpEntry->expiry = t + lease; + + int ind = getIndex((char)(dhcpEntry->rangeInd), dhcpEntry->ip); + + if (ind >= 0) { + if (cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] != MY_MAX_TIME) + cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] = dhcpEntry->expiry; + + cfig.dhcpRanges[dhcpEntry->rangeInd].dhcpEntry[ind] = dhcpEntry; + } + } +} + +void setLeaseExpiry(data7 *dhcpEntry) { + if (dhcpEntry && dhcpEntry->ip) { + int ind = getIndex((char)(dhcpEntry->rangeInd), dhcpEntry->ip); + + if (ind >= 0) { + if (cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] != MY_MAX_TIME) + cfig.dhcpRanges[dhcpEntry->rangeInd].expiry[ind] = dhcpEntry->expiry; + + cfig.dhcpRanges[dhcpEntry->rangeInd].dhcpEntry[ind] = dhcpEntry; + } + } +} + +void lockIP(MYDWORD ip) { + if (dhcpService && ip) { + MYDWORD iip = htonl(ip); + + for (unsigned char rangeInd = 0; rangeInd < cfig.rangeCount; rangeInd++) { + if (iip >= cfig.dhcpRanges[rangeInd].rangeStart && iip <= cfig.dhcpRanges[rangeInd].rangeEnd) { + int ind = (int)(iip - cfig.dhcpRanges[rangeInd].rangeStart); + + if (cfig.dhcpRanges[rangeInd].expiry[ind] != MY_MAX_TIME) + cfig.dhcpRanges[rangeInd].expiry[ind] = MY_MAX_TIME; + + break; + } + } + } +} + +void holdIP(MYDWORD ip) { + if (dhcpService && ip) { + MYDWORD iip = htonl(ip); + + for (unsigned char rangeInd = 0; rangeInd < cfig.rangeCount; rangeInd++) { + if (iip >= cfig.dhcpRanges[rangeInd].rangeStart && iip <= cfig.dhcpRanges[rangeInd].rangeEnd) { + int ind = (int)(iip - cfig.dhcpRanges[rangeInd].rangeStart); + + if (cfig.dhcpRanges[rangeInd].expiry[ind] == 0) + cfig.dhcpRanges[rangeInd].expiry[ind] = 1; + + break; + } + } + } +} + +void *sendToken(void *lpParam) { + sleep(10); + + while (kRunning) { + strcpy(token.dhcpp.header.bp_sname, cfig.servername); + errno = 0; + + sendto(cfig.dhcpReplConn.sock, token.raw, token.bytes, 0, (sockaddr *)&token.remote, sizeof(token.remote)); + + // errno = WSAGetLastError(); + + // if (errno) + // else if (verbatim || cfig.dhcpLogLevel >= 2) + + sleep(300); + } + + pthread_exit(nullptr); +} + +MYDWORD sendRepl(data9 *req) { + char logBuff[256]; + char ipbuff[32]; + data3 op {}; + + MYBYTE *opPointer = req->dhcpp.vend_data; + + while ((*opPointer) != DHCP_OPTION_END && opPointer < req->vp) { + if ((*opPointer) == DHCP_OPTION_MESSAGETYPE) { + *(opPointer + 2) = DHCP_MESS_INFORM; + break; + } + opPointer = opPointer + *(opPointer + 1) + 2; + } + + if (!req->opAdded[DHCP_OPTION_MESSAGETYPE]) { + op.opt_code = DHCP_OPTION_MESSAGETYPE; + op.size = 1; + op.value[0] = DHCP_MESS_INFORM; + pvdata(req, &op); + } + + if (req->hostname[0] && !req->opAdded[DHCP_OPTION_HOSTNAME]) { + op.opt_code = DHCP_OPTION_HOSTNAME; + op.size = strlen(req->hostname) + 1; + memcpy(op.value, req->hostname, op.size); + pvdata(req, &op); + } + + // op.opt_code = DHCP_OPTION_SERIAL; + // op.size = 4; + // pUInt(op.value, cfig.serial1); + // pvdata(req, &op); + + *(req->vp) = DHCP_OPTION_END; + req->vp++; + req->bytes = (int)(req->vp - (MYBYTE *)req->raw); + + req->dhcpp.header.bp_op = BOOTP_REQUEST; + errno = 0; + + req->bytes = (int)sendto( + cfig.dhcpReplConn.sock, req->raw, req->bytes, 0, (sockaddr *)&token.remote, sizeof(token.remote)); + + //errno = WSAGetLastError(); + + if (errno || req->bytes <= 0) { + cfig.dhcpRepl = 0; + + if (verbatim || cfig.dhcpLogLevel >= 1) { + if (cfig.replication == 1) + sprintf(logBuff, "Error %s Sending DHCP Update to Secondary Server", strerror(errno)); + else + sprintf(logBuff, "Error %s Sending DHCP Update to Primary Server", strerror(errno)); + + logDHCPMess(logBuff, 1); + } + + return 0; + } else if (verbatim || cfig.dhcpLogLevel >= 2) { + if (cfig.replication == 1) + sprintf(logBuff, + "DHCP Update for host %s (%s) sent to Secondary Server", + req->dhcpEntry->mapname, + IP2String(ipbuff, req->dhcpEntry->ip)); + else + sprintf(logBuff, + "DHCP Update for host %s (%s) sent to Primary Server", + req->dhcpEntry->mapname, + IP2String(ipbuff, req->dhcpEntry->ip)); + + logDHCPMess(logBuff, 2); + } + + return req->dhcpp.header.bp_yiaddr; +} + +/* +MYDWORD sendRepl(data7 *dhcpEntry) +{ + data9 req; + memset(&req, 0, sizeof(data9)); + req.vp = req.dhcpp.vend_data; + req.messsize = sizeof(dhcp_packet); + req.dhcpEntry = dhcpEntry; + + req.dhcpp.header.bp_op = BOOTP_REQUEST; + req.dhcpp.header.bp_xid = t; + req.dhcpp.header.bp_ciaddr = dhcpEntry->ip; + req.dhcpp.header.bp_yiaddr = dhcpEntry->ip; + req.dhcpp.header.bp_hlen = 16; + getHexValue(req.dhcpp.header.bp_chaddr, req.dhcpEntry->mapname, &(req.dhcpp.header.bp_hlen)); + req.dhcpp.header.bp_magic_num[0] = 99; + req.dhcpp.header.bp_magic_num[1] = 130; + req.dhcpp.header.bp_magic_num[2] = 83; + req.dhcpp.header.bp_magic_num[3] = 99; + strcpy(req.hostname, dhcpEntry->hostname); + + return sendRepl(&req); +} +*/ + +void recvRepl(data9 *req) { + char ipbuff[32]; + char logBuff[512]; + cfig.dhcpRepl = t + 650; + + MYDWORD ip = req->dhcpp.header.bp_yiaddr ? req->dhcpp.header.bp_yiaddr : req->dhcpp.header.bp_ciaddr; + + if (!ip && !req->dhcpp.header.bp_hlen) { + // if (verbatim || cfig.dhcpLogLevel >= 2) + // { + // sprintf(logBuff, "Token Received"); + // logDHCPMess(logBuff, 2); + // } + + if (req->dns) + cfig.dnsRepl = t + 650; + + if (cfig.replication == 1) { + if (dnsService) { + sprintf(cfig.nsS, "%s.%s", req->dhcpp.header.bp_sname, cfig.zone); + add2Cache(req->dhcpp.header.bp_sname, + cfig.zoneServers[1], + (t + 650), + CTYPE_SERVER_A_AUTH, + CTYPE_SERVER_PTR_AUTH); + } + + errno = 0; + + sendto(cfig.dhcpReplConn.sock, token.raw, token.bytes, 0, (sockaddr *)&token.remote, sizeof(token.remote)); + + // errno = WSAGetLastError(); + // + // if (!errno && (verbatim || cfig.dhcpLogLevel >= 2)) + // { + // sprintf(logBuff, "Token Responded"); + // logDHCPMess(logBuff, 2); + // } + } else if (cfig.replication == 2) { + if (!cfig.nsP[0] && req->dhcpp.header.bp_sname[0]) + sprintf(cfig.nsP, "%s.%s", req->dhcpp.header.bp_sname, cfig.zone); + } + + return; + } + + char rInd = getRangeInd(ip); + + if (rInd >= 0) { + int ind = getIndex(rInd, ip); + req->dhcpEntry = cfig.dhcpRanges[rInd].dhcpEntry[ind]; + + if (req->dhcpEntry && !req->dhcpEntry->fixed && strcasecmp(req->dhcpEntry->mapname, req->chaddr) != 0) + req->dhcpEntry->expiry = 0; + } + + req->dhcpEntry = findDHCPEntry(req->chaddr); + + if (req->dhcpEntry && req->dhcpEntry->ip != ip) { + if (req->dhcpEntry->fixed) { + if (cfig.replication == 1) + sprintf(logBuff, + "DHCP Update ignored for %s (%s) from Secondary Server", + req->chaddr, + IP2String(ipbuff, ip)); + else + sprintf( + logBuff, "DHCP Update ignored for %s (%s) from Primary Server", req->chaddr, IP2String(ipbuff, ip)); + + logDHCPMess(logBuff, 1); + return; + } else if (req->dhcpEntry->rangeInd >= 0) { + int ind = getIndex((char)(req->dhcpEntry->rangeInd), req->dhcpEntry->ip); + + if (ind >= 0) + cfig.dhcpRanges[req->dhcpEntry->rangeInd].dhcpEntry[ind] = nullptr; + } + } + + if (!req->dhcpEntry && rInd >= 0) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_DHCP_ENTRY; + g_lump.mapname = req->chaddr; + g_lump.hostname = req->hostname; + req->dhcpEntry = createCache(&g_lump); + + if (req->dhcpEntry) + dhcpCache[req->dhcpEntry->mapname] = req->dhcpEntry; + /* + req->dhcpEntry = (data7*)calloc(1, sizeof(data7)); + + if (!req->dhcpEntry) + { + sprintf(logBuff, "Memory Allocation Error"); + logDHCPMess(logBuff, 1); + return; + } + + req->dhcpEntry->mapname = cloneString(req->chaddr); + + if (!req->dhcpEntry->mapname) + { + sprintf(logBuff, "Memory Allocation Error"); + free(req->dhcpEntry); + logDHCPMess(logBuff, 1); + return; + } +*/ + } + + if (req->dhcpEntry) { + req->dhcpEntry->ip = ip; + req->dhcpEntry->rangeInd = rInd < 0 ? -1 : (int)rInd; + req->dhcpEntry->display = true; + req->dhcpEntry->local = false; + + MYDWORD hangTime = req->lease; + + if (hangTime) { + if (req->rebind > hangTime) + hangTime = req->rebind; + } else + hangTime = UINT_MAX; + + setLeaseExpiry(req->dhcpEntry, hangTime); + strcpy(req->dhcpEntry->hostname, req->hostname); + + //_beginthread(updateStateFile, 0, (void*)req->dhcpEntry); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, updateStateFile, req->dhcpEntry); + pthread_attr_destroy(&attr); + + if (dnsService && cfig.replication != 2) { + if (req->lease) + updateDNS(req); + else + expireEntry(req->dhcpEntry->ip); + } + + if (verbatim || cfig.dhcpLogLevel >= 2) { + if (cfig.replication == 1) + sprintf(logBuff, + "DHCP Update received for %s (%s) from Secondary Server", + req->chaddr, + IP2String(ipbuff, ip)); + else + sprintf(logBuff, + "DHCP Update received for %s (%s) from Primary Server", + req->chaddr, + IP2String(ipbuff, ip)); + + logDHCPMess(logBuff, 2); + } + } else { + if (cfig.replication == 1) + sprintf( + logBuff, "DHCP Update ignored for %s (%s) from Secondary Server", req->chaddr, IP2String(ipbuff, ip)); + else + sprintf(logBuff, "DHCP Update ignored for %s (%s) from Primary Server", req->chaddr, IP2String(ipbuff, ip)); + + logDHCPMess(logBuff, 1); + return; + } +} + +char getRangeInd(MYDWORD ip) { + if (ip) { + MYDWORD iip = htonl(ip); + + for (unsigned char k = 0; k < cfig.rangeCount; k++) + if (iip >= cfig.dhcpRanges[k].rangeStart && iip <= cfig.dhcpRanges[k].rangeEnd) + return (char)k; + } + return -1; +} + +int getIndex(char rangeInd, MYDWORD ip) { + if (ip && rangeInd >= 0 && rangeInd < cfig.rangeCount) { + MYDWORD iip = htonl(ip); + if (iip >= cfig.dhcpRanges[rangeInd].rangeStart && iip <= cfig.dhcpRanges[rangeInd].rangeEnd) + return (int)(iip - cfig.dhcpRanges[rangeInd].rangeStart); + } + return -1; +} + +void loadOptions(FILE *f, const char *sectionName, data20 *optionData) { + optionData->ip = 0; + optionData->mask = 0; + MYBYTE maxInd = sizeof(opData) / sizeof(data4); + MYWORD buffsize = sizeof(dhcp_packet) - sizeof(dhcp_header); + MYBYTE *dp = optionData->options; + MYBYTE op_specified[256]; + + memset(op_specified, 0, 256); + *dp = 0; + dp++; + + char raw[512]; + char name[512]; + char value[512]; + char logBuff[512]; + + while (readSection(raw, f)) { + MYBYTE *ddp = dp; + MYBYTE hoption[256]; + MYBYTE valSize = sizeof(hoption) - 1; + MYBYTE opTag = 0; + MYBYTE opType = 0; + MYBYTE valType = 0; + bool tagFound = false; + + mySplit(name, value, raw, '='); + + //printf("%s=%s\n", name, value); + + if (!name[0]) { + sprintf(logBuff, "Warning: section [%s] invalid option %s ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + + if (!strcasecmp(name, "DHCPRange")) { + if (!strcasecmp(sectionName, RANGESET)) + addDHCPRange(value); + else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } else if (!strcasecmp(name, "IP")) { + if (!strcasecmp(sectionName, GLOBALOPTIONS) || !strcasecmp(sectionName, RANGESET)) { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } else if (!isIP(value) && strcasecmp(value, "0.0.0.0") != 0) { + sprintf(logBuff, "Warning: section [%s] option Invalid IP Addr %s option ignored", sectionName, value); + logDHCPMess(logBuff, 1); + } else + optionData->ip = inet_addr(value); + + continue; + } else if (!strcasecmp(name, "FilterMacRange")) { + if (!strcasecmp(sectionName, RANGESET)) + addMacRange(optionData->rangeSetInd, value); + else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } + + if (!value[0]) + valType = 9; + else if (value[0] == '"' && value[strlen(value) - 1] == '"') { + valType = 2; + value[0] = NBSP; + value[strlen(value) - 1] = NBSP; + myTrim(value, value); + + if (strlen(value) <= UCHAR_MAX) + valSize = strlen(value); + else { + sprintf(logBuff, "Warning: section [%s] option %s value too big, option ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + } else if (strchr(value, ':')) { + valType = 2; + valSize = sizeof(hoption) - 1; + char *errorPos = getHexValue(hoption, value, &valSize); + + if (errorPos) { + valType = 1; + valSize = strlen(value); + } else + memcpy(value, hoption, valSize); + } else if (isInt(value) && strtol(value, nullptr, 10) > USHRT_MAX) + valType = 4; + else if (isInt(value) && strtol(value, nullptr, 10) > UCHAR_MAX) + valType = 5; + else if (isInt(value)) + valType = 6; + else if (strchr(value, '.') || strchr(value, ',')) { + valType = 2; + char buff[1024]; + int numbytes = myTokenize(buff, value, "/,.", true); + + if (numbytes > 255) { + sprintf(logBuff, "Warning: section [%s] option %s, too many bytes, entry ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } else { + char *ptr = buff; + valSize = 0; + + for (; *ptr; ptr = myGetToken(ptr, 1)) { + //printf("%s:", ptr); + if (isInt(ptr) && strtol(ptr, nullptr, 10) <= UCHAR_MAX) { + hoption[valSize] = strtol(ptr, nullptr, 10); + valSize++; + } else + break; + } + + if (!(*ptr)) + memcpy(value, hoption, valSize); + else { + valType = 1; + valSize = strlen(value); + } + } + } else { + if (strlen(value) <= UCHAR_MAX) { + valSize = strlen(value); + valType = 1; + } else { + sprintf(logBuff, "Warning: section [%s] option %s value too long, option ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + } + + if (!strcasecmp(name, "FilterVendorClass")) { + if (!strcasecmp(sectionName, RANGESET)) + addVendClass(optionData->rangeSetInd, value, valSize); + else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } else if (!strcasecmp(name, "FilterUserClass")) { + if (!strcasecmp(sectionName, RANGESET)) + addUserClass(optionData->rangeSetInd, value, valSize); + else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } else if (!strcasecmp(name, "FilterSubnetSelection")) { + if (valSize != 4) { + sprintf(logBuff, "Warning: section [%s] invalid value %s, option ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + } else if (!strcasecmp(sectionName, RANGESET)) { + addServer(cfig.rangeSet[optionData->rangeSetInd].subnetIP, MAX_RANGE_FILTERS, fIP(value)); + cfig.hasFilter = 1; + } else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } else if (!strcasecmp(name, "TargetRelayAgent")) { + if (valSize != 4) { + sprintf(logBuff, "Warning: section [%s] invalid value %s, option ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + } else if (!strcasecmp(sectionName, RANGESET)) { + cfig.rangeSet[optionData->rangeSetInd].targetIP = fIP(value); + //printf("TARGET IP %s set RangeSetInd %d\n", IP2String(ipbuff, cfig.rangeSet[optionData->rangeSetInd].targetIP), optionData->rangeSetInd); + } else { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + continue; + } + + opTag = 0; + + if (isInt(name)) { + if (strtol(name, nullptr, 10) < 1 || strtol(name, nullptr, 10) >= 254) { + sprintf(logBuff, "Warning: section [%s] invalid option %s, ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + + opTag = strtol(name, nullptr, 10); + opType = 0; + } + + for (MYBYTE i = 0; i < maxInd; i++) + if (!strcasecmp(name, opData[i].opName) || (opTag && opTag == opData[i].opTag)) { + opTag = opData[i].opTag; + opType = opData[i].opType; + tagFound = true; + break; + } + + if (!opTag) { + sprintf(logBuff, "Warning: section [%s] invalid option %s, ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + + if (!opType) + opType = valType; + + //sprintf(logBuff, "Tag %i ValType %i opType %i value=%s size=%u", opTag, valType, opType, value, valSize); + //logDHCPMess(logBuff, 1); + + if (op_specified[opTag]) { + sprintf(logBuff, "Warning: section [%s] duplicate option %s, ignored", sectionName, raw); + logDHCPMess(logBuff, 1); + continue; + } + + //printf("Option=%u opType=%u valueType=%u valSize=%u\n", opTag, opType, valType, valSize); + + op_specified[opTag] = true; + + if (valType == 9) { + if (buffsize > 2) { + *dp = opTag; + dp++; + *dp = 0; + dp++; + buffsize -= 2; + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + continue; + } + + switch (opType) { + case 1: { + value[valSize] = 0; + valSize++; + + if (valType != 1 && valType != 2) { + sprintf(logBuff, + "Warning: section [%s] option %s, need string value, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } else if (!strcasecmp(serviceName, "DUALServer") && opTag == DHCP_OPTION_DOMAINNAME) { + sprintf(logBuff, + "Warning: section [%s] Domain Name %s should be in section [DOMAIN_NAME], ignored", + sectionName, + value); + logDHCPMess(logBuff, 1); + continue; + } else if (buffsize > valSize + 2) { + *dp = opTag; + dp++; + *dp = valSize; + dp++; + memcpy(dp, value, valSize); + dp += valSize; + buffsize -= (valSize + 2); + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + + case 3: + case 8: { + if (valType == 2) { + if (opType == 3 && valSize % 4) { + sprintf(logBuff, + "Warning: section [%s] option %s, missing/extra bytes/octates in IP, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } else if (opType == 8 && valSize % 8) { + sprintf(logBuff, + "Warning: section [%s] option %s, some values not in IP/Mask form, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } + + if (opTag == DHCP_OPTION_NETMASK) { + if (valSize != 4 || !checkMask(fIP(value))) { + sprintf(logBuff, + "Warning: section [%s] Invalid subnetmask %s, option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } else + optionData->mask = fIP(value); + } + + if (buffsize > valSize + 2) { + *dp = opTag; + dp++; + *dp = valSize; + dp++; + memcpy(dp, value, valSize); + dp += valSize; + buffsize -= (valSize + 2); + } else { + sprintf( + logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } else { + sprintf(logBuff, + "Warning: section [%s] option %s, Invalid value, should be one or more IP/4 Bytes", + sectionName, + raw); + logDHCPMess(logBuff, 1); + } + } break; + + case 4: { + MYDWORD j; + + if (valType == 2 && valSize == 4) + j = fUInt(value); + else if (valType >= 4 && valType <= 6) + j = strtol(value, nullptr, 10); + else { + sprintf(logBuff, + "Warning: section [%s] option %s, value should be integer between 0 & %u or 4 bytes, " + "option ignored", + sectionName, + name, + UINT_MAX); + logDHCPMess(logBuff, 1); + continue; + } + + if (opTag == DHCP_OPTION_IPADDRLEASE) { + if (j == 0) + j = UINT_MAX; + + if (!strcasecmp(serviceName, "DUALServer")) { + if (!strcasecmp(sectionName, GLOBALOPTIONS)) { + sprintf(logBuff, + "Warning: section [%s] option %s not allowed in this section, please set it in " + "[TIMINGS] section", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } else if (j < cfig.lease) { + sprintf( + logBuff, + "Warning: section [%s] option %s value should be more then %u (Default Lease), ignored", + sectionName, + name, + cfig.lease); + logDHCPMess(logBuff, 1); + continue; + } + } else if (!strcasecmp(serviceName, "OpenDHCPServer") && !strcasecmp(sectionName, GLOBALOPTIONS)) + cfig.lease = j; + } + + if (buffsize > 6) { + *dp = opTag; + dp++; + *dp = 4; + dp++; + dp += pUInt(dp, j); + buffsize -= 6; + //printf("%s=%u=%u\n",opData[op_index].opName,opData[op_index].opType,htonl(j)); + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + + case 5: { + MYWORD j; + + if (valType == 2 && valSize == 2) + j = fUShort(value); + else if (valType == 5 || valType == 6) + j = strtol(value, nullptr, 10); + else { + sprintf( + logBuff, + "Warning: section [%s] option %s, value should be between 0 & %u or 2 bytes, option ignored", + sectionName, + name, + USHRT_MAX); + logDHCPMess(logBuff, 1); + continue; + } + + if (buffsize > 4) { + *dp = opTag; + dp++; + *dp = 2; + dp++; + dp += pUShort(dp, j); + buffsize -= 4; + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + + case 6: { + MYBYTE j; + + if (valType == 2 && valSize == 1) + j = *value; + else if (valType == 6) + j = strtol(value, nullptr, 10); + else { + sprintf(logBuff, + "Warning: section [%s] option %s, value should be between 0 & %u or single byte, option " + "ignored", + sectionName, + name, + UCHAR_MAX); + logDHCPMess(logBuff, 1); + continue; + } + + if (buffsize > 3) { + *dp = opTag; + dp++; + *dp = 1; + dp++; + *dp = j; + dp++; + buffsize -= 3; + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + + case 7: { + MYBYTE j; + + if (valType == 2 && valSize == 1 && *value < 2) + j = *value; + else if (valType == 1 + && (!strcasecmp(value, "yes") || !strcasecmp(value, "on") || !strcasecmp(value, "true"))) + j = 1; + else if (valType == 1 + && (!strcasecmp(value, "no") || !strcasecmp(value, "off") || !strcasecmp(value, "false"))) + j = 0; + else if (valType == 6 && strtol(value, nullptr, 10) < 2) + j = strtol(value, nullptr, 10); + else { + sprintf(logBuff, + "Warning: section [%s] option %s, value should be yes/on/true/1 or no/off/false/0, option " + "ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } + + if (buffsize > 3) { + *dp = opTag; + dp++; + *dp = 1; + dp++; + *dp = j; + dp++; + buffsize -= 3; + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + + default: { + if (valType == 6) { + valType = 2; + valSize = 1; + *value = (char)strtol(value, nullptr, 10); + } + + if (opType == 2 && valType != 2) { + sprintf(logBuff, + "Warning: section [%s] option %s, value should be comma separated bytes or hex string, " + "option ignored", + sectionName, + raw); + logDHCPMess(logBuff, 1); + continue; + } else if (buffsize > valSize + 2) { + *dp = opTag; + dp++; + *dp = valSize; + dp++; + memcpy(dp, value, valSize); + dp += valSize; + buffsize -= (valSize + 2); + } else { + sprintf(logBuff, "Warning: section [%s] option %s, no more space for options", sectionName, raw); + logDHCPMess(logBuff, 1); + } + } break; + } + + //printf("%s Option=%u opType=%u valType=%u valSize=%u\n", raw, opTag, opType, valType, valSize); + //printf("%s %s\n", name, hex2String(tempbuff, ddp, valSize+2, ':')); + } + + //printf("%s=%s\n", sectionName, optionData->vendClass); + + *dp = DHCP_OPTION_END; + dp++; + optionData->optionSize = (dp - optionData->options); + //printf("section=%s buffersize = %u option size=%u\n", sectionName, buffsize, optionData->optionSize); +} + +void lockOptions(FILE *f) { + char raw[512]; + char name[512]; + char value[512]; + + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (!name[0] || !value[0]) + continue; + + int op_index; + MYBYTE n = sizeof(opData) / sizeof(data4); + + for (op_index = 0; op_index < n; op_index++) + if (!strcasecmp(name, opData[op_index].opName) + || (opData[op_index].opTag && strtol(name, nullptr, 10) == opData[op_index].opTag)) + break; + + if (op_index >= n) + continue; + + if (opData[op_index].opType == 3) { + if (myTokenize(value, value, "/,.", true)) { + char *ptr = value; + char hoption[256]; + MYBYTE valueSize = 0; + + for (; *ptr; ptr = myGetToken(ptr, 1)) { + if (isInt(ptr) && strtol(ptr, nullptr, 10) <= UCHAR_MAX) { + hoption[valueSize] = (char)strtol(ptr, nullptr, 10); + valueSize++; + } else + break; + } + + if (*ptr) + continue; + + if (valueSize % 4) + continue; + + for (MYBYTE i = 0; i < valueSize; i += 4) { + MYDWORD ip = *((MYDWORD *)&(hoption[i])); + + if (ip != INADDR_ANY && ip != INADDR_NONE) + lockIP(ip); + } + } + } + } +} + +void addDHCPRange(char *dp) { + char logBuff[256]; + MYDWORD rs = 0; + MYDWORD re = 0; + char name[512]; + char value[512]; + mySplit(name, value, dp, '-'); + + if (isIP(name) && isIP(value)) { + rs = htonl(inet_addr(name)); + re = htonl(inet_addr(value)); + + if (rs && re && rs <= re) { + data13 *range; + MYBYTE m = 0; + + for (; m < MAX_DHCP_RANGES && cfig.dhcpRanges[m].rangeStart; m++) { + range = &cfig.dhcpRanges[m]; + + if ((rs >= range->rangeStart && rs <= range->rangeEnd) + || (re >= range->rangeStart && re <= range->rangeEnd) + || (range->rangeStart >= rs && range->rangeStart <= re) + || (range->rangeEnd >= rs && range->rangeEnd <= re)) { + sprintf(logBuff, "Warning: DHCP Range %s overlaps with another range, ignored", dp); + logDHCPMess(logBuff, 1); + return; + } + } + + if (m < MAX_DHCP_RANGES) { + cfig.dhcpSize += (re - rs + 1); + range = &cfig.dhcpRanges[m]; + range->rangeStart = rs; + range->rangeEnd = re; + range->expiry = (time_t *)calloc((re - rs + 1), sizeof(time_t)); + memset(range->expiry, 0, (re - rs + 1) * sizeof(time_t)); + range->dhcpEntry = (data7 **)calloc((re - rs + 1), sizeof(struct data7 *)); + memset(range->dhcpEntry, 0, (re - rs + 1) * sizeof(struct data7 *)); + + if (!range->expiry || !range->dhcpEntry) { + if (range->expiry) + free(range->expiry); + + if (range->dhcpEntry) + free(range->dhcpEntry); + + sprintf(logBuff, "DHCP Ranges Load, Memory Allocation Error"); + logDHCPMess(logBuff, 1); + return; + } + } + } else { + sprintf(logBuff, "Section [%s] Invalid DHCP range %s in ini file, ignored", RANGESET, dp); + logDHCPMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [%s] Invalid DHCP range %s in ini file, ignored", RANGESET, dp); + logDHCPMess(logBuff, 1); + } +} + +void addVendClass(MYBYTE rangeSetInd, char *vendClass, MYBYTE vendClassSize) { + char logBuff[256]; + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + + MYBYTE i = 0; + + for (; i <= MAX_RANGE_FILTERS && rangeSet->vendClassSize[i]; i++) + ; + + if (i >= MAX_RANGE_FILTERS || !vendClassSize) + return; + + rangeSet->vendClass[i] = (MYBYTE *)calloc(vendClassSize, 1); + + if (!rangeSet->vendClass[i]) { + sprintf(logBuff, "Vendor Class Load, Memory Allocation Error"); + logDHCPMess(logBuff, 1); + } else { + cfig.hasFilter = true; + rangeSet->vendClassSize[i] = vendClassSize; + memcpy(rangeSet->vendClass[i], vendClass, vendClassSize); + //printf("Loaded Vendor Class %s Size=%i rangeSetInd=%i Ind=%i\n", rangeSet->vendClass[i], rangeSet->vendClassSize[i], rangeSetInd, i); + //printf("Loaded Vendor Class %s Size=%i rangeSetInd=%i Ind=%i\n", hex2String(tempbuff, rangeSet->vendClass[i], rangeSet->vendClassSize[i], ':'), rangeSet->vendClassSize[i], rangeSetInd, i); + } +} + +void addUserClass(MYBYTE rangeSetInd, char *userClass, MYBYTE userClassSize) { + char logBuff[256]; + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + + MYBYTE i = 0; + + for (; i <= MAX_RANGE_FILTERS && rangeSet->userClassSize[i]; i++) + ; + + if (i >= MAX_RANGE_FILTERS || !userClassSize) + return; + + rangeSet->userClass[i] = (MYBYTE *)calloc(userClassSize, 1); + + if (!rangeSet->userClass[i]) { + sprintf(logBuff, "Vendor Class Load, Memory Allocation Error"); + logDHCPMess(logBuff, 1); + } else { + cfig.hasFilter = true; + rangeSet->userClassSize[i] = userClassSize; + memcpy(rangeSet->userClass[i], userClass, userClassSize); + //printf("Loaded User Class %s Size=%i rangeSetInd=%i Ind=%i\n", hex2String(tempbuff, rangeSet->userClass[i], rangeSet->userClassSize[i], ':'), rangeSet->vendClassSize[i], rangeSetInd, i); + } +} + +void addMacRange(MYBYTE rangeSetInd, char *macRange) { + char logBuff[256]; + + if (macRange[0]) { + data14 *rangeSet = &cfig.rangeSet[rangeSetInd]; + + MYBYTE i = 0; + + for (; i <= MAX_RANGE_FILTERS && rangeSet->macSize[i]; i++) + ; + + if (i >= MAX_RANGE_FILTERS) + return; + + char name[256]; + char value[256]; + + mySplit(name, value, macRange, '-'); + + //printf("%s=%s\n", name, value); + + if (!name[0] || !value[0]) { + sprintf(logBuff, "Section [%s], invalid Filter_Mac_Range %s, ignored", RANGESET, macRange); + logDHCPMess(logBuff, 1); + } else { + MYBYTE macSize1 = 16; + MYBYTE macSize2 = 16; + auto *macStart = (MYBYTE *)calloc(1, macSize1); + auto *macEnd = (MYBYTE *)calloc(1, macSize2); + + if (!macStart || !macEnd) { + sprintf(logBuff, "DHCP Range Load, Memory Allocation Error"); + logDHCPMess(logBuff, 1); + } else if (getHexValue(macStart, name, &macSize1) || getHexValue(macEnd, value, &macSize2)) { + sprintf(logBuff, "Section [%s], Invalid character in Filter_Mac_Range %s", RANGESET, macRange); + logDHCPMess(logBuff, 1); + free(macStart); + free(macEnd); + } else if (memcmp(macStart, macEnd, 16) > 0) { + sprintf(logBuff, + "Section [%s], Invalid Filter_Mac_Range %s, (higher bound specified on left), ignored", + RANGESET, + macRange); + logDHCPMess(logBuff, 1); + free(macStart); + free(macEnd); + } else if (macSize1 != macSize2) { + sprintf(logBuff, + "Section [%s], Invalid Filter_Mac_Range %s, (start/end size mismatched), ignored", + RANGESET, + macRange); + logDHCPMess(logBuff, 1); + free(macStart); + free(macEnd); + } else { + cfig.hasFilter = true; + rangeSet->macSize[i] = macSize1; + rangeSet->macStart[i] = macStart; + rangeSet->macEnd[i] = macEnd; + //printf("Mac Loaded, Size=%i Start=%s rangeSetInd=%i Ind=%i\n", rangeSet->macSize[i], hex2String(tempbuff, rangeSet->macStart[i], rangeSet->macSize[i]), rangeSetInd, i); + } + } + } +} + +void loadDHCP() { + char ipbuff[32]; + char logBuff[512]; + data7 *dhcpEntry = nullptr; + data8 dhcpData{}; + char mapname[64]; + FILE *f = nullptr; + FILE *ff = nullptr; + + if ((f = openSection(GLOBALOPTIONS, 1))) { + data20 optionData{}; + loadOptions(f, GLOBALOPTIONS, &optionData); + cfig.options = (MYBYTE *)calloc(1, optionData.optionSize); + memcpy(cfig.options, optionData.options, optionData.optionSize); + cfig.mask = optionData.mask; + } + + if (!cfig.mask) + cfig.mask = inet_addr("255.255.255.0"); + + for (MYBYTE i = 1; i <= MAX_RANGE_SETS; i++) { + if ((f = openSection(RANGESET, i))) { + MYBYTE m = cfig.rangeCount; + data20 optionData{}; + optionData.rangeSetInd = i - 1; + loadOptions(f, RANGESET, &optionData); + MYBYTE *options = nullptr; + cfig.rangeSet[optionData.rangeSetInd].active = true; + + if (optionData.optionSize > 3) { + options = (MYBYTE *)calloc(1, optionData.optionSize); + memcpy(options, optionData.options, optionData.optionSize); + } + + for (; m < MAX_DHCP_RANGES && cfig.dhcpRanges[m].rangeStart; m++) { + cfig.dhcpRanges[m].rangeSetInd = optionData.rangeSetInd; + cfig.dhcpRanges[m].options = options; + cfig.dhcpRanges[m].mask = optionData.mask; + } + cfig.rangeCount = m; + } else + break; + } + + //printf("%s\n", IP2String(ipbuff, cfig.mask)); + + for (unsigned char rangeInd = 0; rangeInd < cfig.rangeCount; rangeInd++) { + if (!cfig.dhcpRanges[rangeInd].mask) + cfig.dhcpRanges[rangeInd].mask = cfig.mask; + + for (MYDWORD iip = cfig.dhcpRanges[rangeInd].rangeStart; iip <= cfig.dhcpRanges[rangeInd].rangeEnd; iip++) { + MYDWORD ip = htonl(iip); + + if ((cfig.dhcpRanges[rangeInd].mask | (~ip)) == UINT_MAX + || (cfig.dhcpRanges[rangeInd].mask | ip) == UINT_MAX) + cfig.dhcpRanges[rangeInd].expiry[iip - cfig.dhcpRanges[rangeInd].rangeStart] = MY_MAX_TIME; + } + } + + if ((f = openSection(GLOBALOPTIONS, 1))) + lockOptions(f); + + for (MYBYTE i = 1; i <= MAX_RANGE_SETS; i++) { + if ((f = openSection(RANGESET, i))) + lockOptions(f); + else + break; + } + + ff = fopen(iniFile, "rt"); + + if (ff) { + char sectionName[512]; + + while (fgets(sectionName, 510, ff)) { + if (*sectionName == '[') { + char *secend = strchr(sectionName, ']'); + + if (secend) { + *secend = 0; + sectionName[0] = NBSP; + myTrim(sectionName, sectionName); + } else + continue; + } else + continue; + + if (!strchr(sectionName, ':')) + continue; + + //printf("%s\n", sectionName); + + MYBYTE hexValue[UCHAR_MAX]; + MYBYTE hexValueSize = sizeof(hexValue); + data20 optionData{}; + + if (strlen(sectionName) <= 48 && !getHexValue(hexValue, sectionName, &hexValueSize)) { + if (hexValueSize <= 16) { + dhcpEntry = findDHCPEntry(hex2String(mapname, hexValue, hexValueSize)); + + if (!dhcpEntry) { + if ((f = openSection(sectionName, 1))) + loadOptions(f, sectionName, &optionData); + if ((f = openSection(sectionName, 1))) + lockOptions(f); + + auto p = dhcpCache.begin(); + + for (; p != dhcpCache.end(); p++) { + if (p->second && p->second->ip && p->second->ip == optionData.ip) + break; + } + + if (p == dhcpCache.end()) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_DHCP_ENTRY; + g_lump.mapname = mapname; + g_lump.optionSize = optionData.optionSize; + g_lump.options = optionData.options; + dhcpEntry = createCache(&g_lump); + + if (!dhcpEntry) + return; + + char idx = getRangeInd(optionData.ip); + + dhcpEntry->ip = optionData.ip; + dhcpEntry->rangeInd = idx < 0 ? -1 : (int)idx; + dhcpEntry->fixed = 1; + dhcpEntry->expiry = 0; + dhcpCache[dhcpEntry->mapname] = dhcpEntry; + setLeaseExpiry(dhcpEntry); + lockIP(optionData.ip); + //printf("%s=%s=%s size=%u %u\n", mapname, dhcpEntry->mapname, IP2String(ipbuff, optionData.ip), optionData.optionSize, dhcpEntry->options); + } else { + sprintf(logBuff, + "Static DHCP Host [%s] Duplicate IP Address %s, Entry ignored", + sectionName, + IP2String(ipbuff, optionData.ip)); + logDHCPMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Duplicate Static DHCP Host [%s] ignored", sectionName); + logDHCPMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Invalid Static DHCP Host MAC Addr size, ignored"); + logDHCPMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Invalid Static DHCP Host MAC Addr [%s] ignored", sectionName); + logDHCPMess(logBuff, 1); + } + + if (!optionData.ip) { + sprintf(logBuff, "Warning: No IP Address for DHCP Static Host %s specified", sectionName); + logDHCPMess(logBuff, 1); + } + } + + fclose(ff); + } + + f = fopen(leaFile, "rb"); + + if (f) { + while (fread(&dhcpData, sizeof(data8), 1, f)) { + char rangeInd = -1; + int ind = -1; + //sprintf(logBuff, "Loading %s=%s", dhcpData.hostname, IP2String(ipbuff, dhcpData.ip)); + //logDHCPMess(logBuff, 1); + + if (dhcpData.expiry > (t - 31 * 24 * 3600) && dhcpData.bp_hlen <= 16 + && !findServer(network.allServers, MAX_SERVERS, dhcpData.ip)) { + hex2String(mapname, dhcpData.bp_chaddr, dhcpData.bp_hlen); + + auto p = dhcpCache.begin(); + + for (; p != dhcpCache.end(); p++) { + dhcpEntry = p->second; + + if (!dhcpEntry || (!strcasecmp(mapname, dhcpEntry->mapname) || dhcpEntry->ip == dhcpData.ip)) + break; + } + + if ((p != dhcpCache.end()) && (strcasecmp(mapname, dhcpEntry->mapname) != 0 || dhcpEntry->ip != dhcpData.ip)) + continue; + + dhcpEntry = findDHCPEntry(mapname); + rangeInd = getRangeInd(dhcpData.ip); + + if (!dhcpEntry && rangeInd >= 0) { + memset(&g_lump, 0, sizeof(data71)); + g_lump.cacheType = CTYPE_DHCP_ENTRY; + g_lump.mapname = mapname; + dhcpEntry = createCache(&g_lump); + } + + if (dhcpEntry) { + dhcpCache[dhcpEntry->mapname] = dhcpEntry; + dhcpEntry->subnetFlg = dhcpData.subnetFlg; + dhcpEntry->ip = dhcpData.ip; + dhcpEntry->rangeInd = rangeInd < 0 ? -1 : (int)rangeInd; + dhcpEntry->expiry = dhcpData.expiry; + dhcpEntry->local = dhcpData.local; + dhcpEntry->display = true; + strcpy(dhcpEntry->hostname, dhcpData.hostname); + setLeaseExpiry(dhcpEntry); + + if (dnsService && dhcpData.hostname[0] && cfig.replication != 2 && dhcpData.expiry > t) { + if (isLocal(dhcpEntry->ip)) + add2Cache( + dhcpData.hostname, dhcpEntry->ip, dhcpData.expiry, CTYPE_LOCAL_A, CTYPE_LOCAL_PTR_AUTH); + else + add2Cache(dhcpData.hostname, + dhcpEntry->ip, + dhcpData.expiry, + CTYPE_LOCAL_A, + CTYPE_LOCAL_PTR_NAUTH); + } + //printf("Loaded %s=%s\n", dhcpData.hostname, IP2String(ipbuff, dhcpData.ip)); + } + } + } + + fclose(f); + } + + f = fopen(leaFile, "wb"); + fclose(f); + f = fopen(leaFile, "rb+"); + + if (f) { + auto p = dhcpCache.begin(); + + for (; p != dhcpCache.end(); p++) { + if ((dhcpEntry = p->second) && dhcpEntry->expiry > (t - 31 * 24 * 3600)) { + memset(&dhcpData, 0, sizeof(data8)); + MYBYTE bp_hlen = 16; + getHexValue(dhcpData.bp_chaddr, dhcpEntry->mapname, &bp_hlen); + dhcpData.bp_hlen = bp_hlen; + dhcpData.ip = dhcpEntry->ip; + dhcpData.subnetFlg = dhcpEntry->subnetFlg; + dhcpData.expiry = dhcpEntry->expiry; + dhcpData.local = dhcpEntry->local; + strcpy(dhcpData.hostname, dhcpEntry->hostname); + cfig.dhcpInd += 1; + dhcpEntry->dhcpInd = cfig.dhcpInd; + dhcpData.dhcpInd = dhcpEntry->dhcpInd; + + if (fseek(f, (long)((dhcpData.dhcpInd - 1) * sizeof(data8)), SEEK_SET) >= 0) + fwrite(&dhcpData, sizeof(data8), 1, f); + } + } + + fclose(f); + } +} + +#if 0 +bool getSection(const char *sectionName, char *buffer, MYBYTE serial, char *fileName) { + //printf("%s=%s\n",fileName,sectionName); + char section[128]; + sprintf(section, "[%s]", sectionName); + myUpper(section); + FILE *f = fopen(fileName, "rt"); + char buff[512]; + MYBYTE found = 0; + + if (f) { + while (fgets(buff, 511, f)) { + myUpper(buff); + myTrim(buff, buff); + + if (strstr(buff, section) == buff) { + found++; + if (found == serial) { + //printf("%s=%s\n",fileName,sectionName); + while (fgets(buff, 511, f)) { + myTrim(buff, buff); + + if (strstr(buff, "[") == buff) + break; + + if ((*buff) >= '0' && (*buff) <= '9' || (*buff) >= 'A' && (*buff) <= 'Z' + || (*buff) >= 'a' && (*buff) <= 'z' || ((*buff) && strchr("/\\?*", (*buff)))) { + buffer += sprintf(buffer, "%s", buff); + buffer++; + } + } + break; + } + } + } + fclose(f); + } + + *buffer = 0; + *(buffer + 1) = 0; + return (found == serial); +} +#endif +FILE *openSection(const char *sectionName, MYBYTE serial) { + char logBuff[256]; + char tempbuff[512]; + char section[128]; + sprintf(section, "[%s]", sectionName); + myUpper(section); + FILE *f = nullptr; + f = fopen(iniFile, "rt"); + + if (f) { + //printf("opened %s=%d\n", tempbuff, f); + char buff[512]; + MYBYTE found = 0; + + while (fgets(buff, 511, f)) { + myUpper(buff); + myTrim(buff, buff); + + if (strstr(buff, section) == buff) { + found++; + + if (found == serial) { + MYDWORD fpos = ftell(f); + + if (fgets(buff, 511, f)) { + myTrim(buff, buff); + + if (buff[0] == '@') { + fclose(f); + f = nullptr; + + buff[0] = NBSP; + myTrim(buff, buff); + + if (strchr(buff, '\\') || strchr(buff, '/')) + strcpy(tempbuff, buff); + else + sprintf(tempbuff, "%s%s", filePATH, buff); + + f = fopen(tempbuff, "rt"); + + if (f) + return f; + else { + sprintf(logBuff, "Error: Section [%s], file %s not found", sectionName, tempbuff); + logMess(logBuff, 1); + return nullptr; + } + } else { + fseek(f, fpos, SEEK_SET); + return f; + } + } + } + } + } + fclose(f); + } + return nullptr; +} + +char *readSection(char *buff, FILE *f) { + while (fgets(buff, 511, f)) { + myTrim(buff, buff); + + if (*buff == '[') + break; + + if ((*buff) >= '0' && (*buff) <= '9' || (*buff) >= 'A' && (*buff) <= 'Z' || (*buff) >= 'a' && (*buff) <= 'z' + || ((*buff) && strchr("/\\?*", (*buff)))) + return buff; + } + + fclose(f); + return nullptr; +} + +char *myGetToken(char *buff, MYBYTE index) { + while (*buff) { + if (index) + index--; + else + break; + + buff += strlen(buff) + 1; + } + + return buff; +} + +MYWORD myTokenize(char *target, char *source, const char *sep, bool whiteSep) { + bool found = true; + char *dp = target; + MYWORD kount = 0; + + while (*source) { + if (sep && sep[0] && strchr(sep, (*source))) { + found = true; + source++; + continue; + } else if (whiteSep && (*source) <= NBSP) { + found = true; + source++; + continue; + } + + if (found) { + if (target != dp) { + *dp = 0; + dp++; + } + kount++; + } + + found = false; + *dp = *source; + dp++; + source++; + } + + *dp = 0; + dp++; + *dp = 0; + + //printf("%s\n", target); + + return kount; +} + +char *myTrim(char *target, char *source) { + while ((*source) && (*source) <= NBSP) + source++; + + int i = 0; + + for (; i < 511 && source[i]; i++) + target[i] = source[i]; + + target[i] = source[i]; + i--; + + for (; i >= 0 && target[i] <= NBSP; i--) + target[i] = 0; + + return target; +} + +void mySplit(char *name, char *value, const char *source, char splitChar) { + int i = 0; + int j = 0; + int k = 0; + + for (; source[i] && j <= 510 && source[i] != splitChar; i++, j++) { + name[j] = source[i]; + } + + if (source[i]) { + i++; + for (; k <= 510 && source[i]; i++, k++) { + value[k] = source[i]; + } + } + + name[j] = 0; + value[k] = 0; + + myTrim(name, name); + myTrim(value, value); + //printf("%s %s\n", name, value); +} + +char *strquery(data5 *req) { + strcpy(req->extbuff, req->query); + + switch (req->dnsType) { + case 1: + strcat(req->extbuff, " A"); + break; + case 2: + strcat(req->extbuff, " NS"); + break; + case 3: + strcat(req->extbuff, " MD"); + break; + case 4: + strcat(req->extbuff, " MF"); + break; + case 5: + strcat(req->extbuff, " CNAME"); + break; + case 6: + strcat(req->extbuff, " SOA"); + break; + case 7: + strcat(req->extbuff, " MB"); + break; + case 8: + strcat(req->extbuff, " MG"); + break; + case 9: + strcat(req->extbuff, " MR"); + break; + case 10: + strcat(req->extbuff, " nullptr"); + break; + case 11: + strcat(req->extbuff, " WKS"); + break; + case 12: + strcat(req->extbuff, " PTR"); + break; + case 13: + strcat(req->extbuff, " HINFO"); + break; + case 14: + strcat(req->extbuff, " MINFO"); + break; + case 15: + strcat(req->extbuff, " MX"); + break; + case 16: + strcat(req->extbuff, " TXT"); + break; + case 28: + strcat(req->extbuff, " AAAA"); + break; + case 251: + strcat(req->extbuff, " IXFR"); + break; + case 252: + strcat(req->extbuff, " AXFR"); + break; + case 253: + strcat(req->extbuff, " MAILB"); + break; + case 254: + strcat(req->extbuff, " MAILA"); + break; + case 255: + strcat(req->extbuff, " ANY"); + break; + } + return req->extbuff; +} + +#if 0 +MYDWORD getClassNetwork(MYDWORD ip) { + data15 data{}; + data.ip = ip; + data.octate[3] = 0; + + if (data.octate[0] < 192) + data.octate[2] = 0; + + if (data.octate[0] < 128) + data.octate[1] = 0; + + return data.ip; +} +#endif + +/* +char *IP2Auth(MYDWORD ip) +{ +data15 data; +data.ip = ip; + +if (data.octate[0] >= 192) +sprintf(tempbuff, "%u.%u.%u", data.octate[2], data.octate[1], data.octate[0]); +else if (data.octate[0] >= 128) +sprintf(tempbuff, "%u.%u", data.octate[1], data.octate[0]); +else +sprintf(tempbuff, "%u", data.octate[0]); + +strcat(tempbuff, arpa); +return tempbuff; +} +*/ + +char *IP2String(char *target, MYDWORD ip, MYBYTE dnsType) { + char *dp = target; + (*dp) = (char)dnsType; + dp++; + data15 inaddr{}; + inaddr.ip = ip; + sprintf(dp, "%u.%u.%u.%u", inaddr.octate[0], inaddr.octate[1], inaddr.octate[2], inaddr.octate[3]); + //MYBYTE *octate = (MYBYTE*)&ip; + //sprintf(target, "%u.%u.%u.%u", octate[0], octate[1], octate[2], octate[3]); + return target; +} + +char *IP2String(char *target, MYDWORD ip) { + data15 inaddr{}; + inaddr.ip = ip; + sprintf(target, "%u.%u.%u.%u", inaddr.octate[0], inaddr.octate[1], inaddr.octate[2], inaddr.octate[3]); + //MYBYTE *octate = (MYBYTE*)&ip; + //sprintf(target, "%u.%u.%u.%u", octate[0], octate[1], octate[2], octate[3]); + return target; +} + +MYBYTE addServer(MYDWORD *array, MYBYTE maxServers, MYDWORD ip) { + if (ip) { + for (MYBYTE i = 0; i < maxServers; i++) { + if (array[i] == ip) + return i; + else if (!array[i]) { + array[i] = ip; + return i; + } + } + } + return maxServers; +} + +MYDWORD *findServer(MYDWORD *array, MYBYTE maxServers, MYDWORD ip) { + if (ip) { + for (MYBYTE i = 0; i < maxServers && array[i]; i++) { + if (array[i] == ip) + return &(array[i]); + } + } + return nullptr; +} + +bool isInt(char *str) { + if (!str || !(*str)) + return false; + + for (; *str; str++) + if (*str < '0' || *str > '9') + return false; + + return true; +} + +bool isIP(char *str) { + if (!str || !(*str)) + return false; + + MYDWORD ip = inet_addr(str); + + if (ip == INADDR_NONE || ip == INADDR_ANY) + return false; + + int j = 0; + + for (; *str; str++) { + if (*str == '.' && *(str + 1) != '.') + j++; + else if (*str < '0' || *str > '9') + return false; + } + + if (j == 3) + return true; + else + return false; +} + +/* +char *toBase64(MYBYTE *source, MYBYTE length) +{ + MYBYTE a = 0, b = 0, i = 0; + char *dp = tempbuff; + + for (; length; length--, source++) + { + i += 2; + a = (*source) >> i; + *dp = base64[a + b]; + dp++; + b = (*source) << (8 - i); + b >>= 2; + if (i == 6) + { + *dp = base64[b]; + dp++; + i = b = 0; + } + } + if (i) + { + *dp = base64[b]; + dp++; + } + *dp = 0; + //printf("%s\n",tempbuff); + return tempbuff; +} + +MYBYTE getBaseValue(MYBYTE a) +{ + if (a >= 'A' && a <= 'Z') + a -= 'A'; + else if (a >= 'a' && a <= 'z') + a = a - 'a' + 26; + else if (a >= '0' && a <= '9') + a = a - '0' + 52; + else if (a == '+') + a = 62; + else if (a == '/') + a = 63; + else + a = UCHAR_MAX; + + return a; +} + +MYBYTE fromBase64(MYBYTE *target, char *source) +{ + //printf("SOURCE=%s\n", source); + MYBYTE b = 0; + MYBYTE shift = 4; + MYBYTE bp_hlen = (3 * strlen(source))/4; + *target = 0; + + if (*source) + { + b = getBaseValue(*source); + *target = b << 2; + source++; + + while (*source) + { + b = getBaseValue(*source); + (*target) += (b >> (8 - shift)); + target++; + (*target) = (b << shift); + shift += 2; + + if (shift > 8) + { + source++; + + if (*source) + { + b = getBaseValue(*source); + *target = b << 2; + shift = 4; + } + else + break; + } + + source++; + } + } + //printf("SIZE=%u\n", bp_hlen); + return bp_hlen; +} + +char *toUUE(char *tempbuff, MYBYTE *source, MYBYTE length) +{ + MYBYTE a = 0, b = 0, i = 0; + char *dp = tempbuff; + + for (; length; length--, source++) + { + i += 2; + a = (*source) >> i; + *dp = a + b + NBSP; + dp++; + b = (*source) << (8 - i); + b >>= 2; + if (i == 6) + { + *dp = b + NBSP; + dp++; + i = b = 0; + } + } + if (i) + { + *dp = b + NBSP; + dp++; + } + *dp = 0; + //printf("%s\n",tempbuff); + return tempbuff; +} + +MYBYTE fromUUE(MYBYTE *target, char *source) +{ + //printf("SOURCE=%s\n", source); + MYBYTE b = 0; + MYBYTE shift = 4; + MYBYTE bp_hlen = (3 * strlen(source))/4; + *target = 0; + + if (*source) + { + b = *source - NBSP; + *target = b << 2; + source++; + + while (*source) + { + b = *source - NBSP; + (*target) += (b >> (8 - shift)); + target++; + (*target) = (b << shift); + shift += 2; + + if (shift > 8) + { + source++; + + if (*source) + { + b = *source - NBSP; + *target = b << 2; + shift = 4; + } + else + break; + } + + source++; + } + } + //printf("SIZE=%u\n", bp_hlen); + return bp_hlen; +} +*/ +char *hex2String(char *target, const MYBYTE *hex, MYBYTE bytes) { + char *dp = target; + + if (bytes) + dp += sprintf(target, "%02x", *hex); + else + *target = 0; + + for (MYBYTE i = 1; i < bytes; i++) + dp += sprintf(dp, ":%02x", *(hex + i)); + + return target; +} + +char *genHostName(char *target, const MYBYTE *hex, MYBYTE bytes) { + char *dp = target; + + if (bytes) + dp += sprintf(target, "Host%02x", *hex); + else + *target = 0; + + for (MYBYTE i = 1; i < bytes; i++) + dp += sprintf(dp, "%02x", *(hex + i)); + + return target; +} + +/* +char *IP62String(char *target, MYBYTE *source) +{ + MYWORD *dw = (MYWORD*)source; + char *dp = target; + MYBYTE markbyte; + + for (markbyte = 4; markbyte > 0 && !dw[markbyte - 1]; markbyte--); + + for (MYBYTE i = 0; i < markbyte; i++) + dp += sprintf(dp, "%x:", ntohs(dw[i])); + + for (markbyte = 4; markbyte < 8 && !dw[markbyte]; markbyte++); + + for (MYBYTE i = markbyte; i < 8; i++) + dp += sprintf(dp, ":%x", htons(dw[i])); + + return target; +} +*/ + +char *IP62String(char *target, MYBYTE *source) { + char *dp = target; + bool zerostarted = false; + bool zeroended = false; + + for (MYBYTE i = 0; i < 16; i += 2, source += 2) { + if (source[0]) { + if (zerostarted) + zeroended = true; + + if (zerostarted && zeroended) { + dp += sprintf(dp, "::"); + zerostarted = false; + } else if (dp != target) + dp += sprintf(dp, ":"); + + dp += sprintf(dp, "%x", source[0]); + dp += sprintf(dp, "%02x", source[1]); + } else if (source[1]) { + if (zerostarted) + zeroended = true; + + if (zerostarted && zeroended) { + dp += sprintf(dp, "::"); + zerostarted = false; + } else if (dp != target) + dp += sprintf(dp, ":"); + + dp += sprintf(dp, "%0x", source[1]); + } else if (!zeroended) + zerostarted = true; + } + + return target; +} + +char *getHexValue(MYBYTE *target, char *source, MYBYTE *size) { + if (*size) + memset(target, 0, (*size)); + + for ((*size) = 0; (*source) && (*size) < UCHAR_MAX; (*size)++, target++) { + if ((*source) >= '0' && (*source) <= '9') { + (*target) = (*source) - '0'; + } else if ((*source) >= 'a' && (*source) <= 'f') { + (*target) = (*source) - 'a' + 10; + } else if ((*source) >= 'A' && (*source) <= 'F') { + (*target) = (*source) - 'A' + 10; + } else { + return source; + } + + source++; + + if ((*source) >= '0' && (*source) <= '9') { + (*target) *= 16; + (*target) += (*source) - '0'; + } else if ((*source) >= 'a' && (*source) <= 'f') { + (*target) *= 16; + (*target) += (*source) - 'a' + 10; + } else if ((*source) >= 'A' && (*source) <= 'F') { + (*target) *= 16; + (*target) += (*source) - 'A' + 10; + } else if ((*source) == ':' || (*source) == '-') { + source++; + continue; + } else if (*source) { + return source; + } else { + continue; + } + + source++; + + if ((*source) == ':' || (*source) == '-') { + source++; + } else if (*source) + return source; + } + + if (*source) + return source; + + //printf("macfucked in=%s\n", tSource); + //printf("macfucked out=%s\n", hex2String(tempbuff, tTarget, *size)); + return nullptr; +} + +char *myUpper(char *string) { + char diff = 'a' - 'A'; + MYWORD len = strlen(string); + for (int i = 0; i < len; i++) + if (string[i] >= 'a' && string[i] <= 'z') + string[i] = (char)(string[i] - diff); + return string; +} + +char *myLower(char *string) { + char diff = 'a' - 'A'; + MYWORD len = strlen(string); + for (int i = 0; i < len; i++) + if (string[i] >= 'A' && string[i] <= 'Z') + string[i] = (char)(string[i] + diff); + return string; +} + +bool wildcmp(char *string, char *wild) { + // Written by Jack Handy - jakkhandy@hotmail.com + // slightly modified + char *cp = nullptr; + char *mp = nullptr; + + while ((*string) && (*wild != '*')) { + if ((*wild != *string) && (*wild != '?')) { + return false; + } + wild++; + string++; + } + + while (*string) { + if (*wild == '*') { + if (!*++wild) + return true; + + mp = wild; + cp = string + 1; + } else if ((*wild == *string) || (*wild == '?')) { + wild++; + string++; + } else { + wild = mp; + string = cp++; + } + } + + while (*wild == '*') + wild++; + + return !(*wild); +} + +bool isLocal(MYDWORD ip) { + if (cfig.rangeStart && htonl(ip) >= cfig.rangeStart && htonl(ip) <= cfig.rangeEnd) + return true; + // else if (getRangeInd(ip) >= 0) + // return true; + else + return false; +} + +char *setMapName(char *tempbuff, char *mapname, MYBYTE dnsType) { + char *dp = tempbuff; + (*dp) = (char)dnsType; + dp++; + strcpy(dp, mapname); + myLower(dp); + return tempbuff; +} + +MYBYTE makeLocal(char *mapname) { + if (!strcasecmp(mapname, cfig.zone)) { + mapname[0] = 0; + return QTYPE_A_ZONE; + } else if (!strcasecmp(mapname, cfig.authority)) { + //char *dp = strstr(mapname, arpa); + //(*dp) = 0; + return QTYPE_P_ZONE; + } else if (char *dp = strchr(mapname, '.')) { + if (!strcasecmp(dp + 1, cfig.zone)) { + *dp = 0; + return QTYPE_A_LOCAL; + } else if ((dp = strstr(mapname, arpa))) { + if (strstr(mapname, cfig.authority)) { + *dp = 0; + return QTYPE_P_LOCAL; + } else { + *dp = 0; + return QTYPE_P_EXT; + } + } else if (strstr(mapname, ip6arpa)) + return QTYPE_P_EXT; + else + return QTYPE_A_EXT; + } else + return QTYPE_A_BARE; +} + + +#if 0 +void listCache() { + char ipbuff[32]; + char logBuff[256]; + auto p = dnsCache[currentInd].begin(); + data7 *cache = nullptr; + + while (p != dnsCache[currentInd].end()) { + cache = p->second; + + if (cache->hostname) + sprintf(logBuff, "%s=%s", cache->mapname, cache->hostname); + else + sprintf(logBuff, "%s=%s", cache->mapname, IP2String(ipbuff, cache->ip)); + + logDNSMess(logBuff, 1); + p++; + } +} + +void listDhcpCache() { + char logBuff[256]; + auto p = dhcpCache.begin(); + data7 *cache = nullptr; + + while (p != dhcpCache.end()) { + cache = p->second; + sprintf(logBuff, "%s", cache->mapname); + logDHCPMess(logBuff, 1); + p++; + } +} +#endif + +void checkSize() { + data7 *cache = nullptr; + expiryMap::iterator p; + + //while (p != dnsAge[currentInd].end() && p->first < t && maxDelete > 0) + while (true) { + p = dnsAge[currentInd].begin(); + + if (p == dnsAge[currentInd].end()) + break; + + if (p->first > t) + break; + + cache = p->second; + //debug(cache->mapname); + + dnsAge[currentInd].erase(p); + + if (!cache) + continue; + + if (cache->expiry > t) { + dnsAge[currentInd].insert(pair(cache->expiry, cache)); + //sprintf(logBuff, "Entry %s being advanced", cache->name); + //logMess(logBuff, 1); + } else { + if (cache->cacheType == CTYPE_QUEUE && cache->expiry) { + if (cache->dnsIndex < MAX_SERVERS) { + if (network.currentDNS == cache->dnsIndex) { + if (network.dns[1]) { + network.currentDNS++; + + if (network.currentDNS >= MAX_SERVERS || !network.dns[network.currentDNS]) + network.currentDNS = 0; + } + } + } else if (cache->dnsIndex >= 128 && cache->dnsIndex < 192) { + data10 *dnsRoute = &cfig.dnsRoutes[(cache->dnsIndex - 128) / 2]; + MYBYTE currentDNS = cache->dnsIndex % 2; + + if (dnsRoute->currentDNS == currentDNS && dnsRoute->dns[1]) + dnsRoute->currentDNS = 1 - dnsRoute->currentDNS; + } + } + + if (cfig.replication != 2) { + if (cache->cacheType == CTYPE_LOCAL_A || cache->cacheType == CTYPE_SERVER_A_AUTH) + cfig.serial1 = t; + else if (cache->cacheType == CTYPE_LOCAL_PTR_AUTH || cache->cacheType == CTYPE_SERVER_PTR_AUTH) + cfig.serial2 = t; + } + + //char logBuff[256]; + //sprintf(logBuff, "cache %p Data Type=%u Cache Size=%u, Age Size=%u, Entry %s being deleted", cache, cache->cacheType, dnsCache[currentInd].size(), dnsAge[currentInd].size(), cache->name); + //logMess(logBuff, 1); + delDnsEntry(cache); + //maxDelete--; + } + } + + //sprintf(logBuff, "End Cache size %u=%u",dnsCache[currentInd].size(),dnsAge[currentInd].size()); + //debug(logBuff); +} + +void delDnsEntry(data7 *cache) { + auto r = dnsCache[currentInd].find(cache->mapname); + + for (; r != dnsCache[currentInd].end(); r++) { + if (strcasecmp(r->second->mapname, cache->mapname) != 0) + break; + else if (r->second == cache) { + //char logBuff[256]; + //sprintf(logBuff, "cache %p Data Type=%u CacheSize=%u, AgeSize=%u, Entry %s being deleted", cache, cache->cacheType, dnsCache[currentInd].size(), dnsAge[currentInd].size(), cache->name); + //debug(logBuff); + dnsCache[currentInd].erase(r); + free(cache); + break; + } + } +} + +void calcRangeLimits(MYDWORD ip, MYDWORD mask, MYDWORD *rangeStart, MYDWORD *rangeEnd) { + *rangeStart = htonl(ip & mask) + 1; + *rangeEnd = htonl(ip | (~mask)) - 1; +} + +bool checkMask(MYDWORD mask) { + mask = htonl(mask); + + while (mask) { + if (mask < (mask << 1)) + return false; + + mask <<= 1; + } + return true; +} + +#if 0 +MYDWORD calcMask(MYDWORD rangeStart, MYDWORD rangeEnd) { + data15 ip1 {}, ip2 {}, mask {}; + + ip1.ip = htonl(rangeStart); + ip2.ip = htonl(rangeEnd); + + for (MYBYTE i = 0; i < 4; i++) { + mask.octate[i] = ip1.octate[i] ^ ip2.octate[i]; + + if (i && mask.octate[i - 1] < 255) + mask.octate[i] = 0; + else if (mask.octate[i] == 0) + mask.octate[i] = 255; + else if (mask.octate[i] < 2) + mask.octate[i] = 254; + else if (mask.octate[i] < 4) + mask.octate[i] = 252; + else if (mask.octate[i] < 8) + mask.octate[i] = 248; + else if (mask.octate[i] < 16) + mask.octate[i] = 240; + else if (mask.octate[i] < 32) + mask.octate[i] = 224; + else if (mask.octate[i] < 64) + mask.octate[i] = 192; + else if (mask.octate[i] < 128) + mask.octate[i] = 128; + else + mask.octate[i] = 0; + } + + return mask.ip; +} +#endif + +char *findHost(char *tempbuff, MYDWORD ip) { + IP2String(tempbuff, htonl(ip)); + data7 *cache = findDNSEntry(tempbuff, DNS_TYPE_PTR); + + if (cache) + strcpy(tempbuff, cache->hostname); + else + tempbuff[0] = 0; + + return tempbuff; +} + +data7 *findDNSEntry(char *key, MYBYTE dnsType, MYBYTE cacheType) { + char tempbuff[512]; + auto it = dnsCache[currentInd].find(setMapName(tempbuff, key, dnsType)); + + while (it != dnsCache[currentInd].end() && it->second && !strcasecmp(it->second->mapname, tempbuff)) { + if (it->second->cacheType == cacheType) + return it->second; + else + it++; + } + + return nullptr; +} + +data7 *findDNSEntry(char *key, MYBYTE dnsType) { + char tempbuff[512]; + //printf("finding %u=%s\n",ind,key); + auto it = dnsCache[currentInd].find(setMapName(tempbuff, key, dnsType)); + + if (it != dnsCache[currentInd].end() && it->second) + return it->second; + + return nullptr; +} + +data7 *findQueue(const char *key) { + //printf("finding %u=%s\n",ind,key); + auto it = dnsCache[currentInd].find(key); + + if (it != dnsCache[currentInd].end() && it->second->cacheType == CTYPE_QUEUE) + return it->second; + + return nullptr; +} + +data7 *findDHCPEntry(char *key) { + //printf("finding %u=%s\n",ind,key); + myLower(key); + auto it = dhcpCache.find(key); + + if (it != dhcpCache.end() && it->second) + return it->second; + + return nullptr; +} + +void addDNSEntry(data7 *entry) { + myLower(entry->mapname); + dnsCache[currentInd].insert(pair(entry->mapname, entry)); + + if (entry->expiry && entry->expiry < MY_MAX_TIME) + dnsAge[currentInd].insert(pair(entry->expiry, entry)); +} + +char *cloneString(char *string) { + char *s = (char *)calloc(1, strlen(string) + 1); + + if (s) + strcpy(s, string); + + return s; +} + +MYDWORD getSerial(char *zone) { + char tempbuff[512]; + char logBuff[256]; + char ipbuff[32]; + MYDWORD serial1 = 0; + data5 req; + memset(&req, 0, sizeof(data5)); + req.remote.sin_family = AF_INET; + req.remote.sin_port = htons(IPPORT_DNS); + timeval tv1 {}; + fd_set readfds1; + + if (cfig.replication == 2) + req.remote.sin_addr.s_addr = cfig.zoneServers[0]; + else + req.remote.sin_addr.s_addr = cfig.zoneServers[1]; + + req.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + req.dnsp = (dnsPacket *)req.raw; + req.dnsp->header.qdcount = htons(1); + req.dnsp->header.rd = false; + req.dnsp->header.xid = (t % USHRT_MAX); + req.dp = &req.dnsp->data; + req.dp += pQu(req.dp, zone); + req.dp += pUShort(req.dp, DNS_TYPE_SOA); + req.dp += pUShort(req.dp, DNS_CLASS_IN); + req.bytes = (int)(req.dp - req.raw); + //pUShort(req.raw, req.bytes - 2); + + if ((req.bytes = (int)sendto(req.sock, req.raw, req.bytes, 0, (sockaddr *)&req.remote, sizeof(req.remote))) <= 0) { + closesocket(req.sock); + sprintf(logBuff, "Failed to send request to Primary Server %s", IP2String(ipbuff, req.remote.sin_addr.s_addr)); + logDNSMess(logBuff, 1); + return 0; + } + + FD_ZERO(&readfds1); + tv1.tv_sec = 3; + tv1.tv_usec = 0; + FD_SET(req.sock, &readfds1); + select(USHRT_MAX, &readfds1, nullptr, nullptr, &tv1); + + if (FD_ISSET(req.sock, &readfds1)) { + req.sockLen = sizeof(req.remote); + req.bytes = (int)recvfrom(req.sock, req.raw, sizeof(req.raw), 0, (sockaddr *)&req.remote, &req.sockLen); + + if (req.bytes > 0 && !req.dnsp->header.rcode && req.dnsp->header.qr && ntohs(req.dnsp->header.ancount)) { + req.dp = &req.dnsp->data; + + for (int j = 1; j <= ntohs(req.dnsp->header.qdcount); j++) { + req.dp += fQu(tempbuff, req.dnsp, req.dp); + req.dp += 4; + } + + for (int i = 1; i <= ntohs(req.dnsp->header.ancount); i++) { + req.dp += fQu(tempbuff, req.dnsp, req.dp); + req.dnsType = fUShort(req.dp); + req.dp += 2;//type + req.qclass = fUShort(req.dp); + req.dp += 2;//class + fUInt(req.dp); + req.dp += 4;//ttl + req.dp += 2;//datalength + + if (req.dnsType == DNS_TYPE_SOA) { + req.dp += fQu(tempbuff, req.dnsp, req.dp); + req.dp += fQu(tempbuff, req.dnsp, req.dp); + serial1 = fUInt(req.dp); + } + } + closesocket(req.sock); + return serial1; + } else { + closesocket(req.sock); + //sprintf(logBuff, "Zone %s not found on Primary Server %s", zone, IP2String(ipbuff, req.remote.sin_addr.s_addr)); + //logDNSMess(logBuff, 1); + return 0; + } + } + + closesocket(req.sock); + sprintf(logBuff, "Failed to contact the Primary Server %s", IP2String(ipbuff, req.remote.sin_addr.s_addr)); + logDNSMess(logBuff, 1); + return 0; +} + +#if 0 +void sendServerName() { + errno = 0; + data5 req; + memset(&req, 0, sizeof(data5)); + req.remote.sin_family = AF_INET; + req.remote.sin_port = htons(IPPORT_DNS); + req.remote.sin_addr.s_addr = cfig.zoneServers[0]; + + timeval tv1{}; + fd_set readfds1; + + req.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + req.dnsp = (dnsPacket *)req.raw; + req.dnsp->header.opcode = OPCODE_DYNAMIC_UPDATE; + req.dnsp->header.qr = true; + req.dnsp->header.zcount = htons(1); + req.dnsp->header.prcount = htons(1); + req.dnsp->header.xid = (t % USHRT_MAX); + req.dp = &req.dnsp->data; + req.dp += pQu(req.dp, cfig.zone); + req.dp += pUShort(req.dp, DNS_TYPE_SOA); + req.dp += pUShort(req.dp, DNS_CLASS_IN); + req.dp += pQu(req.dp, cfig.servername_fqn); + req.dp += pUShort(req.dp, DNS_TYPE_A); + req.dp += pUShort(req.dp, DNS_CLASS_IN); + req.dp += pUInt(req.dp, 0); + req.dp += pUShort(req.dp, 4); + req.dp += pIP(req.dp, cfig.zoneServers[1]); + req.bytes = req.dp - req.raw; + //pUShort(req.raw, req.bytes - 2); + + if ((req.bytes = (int)sendto(req.sock, req.raw, req.bytes, 0, (sockaddr *)&req.remote, sizeof(req.remote))) <= 0) { + closesocket(req.sock); + } + + FD_ZERO(&readfds1); + tv1.tv_sec = 5; + tv1.tv_usec = 0; + FD_SET(req.sock, &readfds1); + select(USHRT_MAX, &readfds1, nullptr, nullptr, &tv1); + + if (FD_ISSET(req.sock, &readfds1)) { + req.sockLen = sizeof(req.remote); + req.bytes = recvfrom(req.sock, req.raw, sizeof(req.raw), 0, (sockaddr *)&req.remote, &req.sockLen); + } + + closesocket(req.sock); +} +#endif + +MYWORD recvTcpDnsMess(char *target, SOCKET sock, MYWORD targetSize) { + timeval tv1 {}; + fd_set readfds1; + + FD_ZERO(&readfds1); + FD_SET(sock, &readfds1); + tv1.tv_sec = 5; + tv1.tv_usec = 0; + + if (select(sock + 1, &readfds1, nullptr, nullptr, &tv1)) { + errno = 0; + auto chunk = (int)recv(sock, target, 2, 0); + //errno = WSAGetLastError(); + + if (!errno && chunk == 2) { + char *ptr; + MYWORD rcd = chunk; + MYWORD bytes = fUShort(target) + rcd; + + if (bytes > targetSize - 2) + return 0; + + while (rcd < bytes) { + FD_ZERO(&readfds1); + FD_SET(sock, &readfds1); + tv1.tv_sec = 5; + tv1.tv_usec = 0; + + if (select(sock + 1, &readfds1, nullptr, nullptr, &tv1)) { + errno = 0; + ptr = target + rcd; + chunk = (int)recv(sock, ptr, bytes - rcd, 0); + //errno = WSAGetLastError(); + + if (chunk <= 0 || errno) + return 0; + else + rcd += chunk; + } else + return 0; + } + + return rcd; + } + } + + return 0; +} + +void emptyCache(MYBYTE ind) { + char logBuff[256]; + data7 *cache = nullptr; + + //sprintf(logBuff, "Emptying cache[%d] Start %d=%d",ind, dnsCache[ind].size(), dnsAge[ind].size()); + //logMess(logBuff, 2); + + cfig.mxCount[ind] = 0; + dnsAge[ind].clear(); + auto p = dnsCache[ind].begin(); + + while (p != dnsCache[ind].end()) { + cache = p->second; + dnsCache[ind].erase(p); + free(cache); + p = dnsCache[ind].begin(); + } + + dnsCache[ind].clear(); +} + +void *checkZone(void *lpParam) { + char ipbuff[16]; + char logBuff[256]; + + auto *magin = (data18 *)lpParam; + sleep(cfig.refresh); + + while (kRunning) { + // //if (!dhcpService && !findDNSEntry(IP2String(ipbuff, htonl(cfig.zoneServers[1])), DNS_TYPE_PTR)) + // if (!dhcpService) + // sendServerName(); + + MYBYTE updateInd = !magin->currentInd; + emptyCache(updateInd); + sprintf(logBuff, "Checking Serial from Primary Server %s", IP2String(ipbuff, cfig.zoneServers[0])); + logDNSMess(logBuff, 2); + + MYDWORD serial1 = getSerial(cfig.zone); + MYDWORD serial2 = 0; + + if (serial1) + serial2 = getSerial(cfig.authority); + + if (!serial1 || !serial2) { + //cfig.dnsRepl = 0; + //cfig.dhcpRepl = 0; + sprintf(logBuff, "Failed to get SOA from Primary Server, waiting %i seconds to retry", cfig.retry); + logDNSMess(logBuff, 1); + sleep(cfig.retry); + continue; + } else if (cfig.serial1 && cfig.serial1 == serial1 && cfig.serial2 && cfig.serial2 == serial2) { + if (cfig.refresh > (MYDWORD)(MY_MAX_TIME - t)) + cfig.dnsRepl = MY_MAX_TIME; + else + cfig.dnsRepl = t + cfig.refresh + cfig.retry + cfig.retry; + + if (cfig.expire > (MYDWORD)(MY_MAX_TIME - t)) + cfig.expireTime = MY_MAX_TIME; + else + cfig.expireTime = t + cfig.expire; + + sprintf(logBuff, "Zone Refresh not required"); + logDNSMess(logBuff, 2); + sleep(cfig.refresh); + } else { + //WaitForSingleObject(rEvent, INFINITE); + serial1 = getZone(updateInd, cfig.zone); + sleep(5); + + if (serial1) + serial2 = getZone(updateInd, cfig.authority); + //SetEvent(rEvent); + + if (!serial1 || !serial2) { + sprintf(logBuff, "Waiting %u seconds to retry", cfig.retry); + logDNSMess(logBuff, 1); + sleep(cfig.retry); + } else { + if (cfig.refresh > (MYDWORD)(MY_MAX_TIME - t)) + cfig.dnsRepl = MY_MAX_TIME; + else + cfig.dnsRepl = t + cfig.refresh + cfig.retry + cfig.retry; + + magin->currentInd = updateInd; + magin->done = true; + cfig.serial1 = serial1; + cfig.serial2 = serial2; + + if (cfig.expire > (MYDWORD)(MY_MAX_TIME - t)) + cfig.expireTime = MY_MAX_TIME; + else + cfig.expireTime = t + cfig.expire; + + sleep(cfig.refresh); + } + } + } + + pthread_exit(nullptr); +} + +FILE *pullZone(SOCKET sock) { + char target[4096]; + timeval tv1 {}; + fd_set readfds1; + FILE *f = fopen(tempFile, "wb"); + + if (f) { + fclose(f); + f = fopen(tempFile, "ab"); + } else { + closesocket(sock); + return nullptr; + } + + while (true) { + FD_ZERO(&readfds1); + FD_SET(sock, &readfds1); + tv1.tv_sec = 10; + tv1.tv_usec = 0; + + if (select((sock + 1), &readfds1, nullptr, nullptr, &tv1) > 0) { + errno = 0; + auto bytes = recv(sock, target, sizeof(target), 0); + //errno = WSAGetLastError(); + + if (errno) { + closesocket(sock); + fclose(f); + return nullptr; + } + + if (bytes <= 0) + break; + + if (bytes != fwrite(target, 1, bytes, f)) { + closesocket(sock); + fclose(f); + return nullptr; + } + } else { + break; + //closesocket(sock); + //fclose(f); + //return nullptr; + } + } + + closesocket(sock); + fclose(f); + f = fopen(tempFile, "rb"); + return f; +} + +MYDWORD getZone(MYBYTE ind, char *zone) { + data71 lump {}; + char tempbuff[512]; + char ipbuff[16]; + char logBuff[512]; + char localhost[] = "localhost"; + char localhost_ip[] = "1.0.0.127"; + MYDWORD serial1 = 0; + MYDWORD serial2 = 0; + MYDWORD hostExpiry = 0; + MYDWORD refresh = 0; + MYDWORD retry = 0; + MYDWORD expire = 0; + MYDWORD expiry; + MYDWORD minimum = 0; + int added = 0; + char *data; + char *dp; + MYDWORD ip; + data5 req; + data7 *cache = nullptr; + + memset(&lump, 0, sizeof(data71)); + lump.cacheType = CTYPE_LOCALHOST_A; + lump.dnsType = DNS_TYPE_A; + lump.mapname = localhost; + cache = createCache(&lump); + + if (cache) { + cache->ip = ntohl(inet_addr(localhost_ip)); + cache->expiry = MY_MAX_TIME; + dnsCache[ind].insert(pair(cache->mapname, cache)); + } + + memset(&lump, 0, sizeof(data71)); + lump.cacheType = CTYPE_LOCALHOST_PTR; + lump.dnsType = DNS_TYPE_PTR; + lump.mapname = localhost_ip; + lump.hostname = localhost; + cache = createCache(&lump); + + if (cache) { + cache->expiry = MY_MAX_TIME; + dnsCache[ind].insert(pair(cache->mapname, cache)); + } + + memset(&req, 0, sizeof(data5)); + req.sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (req.sock == INVALID_SOCKET) { + sprintf(logBuff, "Failed to Create Socket, Zone Transfer Failed"); + logDNSMess(logBuff, 1); + return 0; + } + + req.addr.sin_family = AF_INET; + req.addr.sin_addr.s_addr = cfig.zoneServers[1]; + req.addr.sin_port = 0; + + int nRet = bind(req.sock, (sockaddr *)&req.addr, sizeof(req.addr)); + + if (nRet == SOCKET_ERROR) { + closesocket(req.sock); + sprintf(logBuff, + "Error: Interface %s not ready, Zone Transfer Failed", + IP2String(ipbuff, req.addr.sin_addr.s_addr)); + logDNSMess(logBuff, 1); + return 0; + } + + req.remote.sin_family = AF_INET; + req.remote.sin_port = htons(IPPORT_DNS); + req.remote.sin_addr.s_addr = cfig.zoneServers[0]; + + req.sockLen = sizeof(req.remote); + + if (connect(req.sock, (sockaddr *)&req.remote, req.sockLen) >= 0) { + req.dp = req.raw; + req.dp += 2; + req.dnsp = (dnsPacket *)req.dp; + req.dnsp->header.qdcount = htons(1); + req.dnsp->header.xid = (t % USHRT_MAX); + req.dp = &req.dnsp->data; + req.dp += pQu(req.dp, zone); + req.dp += pUShort(req.dp, DNS_TYPE_AXFR); + req.dp += pUShort(req.dp, DNS_CLASS_IN); + req.bytes = (int)(req.dp - req.raw); + pUShort(req.raw, req.bytes - 2); + + if (send(req.sock, req.raw, req.bytes, 0) < req.bytes) { + closesocket(req.sock); + sprintf(logBuff, + "Failed to contact Primary Server %s, Zone Transfer Failed", + IP2String(ipbuff, req.remote.sin_addr.s_addr)); + logDNSMess(logBuff, 1); + return 0; + } + + FILE *f = pullZone(req.sock); + + if (!f) + return 0; + + while (kRunning && !serial2) { + req.bytes = (int)fread(req.raw, 1, 2, f); + + if (req.bytes != 2) + break; + + MYWORD pktSize = fUShort(req.raw); + + req.bytes = (int)fread(req.raw, 1, pktSize, f); + + if ((MYWORD)req.bytes != pktSize) { + fclose(f); + return 0; + } + + req.dnsp = (dnsPacket *)(req.raw); + req.dp = &req.dnsp->data; + char *dataend = req.raw + pktSize; + + if (req.dnsp->header.rcode) { + sprintf( + logBuff, "Primary Server %s, zone %s refused", IP2String(ipbuff, req.remote.sin_addr.s_addr), zone); + logDNSMess(logBuff, 1); + fclose(f); + return 0; + } + + if (!req.dnsp->header.qr || !ntohs(req.dnsp->header.ancount)) { + fclose(f); + return 0; + } + + for (int j = 1; j <= ntohs(req.dnsp->header.qdcount); j++) { + req.dp += fQu(req.query, req.dnsp, req.dp); + req.dp += 4; + } + + for (int i = 1; i <= ntohs(req.dnsp->header.ancount); i++) { + //char *dp = req.dp; + req.dp += fQu(req.mapname, req.dnsp, req.dp); + + if (!req.mapname[0]) { + fclose(f); + return 0; + } + + //sprintf(logBuff, "%u=%s\n", pktSize, req.mapname); + //logMess(logBuff, 2); + + req.dnsType = fUShort(req.dp); + req.dp += 2;//type + req.qclass = fUShort(req.dp); + req.dp += 2;//class + expiry = fUInt(req.dp); + req.dp += 4;//ttl + int dataSize = fUShort(req.dp); + req.dp += 2;//datalength + data = req.dp; + req.dp += dataSize; + + switch (req.dnsType) { + case DNS_TYPE_SOA: + + data += fQu(req.cname, req.dnsp, data); + data += fQu(tempbuff, req.dnsp, data); + + if (!cfig.nsP[0]) + strcpy(cfig.nsP, req.cname); + + if (!serial1) { + hostExpiry = expiry; + serial1 = fUInt(data); + data += 4; + refresh = fUInt(data); + data += 4; + retry = fUInt(data); + data += 4; + expire = fUInt(data); + data += 4; + minimum = fUInt(data); + data += 4; + added++; + } else if (!serial2) + serial2 = fUInt(data); + + break; + + case DNS_TYPE_A: + + ip = fIP(data); + makeLocal(req.mapname); + memset(&lump, 0, sizeof(data71)); + lump.cacheType = CTYPE_LOCAL_A; + lump.dnsType = DNS_TYPE_A; + lump.mapname = req.mapname; + cache = createCache(&lump); + + if (cache) { + cache->ip = ip; + cache->expiry = MY_MAX_TIME; + dnsCache[ind].insert(pair(cache->mapname, cache)); + added++; + } + break; + + case DNS_TYPE_PTR: + + myLower(req.mapname); + dp = strstr(req.mapname, arpa); + + if (dp) { + *dp = 0; + fQu(req.cname, req.dnsp, data); + makeLocal(req.cname); + memset(&lump, 0, sizeof(data71)); + lump.cacheType = CTYPE_LOCAL_PTR_AUTH; + lump.dnsType = DNS_TYPE_PTR; + lump.mapname = req.mapname; + lump.hostname = req.cname; + cache = createCache(&lump); + + if (cache) { + cache->expiry = MY_MAX_TIME; + dnsCache[ind].insert(pair(cache->mapname, cache)); + added++; + } + } + break; + + case DNS_TYPE_MX: + + if (makeLocal(req.mapname) == QTYPE_A_ZONE) { + cfig.mxServers[ind][cfig.mxCount[ind]].pref = fUShort(data); + data += sizeof(MYWORD); + fQu(req.cname, req.dnsp, data); + strcpy(cfig.mxServers[ind][cfig.mxCount[ind]].hostname, req.cname); + cfig.mxCount[ind]++; + added++; + } + break; + + case DNS_TYPE_NS: + + fQu(req.cname, req.dnsp, data); + + if (!cfig.nsS[0] && !strcasecmp(cfig.servername_fqn, req.cname)) + strcpy(cfig.nsS, req.cname); + + break; + + case DNS_TYPE_CNAME: + + makeLocal(req.mapname); + fQu(req.cname, req.dnsp, data); + memset(&lump, 0, sizeof(data71)); + + if (makeLocal(req.cname) == QTYPE_A_EXT) + lump.cacheType = CTYPE_EXT_CNAME; + else + lump.cacheType = CTYPE_LOCAL_CNAME; + + lump.dnsType = DNS_TYPE_A; + lump.mapname = req.mapname; + lump.hostname = req.cname; + cache = createCache(&lump); + + //sprintf(logBuff, "%s=%s=%u=%s=%s", req.mapname, req.cname, cache->mapname[0], &cache->mapname[1], cache->hostname); + //logDNSMess(logBuff, 2); + + if (cache) { + dnsCache[ind].insert(pair(cache->mapname, cache)); + cache->expiry = MY_MAX_TIME; + added++; + } + break; + } + } + + if (req.dp != dataend) { + fclose(f); + return 0; + } + } + + fclose(f); + + if (serial1 && serial1 == serial2 && hostExpiry) { + if (cfig.replication == 2) { + cfig.lease = hostExpiry; + cfig.refresh = refresh; + cfig.retry = retry; + cfig.expire = expire; + cfig.minimum = minimum; + } + + //printf("Refresh ind %i serial %u size %i\n", ind, serial1, dnsCache[ind].size()); + sprintf(logBuff, "Zone %s Transferred from Primary Server, %u RRs imported", zone, added); + logDNSMess(logBuff, 1); + return serial1; + } else { + sprintf(logBuff, + "Primary Server %s, zone %s Invalid AXFR data", + IP2String(ipbuff, req.remote.sin_addr.s_addr), + zone); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, + "Failed to contact Primary Server %s, Zone Transfer Failed", + IP2String(ipbuff, req.remote.sin_addr.s_addr)); + logDNSMess(logBuff, 1); + closesocket(req.sock); + return 0; + } + return 0; +} + +bool getSecondary() { + char logBuff[256]; + MYDWORD ip; + MYDWORD hostExpiry = 0; + MYDWORD expiry = 0; + char *data = nullptr; + char *dp = nullptr; + MYWORD rr = 0; + data5 req; + MYDWORD serial = 0; + + memset(&req, 0, sizeof(data5)); + req.sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (req.sock == INVALID_SOCKET) + return false; + + req.addr.sin_family = AF_INET; + req.addr.sin_addr.s_addr = cfig.zoneServers[0]; + req.addr.sin_port = 0; + + int nRet = bind(req.sock, (sockaddr *)&req.addr, sizeof(req.addr)); + + if (nRet == SOCKET_ERROR) { + closesocket(req.sock); + return false; + } + + req.remote.sin_family = AF_INET; + req.remote.sin_port = htons(IPPORT_DNS); + + if (dhcpService && cfig.replication == 1) + req.remote.sin_addr.s_addr = cfig.zoneServers[1]; + else + return false; + + req.sockLen = sizeof(req.remote); + time_t local_t = time(nullptr); + + if (connect(req.sock, (sockaddr *)&req.remote, req.sockLen) == 0) { + req.dp = req.raw; + req.dp += 2; + req.dnsp = (dnsPacket *)req.dp; + req.dnsp->header.qdcount = htons(1); + req.dnsp->header.xid = (local_t % USHRT_MAX); + req.dp = &req.dnsp->data; + req.dp += pQu(req.dp, cfig.authority); + req.dp += pUShort(req.dp, DNS_TYPE_AXFR); + req.dp += pUShort(req.dp, DNS_CLASS_IN); + req.bytes = (int)(req.dp - req.raw); + pUShort(req.raw, (req.bytes - 2)); + + if (send(req.sock, req.raw, req.bytes, 0) < req.bytes) { + closesocket(req.sock); + return false; + } + + FILE *f = pullZone(req.sock); + + if (!f) + return false; + + while (kRunning) { + req.bytes = (int)fread(req.raw, 1, 2, f); + + if (req.bytes < 2) + break; + + MYWORD pktSize = fUShort(req.raw); + req.bytes = (int)fread(req.raw, 1, pktSize, f); + + if ((MYWORD)req.bytes != pktSize) { + fclose(f); + return false; + } + + req.dnsp = (dnsPacket *)(req.raw); + req.dp = &req.dnsp->data; + char *dataend = req.raw + pktSize; + + if (req.dnsp->header.rcode) { + fclose(f); + return false; + } + + if (!req.dnsp->header.qr || !ntohs(req.dnsp->header.ancount)) { + fclose(f); + return false; + } + + for (int j = 1; j <= ntohs(req.dnsp->header.qdcount); j++) { + req.dp += fQu(req.query, req.dnsp, req.dp); + req.dp += 4; + } + + for (int i = 1; i <= ntohs(req.dnsp->header.ancount); i++) { + //char *dp = req.dp; + req.dp += fQu(req.mapname, req.dnsp, req.dp); + + if (!req.mapname[0]) { + fclose(f); + return false; + } + + req.dnsType = fUShort(req.dp); + req.dp += 2;//type + req.qclass = fUShort(req.dp); + req.dp += 2;//class + expiry = fUInt(req.dp); + req.dp += 4;//ttl + int dataSize = fUShort(req.dp); + req.dp += 2;//datalength + data = req.dp; + req.dp += dataSize; + + if (req.dnsType == DNS_TYPE_PTR) { + myLower(req.mapname); + dp = strstr(req.mapname, arpa); + + if (dp) { + *dp = 0; + ip = ntohl(inet_addr(req.mapname)); + fQu(req.cname, req.dnsp, data); + makeLocal(req.cname); + + auto p = dhcpCache.begin(); + data7 *dhcpEntry = nullptr; + + for (; p != dhcpCache.end(); p++) { + if ((dhcpEntry = p->second) && dhcpEntry->ip && dhcpEntry->hostname) { + if (ip == dhcpEntry->ip && !strcasecmp(req.cname, dhcpEntry->hostname)) { + if (expiry < (MYDWORD)(MY_MAX_TIME - local_t)) + expiry += local_t; + else + expiry = MY_MAX_TIME; + + add2Cache(req.cname, ip, expiry, CTYPE_LOCAL_A, CTYPE_LOCAL_PTR_AUTH); + rr++; + break; + } + } + } + } + } + } + + if (req.dp != dataend) { + fclose(f); + return false; + } + } + + sprintf(logBuff, "%u RRs rebuild from Secondary Server", rr); + logDNSMess(logBuff, 2); + fclose(f); + return true; + } else { + closesocket(req.sock); + return false; + } +} + +void *init(void *lparam) { + char tempbuff[512]; + char logBuff[256]; + char ipbuff[32]; + char raw[512]; + char name[512]; + char value[512]; + FILE *f = nullptr; + + memset(exeFile, 0, sizeof(exeFile)); + char id[256]; + sprintf(id, "/proc/%d/exe", getpid()); + readlink(id, exeFile, PATH_MAX - 1); + exeFile[PATH_MAX - 1] = 0; + strcpy(filePATH, exeFile); + char *ptr = strrchr(filePATH, '/'); + ptr++; + *ptr = 0; + + if (!iniFile[0]) + sprintf(iniFile, "%s%s", filePATH, "dualserver.ini"); + + if (dhcpService && !leaFile[0]) + sprintf(leaFile, "%s%s", filePATH, "dualserver.state"); + + if (dhcpService && !icoFile[0]) + sprintf(icoFile, "%s%s", filePATH, "dualserver.png"); + + if (!logFile[0]) + sprintf(logFile, "%s%s", filePATH, "log/dualserver%Y%m%d.log"); + + if ((f = openSection("LOGGING", 1))) { + cfig.dnsLogLevel = 1; + cfig.dhcpLogLevel = 1; + tempbuff[0] = 0; + + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + if (!strcasecmp(name, "DNSLogLevel")) { + if (!strcasecmp(value, "None")) + cfig.dnsLogLevel = 0; + else if (!strcasecmp(value, "Normal")) + cfig.dnsLogLevel = 1; + else if (!strcasecmp(value, "All")) + cfig.dnsLogLevel = 2; + else + sprintf(tempbuff, "Section [LOGGING], Invalid DNSLogLevel: %s", value); + } else if (!strcasecmp(name, "DHCPLogLevel")) { + if (!strcasecmp(value, "None")) + cfig.dhcpLogLevel = 0; + else if (!strcasecmp(value, "Normal")) + cfig.dhcpLogLevel = 1; + else if (!strcasecmp(value, "All")) + cfig.dhcpLogLevel = 2; + else + sprintf(tempbuff, "Section [LOGGING], Invalid DHCPLogLevel: %s", value); + } else + sprintf(tempbuff, "Section [LOGGING], Invalid Entry %s ignored", raw); + } else + sprintf(tempbuff, "Section [LOGGING], Invalid Entry %s ignored", raw); + } + + if (tempbuff[0]) + logMess(logBuff, 1); + + sprintf(logBuff, "%s Starting...", sVersion); + logMess(logBuff, 1); + } else + printf("%s Starting...", sVersion); + + sleep(1); + + if ((f = fopen(iniFile, "rt"))) { + fclose(f); + } else { + sprintf(logBuff, "Warning: file %s not found, defaults will be used", iniFile); + logMess(logBuff, 1); + } + + if ((f = openSection("SERVICES", 1))) { + dhcpService = false; + dnsService = false; + + while (readSection(raw, f)) { + if (!strcasecmp(raw, "DNS")) + dnsService = true; + else if (!strcasecmp(raw, "DHCP")) + dhcpService = true; + else { + sprintf(logBuff, "Section [SERVICES] invalid entry %s ignored", raw); + logMess(logBuff, 1); + } + } + + if (!dhcpService && !dnsService) { + dhcpService = true; + dnsService = true; + } + } + + if (dnsService) { + sprintf(logBuff, "Starting DNS Service"); + logDNSMess(logBuff, 1); + } + + if (dhcpService) { + sprintf(logBuff, "Starting DHCP Service"); + logMess(logBuff, 1); + } + + sleep(1); + + if (dnsService) { + if (cfig.dnsLogLevel == 2) + sprintf(logBuff, "DNS Logging: All"); + else if (cfig.dnsLogLevel == 1) + sprintf(logBuff, "DNS Logging: Normal"); + else + sprintf(logBuff, "DNS Logging: None"); + + logMess(logBuff, 1); + } + + if (dhcpService) { + if (cfig.dhcpLogLevel >= 2) + sprintf(logBuff, "DHCP Logging: All"); + else if (cfig.dhcpLogLevel == 1) + sprintf(logBuff, "DHCP Logging: Normal"); + else + sprintf(logBuff, "DHCP Logging: None"); + + logDHCPMess(logBuff, 1); + + f = fopen(icoFile, "rb+"); + + if (f) { + if (cfig.dhcpLogLevel >= 2 || verbatim) + logDHCPMess("icon file:", icoFile); + + fseek(f, 0, SEEK_END); + icoSize = (int)ftell(f); + icoString = (char *)calloc(1, icoSize); + fseek(f, 0, SEEK_SET); + icoSize = (int)fread(icoString, 1, icoSize, f); + fclose(f); + } + } + + if (verbatim || cfig.dhcpLogLevel >= 2 || cfig.dnsLogLevel >= 2) { + logMess("exe file:", exeFile); + logMess("ini file:", iniFile); + logMess("log file:", logFile); + + if (dhcpService) + logDHCPMess("state file:", leaFile); + } + + if ((f = openSection("LISTEN_ON", 1))) { + while (readSection(raw, f)) { + if (isIP(raw)) { + MYDWORD addr = inet_addr(raw); + addServer(cfig.specifiedServers, MAX_SERVERS, addr); + } else { + sprintf(logBuff, "Warning: Section [LISTEN_ON], Invalid Interface Address %s, ignored", raw); + logMess(logBuff, 1); + } + } + } + + cfig.lease = 36000; + + if ((f = openSection("TIMINGS", 1))) { + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + if (strtol(value, nullptr, 10) || !strcasecmp(value, "0")) { + if (!strcasecmp(name, "AddressTime")) { + cfig.lease = strtol(value, nullptr, 10); + + if (!cfig.lease) + cfig.lease = UINT_MAX; + } else if (!strcasecmp(name, "Refresh")) + cfig.refresh = strtol(value, nullptr, 10); + else if (!strcasecmp(name, "Retry")) + cfig.retry = strtol(value, nullptr, 10); + else if (!strcasecmp(name, "Expire")) + cfig.expire = strtol(value, nullptr, 10); + else if (!strcasecmp(name, "Minimum")) + cfig.minimum = strtol(value, nullptr, 10); + else if (!strcasecmp(name, "MinCacheTime")) + cfig.minCache = strtol(value, nullptr, 10); + else if (!strcasecmp(name, "MaxCacheTime")) + cfig.maxCache = strtol(value, nullptr, 10); + else { + sprintf(logBuff, "Section [TIMINGS], Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [TIMINGS], Invalid value: %s ignored", value); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [TIMINGS], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + + if (!cfig.refresh) { + cfig.refresh = cfig.lease / 10; + + if (cfig.refresh > 3600) + cfig.refresh = 3600; + + if (cfig.refresh < 300) + cfig.refresh = 300; + } + + if (!cfig.retry || cfig.retry > cfig.refresh) { + cfig.retry = cfig.refresh / 10; + + if (cfig.retry > 600) + cfig.retry = 600; + + if (cfig.retry < 60) + cfig.retry = 60; + } + + if (!cfig.expire) { + if (UINT_MAX / 24 > cfig.lease) + cfig.expire = 24 * cfig.lease; + else + cfig.expire = UINT_MAX; + } + + if (!cfig.minimum) + cfig.minimum = cfig.retry; + + if ((f = openSection("DOMAIN_NAME", 1))) { + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + data15 mask{}; + data15 network_l{}; + char left[64]; + + cfig.authority[0] = 0; + myLower(value); + mask.ip = 0; + network_l.ip = 0; + + for (MYBYTE octateNum = 0; octateNum < 3; octateNum++) { + mySplit(left, value, value, '.'); + if (left[0] == '0' || (strtol(left, nullptr, 10) && strtol(left, nullptr, 10) < 256)) { + for (int j = 2; j >= 0; j--) { + network_l.octate[j + 1] = network_l.octate[j]; + mask.octate[j + 1] = mask.octate[j]; + } + + mask.octate[0] = UCHAR_MAX; + network_l.octate[0] = strtol(left, nullptr, 10); + strcat(cfig.authority, left); + strcat(cfig.authority, "."); + } else + break; + + if (!strcasecmp(value, arpa + 1)) + break; + } + + if (!strcasecmp(value, arpa + 1)) { + strcat(cfig.authority, arpa + 1); + cfig.aLen = strlen(cfig.authority); + calcRangeLimits(network_l.ip, mask.ip, &cfig.rangeStart, &cfig.rangeEnd); + cfig.authorized = 1; + } else { + sprintf(logBuff, "Warning: Invalid Domain Name (Part %s), ignored", cfig.authority); + cfig.aLen = 0; + cfig.authority[0] = 0; + logDNSMess(logBuff, 1); + } + } + + if (chkQu(name)) { + strcpy(cfig.zone, name); + cfig.zLen = strlen(cfig.zone); + } else { + cfig.aLen = 0; + cfig.authority[0] = 0; + sprintf(logBuff, "Warning: Invalid Domain Name %s, ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + + if (dnsService) { + if ((f = openSection("FORWARDING_SERVERS", 1))) { + char raw_l[512]; + + while (readSection(raw_l, f)) { + if (isIP(raw_l)) { + MYDWORD addr = inet_addr(raw_l); + addServer(cfig.specifiedDnsServers, MAX_SERVERS, addr); + } else { + sprintf(logBuff, "Section [FORWARDING_SERVERS] Invalid Entry: %s ignored", raw_l); + logDNSMess(logBuff, 1); + } + } + } + } + + cfig.fixedSocket = socket(AF_INET, SOCK_DGRAM, 0); + + if (cfig.fixedSocket < 0) { + sprintf(logBuff, "Failed to create Socket"); + logMess(logBuff, 1); + sleep(1); + exit(EXIT_FAILURE); + } + + getInterfaces(&network); + sprintf(cfig.servername_fqn, "%s.%s", cfig.servername, cfig.zone); + + while (true) { + if ((f = openSection("ZONE_REPLICATION", 1))) { + int i = 2; + while (readSection(raw, f)) { + if (i < MAX_TCP_CLIENTS) { + if (!cfig.authorized) { + sprintf( + logBuff, "Section [ZONE_REPLICATION], Server is not an authority, entry %s ignored", raw); + logDNSMess(logBuff, 1); + continue; + } + + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + if (chkQu(name) && !isIP(name) && isIP(value)) { + if (!strcasecmp(name, "Primary")) + cfig.zoneServers[0] = inet_addr(value); + else if (!strcasecmp(name, "Secondary")) + cfig.zoneServers[1] = inet_addr(value); + else if (!strcasecmp(name, "AXFRClient")) { + cfig.zoneServers[i] = inet_addr(value); + i++; + } else { + sprintf(logBuff, "Section [ZONE_REPLICATION] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [ZONE_REPLICATION] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [ZONE_REPLICATION], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + + if (!cfig.zoneServers[0] && !cfig.zoneServers[1]) + break; + else if (!cfig.zoneServers[0] && cfig.zoneServers[1]) { + sprintf(logBuff, "Section [ZONE_REPLICATION] Missing Primary Server, stopping"); + logDNSMess(logBuff, 1); + sleep(1); + exit(-1); + } else if (cfig.zoneServers[0] && !cfig.zoneServers[1]) { + sprintf(logBuff, "Section [ZONE_REPLICATION] Missing Secondary Server, stopping"); + logDNSMess(logBuff, 1); + sleep(1); + exit(-1); + } else { + if (findServer(network.allServers, MAX_SERVERS, cfig.zoneServers[0]) + && findServer(network.allServers, MAX_SERVERS, cfig.zoneServers[1])) { + sprintf(logBuff, + "Section [ZONE_REPLICATION] Primary & Secondary should be Different Boxes, stopping"); + logDNSMess(logBuff, 1); + sleep(1); + exit(-1); + } else if (findServer(network.allServers, MAX_SERVERS, cfig.zoneServers[0])) { + cfig.replication = 1; + break; + } else if (findServer(network.allServers, MAX_SERVERS, cfig.zoneServers[1])) { + cfig.replication = 2; + break; + } else { + sprintf(logBuff, + "Section [ZONE_REPLICATION] No Server IP not found on this Machine, waiting %u seconds", + cfig.retry); + logDNSMess(logBuff, 1); + } + } + } + + sleep(cfig.retry); + getInterfaces(&network); + } + + if (dhcpService) { + loadDHCP(); + /* + for (int i = 0; i < cfig.rangeCount; i++) + { + char *logPtr = logBuff; + logPtr += sprintf(logPtr, "DHCP Range: "); + logPtr += sprintf(logPtr, "%s", IP2String(ipbuff, htonl(cfig.dhcpRanges[i].rangeStart))); + logPtr += sprintf(logPtr, "-%s", IP2String(ipbuff, htonl(cfig.dhcpRanges[i].rangeEnd))); + logPtr += sprintf(logPtr, "/%s", IP2String(ipbuff, cfig.dhcpRanges[i].mask)); + logMess(logBuff, 1); + } +*/ + if (cfig.replication) { + lockIP(cfig.zoneServers[0]); + lockIP(cfig.zoneServers[1]); + } + } + + if (dnsService) { + if (FILE *fp = openSection("FORWARDING_SERVERS", 1)) { + char raw_l[512]; + int i = 0; + + while (readSection(raw_l, fp)) { + if (i < MAX_SERVERS) { + if (isIP(raw_l)) { + MYDWORD addr = inet_addr(raw_l); + if (addServer(cfig.specifiedDnsServers, MAX_SERVERS, addr)) + i++; + } else { + sprintf(logBuff, "Section [FORWARDING_SERVERS] Invalid Entry: %s ignored", raw_l); + logDNSMess(logBuff, 1); + } + } + } + } + + if ((f = openSection("DNS_ALLOWED_HOSTS", 1))) { + int i = 0; + + while (readSection(raw, f)) { + if (i < MAX_DNS_RANGES) { + MYDWORD rs = 0; + MYDWORD re = 0; + mySplit(name, value, raw, '-'); + + if (isIP(name) && isIP(value)) { + rs = htonl(inet_addr(name)); + re = htonl(inet_addr(value)); + } else if (isIP(name) && !value[0]) { + rs = htonl(inet_addr(name)); + re = rs; + } + + //printf("%u=%u\n", rs, re); + + if (rs && re && rs <= re) { + cfig.dnsRanges[i].rangeStart = rs; + cfig.dnsRanges[i].rangeEnd = re; + i++; + } else { + sprintf(logBuff, "Section [DNS_ALLOWED_HOSTS] Invalid entry %s in ini file, ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + } + + if (cfig.replication != 2 && (f = openSection("DNS_HOSTS", 1))) { + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + if (chkQu(name) && !isIP(name)) { + MYDWORD ip = inet_addr(value); + MYBYTE nameType = makeLocal(name); + bool ipLocal = isLocal(ip); + + if (!strcasecmp(value, "0.0.0.0")) { + addHostNotFound(name); + continue; + } else if (!ip) { + sprintf(logBuff, "Section [DNS_HOSTS] Invalid Entry %s ignored", raw); + logDNSMess(logBuff, 1); + continue; + } + + switch (nameType) { + case QTYPE_A_ZONE: + case QTYPE_A_BARE: + case QTYPE_A_LOCAL: + add2Cache(name, ip, MY_MAX_TIME, CTYPE_STATIC_A_AUTH, 0); + break; + + default: + if (cfig.replication) { + sprintf(logBuff, + "Section [DNS_HOSTS] forward entry for %s not in Forward Zone, ignored", + raw); + logDNSMess(logBuff, 1); + } else + add2Cache(name, ip, MY_MAX_TIME, CTYPE_STATIC_A_NAUTH, 0); + + break; + } + + if (ipLocal) { + add2Cache(name, ip, MY_MAX_TIME, 0, CTYPE_STATIC_PTR_AUTH); + holdIP(ip); + } else if (cfig.replication) { + sprintf( + logBuff, "Section [DNS_HOSTS] reverse entry for %s not in Reverse Zone, ignored", raw); + logDNSMess(logBuff, 1); + } else + add2Cache(name, ip, MY_MAX_TIME, 0, CTYPE_STATIC_PTR_NAUTH); + } else { + sprintf(logBuff, "Section [DNS_HOSTS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [DNS_HOSTS], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + + if (cfig.replication != 2 && (f = openSection("ALIASES", 1))) { + int i = 0; + + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + MYBYTE nameType = makeLocal(name); + MYBYTE aliasType = makeLocal(value); + + if (chkQu(name) && chkQu(value) && strcasecmp(value, cfig.zone) != 0) { + if ((nameType == QTYPE_A_BARE || nameType == QTYPE_A_LOCAL || nameType == QTYPE_A_ZONE)) { + data7 *cache = findDNSEntry(name, DNS_TYPE_A); + + if (!cache) { + memset(&g_lump, 0, sizeof(data71)); + + if ((aliasType == QTYPE_A_BARE || aliasType == QTYPE_A_LOCAL + || aliasType == QTYPE_A_ZONE)) + g_lump.cacheType = CTYPE_LOCAL_CNAME; + else + g_lump.cacheType = CTYPE_EXT_CNAME; + + g_lump.dnsType = DNS_TYPE_A; + g_lump.mapname = name; + g_lump.hostname = value; + cache = createCache(&g_lump); + + if (cache) { + cache->expiry = MY_MAX_TIME; + addDNSEntry(cache); + } + } else { + sprintf(logBuff, "Section [ALIASES] duplicate entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf( + logBuff, "Section [ALIASES] alias %s should be bare/local name, entry ignored", name); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [ALIASES] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [ALIASES], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + + if (cfig.replication != 2 && (f = openSection("MAIL_SERVERS", 1))) { + cfig.mxCount[0] = 0; + + while (readSection(raw, f)) { + if (cfig.mxCount[0] < MAX_SERVERS) { + mySplit(name, value, raw, '='); + if (name[0] && value[0]) { + if (chkQu(name) && strtol(value, nullptr, 10)) { + cfig.mxServers[0][cfig.mxCount[0]].pref = strtol(value, nullptr, 10); + cfig.mxServers[1][cfig.mxCount[0]].pref = strtol(value, nullptr, 10); + + if (!strchr(name, '.')) { + strcat(name, "."); + strcat(name, cfig.zone); + } + + strcpy(cfig.mxServers[0][cfig.mxCount[0]].hostname, name); + strcpy(cfig.mxServers[1][cfig.mxCount[0]].hostname, name); + cfig.mxCount[0]++; + } else { + sprintf(logBuff, "Section [MAIL_SERVERS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [MAIL_SERVERS], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + //cfig.mxCount[1] = cfig.mxCount[0]; + } + } + + if ((f = openSection("CONDITIONAL_FORWARDERS", 1))) { + int i = 0; + + while (readSection(raw, f)) { + if (i < MAX_COND_FORW) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + int j = 0; + + for (; j < MAX_COND_FORW && cfig.dnsRoutes[j].zone[0]; j++) { + if (!strcasecmp(cfig.dnsRoutes[j].zone, name)) { + sprintf(logBuff, + "Section [CONDITIONAL_FORWARDERS], Duplicate Entry for Child Zone %s ignored", + raw); + logDNSMess(logBuff, 1); + break; + } + } + + if (j < MAX_COND_FORW && !cfig.dnsRoutes[j].zone[0]) { + if (name[0] && chkQu(name) && value[0]) { + char *value1 = strchr(value, ','); + + if (value1) { + *value1 = 0; + value1++; + + MYDWORD ip = inet_addr(myTrim(value, value)); + MYDWORD ip1 = inet_addr(myTrim(value1, value1)); + + if (isIP(value) && isIP(value1)) { + strcpy(cfig.dnsRoutes[i].zone, name); + cfig.dnsRoutes[i].zLen = strlen(cfig.dnsRoutes[i].zone); + cfig.dnsRoutes[i].dns[0] = ip; + cfig.dnsRoutes[i].dns[1] = ip1; + i++; + } else { + sprintf( + logBuff, "Section [CONDITIONAL_FORWARDERS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + MYDWORD ip = inet_addr(value); + + if (isIP(value)) { + strcpy(cfig.dnsRoutes[i].zone, name); + cfig.dnsRoutes[i].zLen = strlen(cfig.dnsRoutes[i].zone); + cfig.dnsRoutes[i].dns[0] = ip; + i++; + } else { + sprintf( + logBuff, "Section [CONDITIONAL_FORWARDERS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } else { + sprintf(logBuff, "Section [CONDITIONAL_FORWARDERS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } else { + sprintf(logBuff, "Section [CONDITIONAL_FORWARDERS], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + } + + if ((f = openSection("WILD_HOSTS", 1))) { + int i = 0; + + while (readSection(raw, f)) { + if (i < MAX_WILD_HOSTS) { + mySplit(name, value, raw, '='); + + if (name[0] && value[0]) { + if (chkQu(name) && (isIP(value) || !strcasecmp(value, "0.0.0.0"))) { + MYDWORD ip = inet_addr(value); + strcpy(cfig.wildHosts[i].wildcard, name); + myLower(cfig.wildHosts[i].wildcard); + cfig.wildHosts[i].ip = ip; + i++; + } else { + sprintf(logBuff, "Section [WILD_HOSTS] Invalid Entry: %s ignored", raw); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Section [WILD_HOSTS], Missing value, entry %s ignored", raw); + logDNSMess(logBuff, 1); + } + } + } + } + + if (cfig.replication == 2) { + // if (dhcpService) + // strcpy(cfig.nsS, cfig.servername_fqn); + + while (kRunning) { + // //if (!dhcpService && !findDNSEntry(IP2String(ipbuff, htonl(cfig.zoneServers[1])), DNS_TYPE_PTR)) + // if (!dhcpService) + // { + // sendServerName(); + // sleep(1); + // } + + MYDWORD serial1 = getSerial(cfig.zone); + MYDWORD serial2 = 0; + + if (serial1) + serial2 = getSerial(cfig.authority); + + if (serial1 && serial2) { + cfig.serial1 = getZone(0, cfig.zone); + sleep(5); + + if (cfig.serial1) + cfig.serial2 = getZone(0, cfig.authority); + } + + if (cfig.serial1 && cfig.serial2) { + if (cfig.refresh > (MYDWORD)(MY_MAX_TIME - t)) + cfig.dnsRepl = MY_MAX_TIME; + else + cfig.dnsRepl = t + cfig.refresh + cfig.retry + cfig.retry; + + break; + } + + sprintf(logBuff, "Failed to get Zone(s) from Primary Server, waiting %d seconds to retry", cfig.retry); + logDNSMess(logBuff, 1); + + sleep(cfig.retry); + } + + if (dhcpService) { + data7 *cache = nullptr; + auto p = dnsCache[currentInd].begin(); + + while (p != dnsCache[currentInd].end()) { + cache = p->second; + + switch (cache->cacheType) { + case CTYPE_STATIC_A_AUTH: + holdIP(cache->ip); + break; + + case CTYPE_STATIC_PTR_AUTH: + holdIP(htonl(inet_addr(cache->mapname))); + break; + } + + p++; + } + } + + if (cfig.expire > (MYDWORD)(MY_MAX_TIME - t)) + cfig.expireTime = MY_MAX_TIME; + else + cfig.expireTime = t + cfig.expire; + + g_magin.currentInd = 0; + g_magin.done = false; + + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, checkZone, &g_magin); + pthread_attr_destroy(&attr); + } else if (cfig.replication == 1) { + strcpy(cfig.nsP, cfig.servername_fqn); + findHost(cfig.nsS, cfig.zoneServers[1]); + + if (cfig.nsS[0]) { + strcat(cfig.nsS, "."); + strcat(cfig.nsS, cfig.zone); + } + + cfig.serial1 = t; + cfig.serial2 = t; + cfig.expireTime = MY_MAX_TIME; + + if (dhcpService) + getSecondary(); + } else { + strcpy(cfig.nsP, cfig.servername_fqn); + + cfig.serial1 = t; + cfig.serial2 = t; + cfig.expireTime = MY_MAX_TIME; + char localhost[] = "localhost"; + } + } + + if (dhcpService) { + if (cfig.replication) { + cfig.dhcpReplConn.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (cfig.dhcpReplConn.sock == INVALID_SOCKET) { + sprintf(logBuff, "Failed to Create DHCP Replication Socket"); + logDHCPMess(logBuff, 1); + } else { + //printf("Socket %u\n", cfig.dhcpReplConn.sock); + + if (cfig.replication == 1) + cfig.dhcpReplConn.server = cfig.zoneServers[0]; + else + cfig.dhcpReplConn.server = cfig.zoneServers[1]; + + cfig.dhcpReplConn.addr.sin_family = AF_INET; + cfig.dhcpReplConn.addr.sin_addr.s_addr = cfig.dhcpReplConn.server; + cfig.dhcpReplConn.addr.sin_port = 0; + + int nRet = bind( + cfig.dhcpReplConn.sock, (sockaddr *)&cfig.dhcpReplConn.addr, sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + cfig.dhcpReplConn.ready = false; + sprintf(logBuff, "DHCP Replication Server, Bind Failed"); + logDHCPMess(logBuff, 1); + } else { + cfig.dhcpReplConn.port = IPPORT_DHCPS; + cfig.dhcpReplConn.loaded = true; + cfig.dhcpReplConn.ready = true; + + data3 op{}; + memset(&token, 0, sizeof(data9)); + token.vp = token.dhcpp.vend_data; + token.messsize = sizeof(dhcp_packet); + + token.remote.sin_port = htons(IPPORT_DHCPS); + token.remote.sin_family = AF_INET; + + if (cfig.replication == 1) + token.remote.sin_addr.s_addr = cfig.zoneServers[1]; + else if (cfig.replication == 2) + token.remote.sin_addr.s_addr = cfig.zoneServers[0]; + + token.dhcpp.header.bp_op = BOOTP_REQUEST; + token.dhcpp.header.bp_xid = t; + strcpy(token.dhcpp.header.bp_sname, cfig.servername); + token.dhcpp.header.bp_magic_num[0] = 99; + token.dhcpp.header.bp_magic_num[1] = 130; + token.dhcpp.header.bp_magic_num[2] = 83; + token.dhcpp.header.bp_magic_num[3] = 99; + + op.opt_code = DHCP_OPTION_MESSAGETYPE; + op.size = 1; + op.value[0] = DHCP_MESS_INFORM; + pvdata(&token, &op); + + if (dnsService) { + op.opt_code = DHCP_OPTION_DNS; + op.size = 4; + + if (cfig.replication == 1) + pIP(op.value, cfig.zoneServers[0]); + else + pIP(op.value, cfig.zoneServers[1]); + + pvdata(&token, &op); + } + + //op.opt_code = DHCP_OPTION_HOSTNAME; + //op.size = strlen(cfig.servername); + //memcpy(op.value, cfig.servername, op.size); + //pvdata(&token, &op); + + token.vp[0] = DHCP_OPTION_END; + token.vp++; + token.bytes = (int)(token.vp - (MYBYTE *)token.raw); + + if (cfig.replication == 2) { + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, sendToken, nullptr); + pthread_attr_destroy(&attr); + } + } + } + } + + if (cfig.lease >= MY_MAX_TIME) + sprintf(logBuff, "Default Lease: Infinity"); + else + sprintf(logBuff, "Default Lease: %u (sec)", cfig.lease); + + logMess(logBuff, 1); + } + + if (cfig.replication == 1) + sprintf(logBuff, "Server Name: %s (Primary)", cfig.servername); + else if (cfig.replication == 2) + sprintf(logBuff, "Server Name: %s (Secondary)", cfig.servername); + else + sprintf(logBuff, "Server Name: %s", cfig.servername); + + logDNSMess(logBuff, 1); + + if (dnsService) { + if (cfig.authorized) + sprintf(logBuff, "Authority for Zone: %s (%s)", cfig.zone, cfig.authority); + else + sprintf(logBuff, "Domain Name: %s", cfig.zone); + + logDNSMess(logBuff, 1); + + if (cfig.lease >= MY_MAX_TIME) + sprintf(logBuff, "Default Host Expiry: Infinity"); + else + sprintf(logBuff, "Default Host Expiry: %u (sec)", cfig.lease); + + logDNSMess(logBuff, 1); + + if (cfig.replication) { + sprintf(logBuff, "Refresh: %u (sec)", cfig.refresh); + logDNSMess(logBuff, 1); + sprintf(logBuff, "Retry: %u (sec)", cfig.retry); + logDNSMess(logBuff, 1); + + if (cfig.expire == UINT_MAX) + sprintf(logBuff, "Expire: Infinity"); + else + sprintf(logBuff, "Expire: %u (sec)", cfig.expire); + + logDNSMess(logBuff, 1); + sprintf(logBuff, "Min: %u (sec)", cfig.minimum); + logDNSMess(logBuff, 1); + } + + for (int i = 0; i < MAX_COND_FORW && cfig.dnsRoutes[i].dns[0]; i++) { + char temp[256]; + + if (!cfig.dnsRoutes[i].dns[1]) + sprintf(logBuff, + "Conditional Forwarder: %s for %s", + IP2String(ipbuff, cfig.dnsRoutes[i].dns[0]), + cfig.dnsRoutes[i].zone); + else + sprintf(logBuff, + "Conditional Forwarder: %s, %s for %s", + IP2String(temp, cfig.dnsRoutes[i].dns[0]), + IP2String(ipbuff, cfig.dnsRoutes[i].dns[1]), + cfig.dnsRoutes[i].zone); + + logDNSMess(logBuff, 1); + } + + for (int i = 0; i < MAX_SERVERS && network.dns[i]; i++) { + sprintf(logBuff, "Default Forwarding Server: %s", IP2String(ipbuff, network.dns[i])); + logDNSMess(logBuff, 1); + } + + //char temp[128]; + + for (int i = 0; i <= MAX_DNS_RANGES && cfig.dnsRanges[i].rangeStart; i++) { + char *logPtr = logBuff; + logPtr += sprintf(logPtr, "%s", "DNS Service Permitted Hosts: "); + logPtr += sprintf(logPtr, "%s-", IP2String(ipbuff, htonl(cfig.dnsRanges[i].rangeStart))); + logPtr += sprintf(logPtr, "%s", IP2String(ipbuff, htonl(cfig.dnsRanges[i].rangeEnd))); + logDNSMess(logBuff, 1); + } + } else { + sprintf(logBuff, "Domain Name: %s", cfig.zone); + logDNSMess(logBuff, 1); + } + + getInterfaces(&newNetwork); + memcpy(cfig.oldservers, newNetwork.allServers, (MAX_SERVERS * sizeof(MYDWORD))); + + do { + bool bindfailed = false; + newNetwork.maxFD = 0; + + //printf("Setting DHCP Sockets\n"); + + if (dhcpService) { + int i = 0; + + for (int j = 0; j < MAX_SERVERS && newNetwork.listenServers[j]; j++) { + int k = 0; + + for (; k < MAX_SERVERS && network.dhcpConn[k].loaded; k++) { + if (network.dhcpConn[k].ready && network.dhcpConn[k].server == newNetwork.listenServers[j]) + break; + } + + if (network.dhcpConn[k].ready && network.dhcpConn[k].server == newNetwork.listenServers[j]) { + memcpy(&(newNetwork.dhcpConn[i]), &(network.dhcpConn[k]), sizeof(DhcpConnType)); + + if (newNetwork.maxFD < newNetwork.dhcpConn[i].sock) + newNetwork.maxFD = newNetwork.dhcpConn[i].sock; + + network.dhcpConn[k].ready = false; + i++; + continue; + } else { + newNetwork.dhcpConn[i].sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (newNetwork.dhcpConn[i].sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Create Socket"); + logMess(logBuff, 1); + continue; + } + + //printf("Socket %u\n", newNetwork.dhcpConn[i].sock); + + newNetwork.dhcpConn[i].addr.sin_family = AF_INET; + newNetwork.dhcpConn[i].addr.sin_addr.s_addr = newNetwork.listenServers[j]; + newNetwork.dhcpConn[i].addr.sin_port = htons(IPPORT_DHCPS); + newNetwork.dhcpConn[i].reUseVal = true; + newNetwork.dhcpConn[i].reUseSize = sizeof(newNetwork.dhcpConn[i].reUseVal); + + setsockopt(newNetwork.dhcpConn[i].sock, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&newNetwork.dhcpConn[i].reUseVal, + newNetwork.dhcpConn[i].reUseSize); + + newNetwork.dhcpConn[i].broadCastVal = true; + newNetwork.dhcpConn[i].broadCastSize = sizeof(newNetwork.dhcpConn[i].broadCastVal); + + setsockopt(newNetwork.dhcpConn[i].sock, + SOL_SOCKET, + SO_BROADCAST, + (char *)&newNetwork.dhcpConn[i].broadCastVal, + newNetwork.dhcpConn[i].broadCastSize); + int nRet = bind(newNetwork.dhcpConn[i].sock, + (sockaddr *)&newNetwork.dhcpConn[i].addr, + sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + close(newNetwork.dhcpConn[i].sock); + sprintf(logBuff, "%s Port 67 already in use", IP2String(ipbuff, newNetwork.listenServers[j])); + logMess(logBuff, 1); + continue; + } + + newNetwork.dhcpConn[i].loaded = true; + newNetwork.dhcpConn[i].ready = true; + + if (newNetwork.maxFD < newNetwork.dhcpConn[i].sock) + newNetwork.maxFD = newNetwork.dhcpConn[i].sock; + + newNetwork.dhcpConn[i].server = newNetwork.listenServers[j]; + newNetwork.dhcpConn[i].mask = newNetwork.listenMasks[j]; + newNetwork.dhcpConn[i].port = IPPORT_DHCPS; + + i++; + } + } + + if (network.dhcpListener.ready) { + memcpy(&(newNetwork.dhcpListener), &(network.dhcpListener), sizeof(DhcpConnType)); + + if (newNetwork.maxFD < newNetwork.dhcpListener.sock) + newNetwork.maxFD = newNetwork.dhcpListener.sock; + + network.dhcpListener.ready = false; + } else { + newNetwork.dhcpListener.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (newNetwork.dhcpListener.sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Creat DHCP Socket"); + logMess(logBuff, 1); + } else { + newNetwork.dhcpListener.reUseVal = true; + newNetwork.dhcpListener.reUseSize = sizeof(newNetwork.dhcpListener.reUseVal); + setsockopt(newNetwork.dhcpListener.sock, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&newNetwork.dhcpListener.reUseVal, + newNetwork.dhcpListener.reUseSize); + newNetwork.dhcpListener.pktinfoVal = true; + newNetwork.dhcpListener.pktinfoSize = sizeof(newNetwork.dhcpListener.pktinfoVal); + setsockopt(newNetwork.dhcpListener.sock, + IPPROTO_IP, + IP_PKTINFO, + &newNetwork.dhcpListener.pktinfoVal, + newNetwork.dhcpListener.pktinfoSize); + + newNetwork.dhcpListener.addr.sin_family = AF_INET; + newNetwork.dhcpListener.addr.sin_addr.s_addr = INADDR_ANY; + newNetwork.dhcpListener.addr.sin_port = htons(IPPORT_DHCPS); + + int nRet = bind(newNetwork.dhcpListener.sock, + (sockaddr *)&newNetwork.dhcpListener.addr, + sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + close(newNetwork.dhcpListener.sock); + sprintf(logBuff, "DHCP Port 67 already in use"); + logMess(logBuff, 1); + } else { + newNetwork.dhcpListener.loaded = true; + newNetwork.dhcpListener.ready = true; + + if (newNetwork.maxFD < newNetwork.dhcpListener.sock) + newNetwork.maxFD = newNetwork.dhcpListener.sock; + } + } + } + + newNetwork.httpConn.port = 6789; + newNetwork.httpConn.server = newNetwork.dhcpConn[0].server; + newNetwork.httpConn.loaded = true; + + if ((f = openSection("HTTP_INTERFACE", 1))) { + while (readSection(raw, f)) { + mySplit(name, value, raw, '='); + + if (!strcasecmp(name, "HTTPServer")) { + mySplit(name, value, value, ':'); + + if (isIP(name)) { + newNetwork.httpConn.loaded = true; + newNetwork.httpConn.server = inet_addr(name); + } else { + newNetwork.httpConn.loaded = false; + sprintf(logBuff, "Warning: Section [HTTP_INTERFACE], Invalid IP Address %s, ignored", name); + logMess(logBuff, 1); + } + + if (value[0]) { + if (strtol(value, nullptr, 10)) + newNetwork.httpConn.port = strtol(value, nullptr, 10); + else { + newNetwork.httpConn.loaded = false; + sprintf(logBuff, "Warning: Section [HTTP_INTERFACE], Invalid port %s, ignored", value); + logMess(logBuff, 1); + } + } + + if (newNetwork.httpConn.server != inet_addr("127.0.0.1") + && !findServer(newNetwork.allServers, MAX_SERVERS, newNetwork.httpConn.server)) { + newNetwork.httpConn.loaded = false; + sprintf(logBuff, "Warning: Section [HTTP_INTERFACE], %s not available, ignored", raw); + logMess(logBuff, 1); + } + } else if (!strcasecmp(name, "HTTPClient")) { + if (isIP(value)) + addServer(cfig.httpClients, 8, inet_addr(value)); + else { + sprintf(logBuff, "Warning: Section [HTTP_INTERFACE], invalid client IP %s, ignored", raw); + logMess(logBuff, 1); + } + } else if (!strcasecmp(name, "HTTPTitle")) { + strncpy(htmlTitle, value, 255); + htmlTitle[255] = 0; + } else { + sprintf(logBuff, "Warning: Section [HTTP_INTERFACE], invalid entry %s, ignored", raw); + logMess(logBuff, 1); + } + } + } + + if (htmlTitle[0] == 0) + sprintf(htmlTitle, "Dual Server on %s", cfig.servername); + + if (newNetwork.httpConn.loaded) { + if (network.httpConn.ready && network.httpConn.server == newNetwork.httpConn.server + && network.httpConn.port == newNetwork.httpConn.port) { + memcpy(&(newNetwork.httpConn), &(network.httpConn), sizeof(ConnType)); + + if (newNetwork.httpConn.sock > newNetwork.maxFD) + newNetwork.maxFD = newNetwork.httpConn.sock; + + network.httpConn.ready = false; + } else if (newNetwork.httpConn.server) { + newNetwork.httpConn.sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (newNetwork.httpConn.sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Create Socket"); + logMess(logBuff, 1); + } else { + //printf("Socket %u\n", newNetwork.httpConn.sock); + + newNetwork.httpConn.addr.sin_family = AF_INET; + newNetwork.httpConn.addr.sin_addr.s_addr = newNetwork.httpConn.server; + newNetwork.httpConn.addr.sin_port = htons(newNetwork.httpConn.port); + + int nRet = bind(newNetwork.httpConn.sock, + (sockaddr *)&newNetwork.httpConn.addr, + sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + sprintf(logBuff, + "Http Interface %s TCP Port %u not available", + IP2String(ipbuff, newNetwork.httpConn.server), + newNetwork.httpConn.port); + logMess(logBuff, 1); + closesocket(newNetwork.httpConn.sock); + } else { + nRet = listen(newNetwork.httpConn.sock, SOMAXCONN); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + sprintf(logBuff, + "%s TCP Port %u Error on Listen", + IP2String(ipbuff, newNetwork.httpConn.server), + newNetwork.httpConn.port); + logMess(logBuff, 1); + closesocket(newNetwork.httpConn.sock); + } else { + newNetwork.httpConn.loaded = true; + newNetwork.httpConn.ready = true; + + if (newNetwork.httpConn.sock > newNetwork.maxFD) + newNetwork.maxFD = newNetwork.httpConn.sock; + } + } + } + } + } + } + + //printf("Setting DNS Sockets\n"); + + if (dnsService) { + if (cfig.replication != 2) { + char localhost[] = "localhost"; + add2Cache(localhost, inet_addr("127.0.0.1"), MY_MAX_TIME, CTYPE_LOCALHOST_A, CTYPE_LOCALHOST_PTR); + + for (int i = 0; i < MAX_SERVERS && newNetwork.listenServers[i]; i++) { + if (isLocal(newNetwork.listenServers[i])) + add2Cache(cfig.servername, + newNetwork.listenServers[i], + MY_MAX_TIME, + CTYPE_SERVER_A_AUTH, + CTYPE_SERVER_PTR_AUTH); + else + add2Cache(cfig.servername, + newNetwork.listenServers[i], + MY_MAX_TIME, + CTYPE_SERVER_A_AUTH, + CTYPE_SERVER_PTR_NAUTH); + } + } + + int i = 0; + + for (int j = 0; j < MAX_SERVERS && newNetwork.listenServers[j]; j++) { + int k = 0; + + for (; k < MAX_SERVERS && network.dnsUdpConn[k].loaded; k++) { + if (network.dnsUdpConn[k].ready && network.dnsUdpConn[k].server == newNetwork.listenServers[j]) + break; + } + + if (network.dnsUdpConn[k].ready && network.dnsUdpConn[k].server == newNetwork.listenServers[j]) { + memcpy(&(newNetwork.dnsUdpConn[i]), &(network.dnsUdpConn[k]), sizeof(ConnType)); + + if (newNetwork.maxFD < newNetwork.dnsUdpConn[i].sock) + newNetwork.maxFD = newNetwork.dnsUdpConn[i].sock; + + network.dnsUdpConn[k].ready = false; + i++; + continue; + } else { + newNetwork.dnsUdpConn[i].sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (newNetwork.dnsUdpConn[i].sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Create Socket"); + logDNSMess(logBuff, 1); + continue; + } + + //printf("Socket %u\n", newNetwork.dnsUdpConn[i].sock); + + newNetwork.dnsUdpConn[i].addr.sin_family = AF_INET; + newNetwork.dnsUdpConn[i].addr.sin_addr.s_addr = newNetwork.listenServers[j]; + newNetwork.dnsUdpConn[i].addr.sin_port = htons(IPPORT_DNS); + + int nRet = bind(newNetwork.dnsUdpConn[i].sock, + (sockaddr *)&newNetwork.dnsUdpConn[i].addr, + sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + closesocket(newNetwork.dnsUdpConn[i].sock); + sprintf(logBuff, + "Warning: %s UDP Port 53 already in use", + IP2String(ipbuff, newNetwork.listenServers[j])); + logDNSMess(logBuff, 1); + continue; + } + + newNetwork.dnsUdpConn[i].loaded = true; + newNetwork.dnsUdpConn[i].ready = true; + + if (newNetwork.maxFD < newNetwork.dnsUdpConn[i].sock) + newNetwork.maxFD = newNetwork.dnsUdpConn[i].sock; + + newNetwork.dnsUdpConn[i].server = newNetwork.listenServers[j]; + newNetwork.dnsUdpConn[i].port = IPPORT_DNS; + + i++; + } + } + + if (network.forwConn.ready) { + memcpy(&(newNetwork.forwConn), &(network.forwConn), sizeof(ConnType)); + + if (newNetwork.maxFD < newNetwork.forwConn.sock) + newNetwork.maxFD = newNetwork.forwConn.sock; + + network.forwConn.ready = false; + } else { + newNetwork.forwConn.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (newNetwork.forwConn.sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Create Socket"); + logDNSMess(logBuff, 1); + } else { + newNetwork.forwConn.addr.sin_family = AF_INET; + newNetwork.forwConn.server = network.dns[0]; + newNetwork.forwConn.port = IPPORT_DNS; + //bind(newNetwork.forwConn.sock, (sockaddr*)&newNetwork.forwConn.addr, sizeof(struct sockaddr_in)); + + //int val = 0; + //setsockopt(network.forwConn.sock, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val)); + int val = IP_PMTUDISC_DONT; + setsockopt(network.forwConn.sock, IPPROTO_IP, IP_PMTUDISC_DONT, &val, sizeof(val)); + + newNetwork.forwConn.loaded = true; + newNetwork.forwConn.ready = true; + + if (newNetwork.maxFD < newNetwork.forwConn.sock) + newNetwork.maxFD = newNetwork.forwConn.sock; + } + } + + i = 0; + + for (int j = 0; j < MAX_SERVERS && newNetwork.listenServers[j]; j++) { + int k = 0; + + for (; k < MAX_SERVERS && network.dnsTcpConn[k].loaded; k++) { + if (network.dnsTcpConn[k].ready && network.dnsTcpConn[k].server == newNetwork.listenServers[j]) + break; + } + + if (network.dnsTcpConn[k].ready && network.dnsTcpConn[k].server == newNetwork.listenServers[j]) { + memcpy(&(newNetwork.dnsTcpConn[i]), &(network.dnsTcpConn[k]), sizeof(ConnType)); + + if (newNetwork.maxFD < newNetwork.dnsTcpConn[i].sock) + newNetwork.maxFD = newNetwork.dnsTcpConn[i].sock; + + network.dnsTcpConn[k].ready = false; + i++; + continue; + } else { + newNetwork.dnsTcpConn[i].sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (newNetwork.dnsTcpConn[i].sock == INVALID_SOCKET) { + bindfailed = true; + sprintf(logBuff, "Failed to Create Socket"); + logDNSMess(logBuff, 1); + } else { + //printf("Socket %u\n", newNetwork.dnsTcpConn[i].sock); + newNetwork.dnsTcpConn[i].addr.sin_family = AF_INET; + newNetwork.dnsTcpConn[i].addr.sin_addr.s_addr = newNetwork.listenServers[j]; + newNetwork.dnsTcpConn[i].addr.sin_port = htons(IPPORT_DNS); + + int nRet = bind(newNetwork.dnsTcpConn[i].sock, + (sockaddr *)&newNetwork.dnsTcpConn[i].addr, + sizeof(struct sockaddr_in)); + + if (nRet == SOCKET_ERROR) { + bindfailed = true; + closesocket(newNetwork.dnsTcpConn[i].sock); + sprintf(logBuff, + "Warning: %s TCP Port 53 already in use", + IP2String(ipbuff, newNetwork.listenServers[j])); + logDNSMess(logBuff, 1); + } else { + nRet = listen(newNetwork.dnsTcpConn[i].sock, SOMAXCONN); + + if (nRet == SOCKET_ERROR) { + closesocket(newNetwork.dnsTcpConn[i].sock); + sprintf(logBuff, "TCP Port 53 Error on Listen"); + logDNSMess(logBuff, 1); + } else { + newNetwork.dnsTcpConn[i].server = newNetwork.listenServers[j]; + newNetwork.dnsTcpConn[i].port = IPPORT_DNS; + + newNetwork.dnsTcpConn[i].loaded = true; + newNetwork.dnsTcpConn[i].ready = true; + + if (newNetwork.maxFD < newNetwork.dnsTcpConn[i].sock) + newNetwork.maxFD = newNetwork.dnsTcpConn[i].sock; + + i++; + } + } + } + } + } + } + + if (dhcpService) { + for (MYBYTE m = 0; m < MAX_SERVERS && newNetwork.allServers[m]; m++) + lockIP(newNetwork.allServers[m]); + + for (MYBYTE m = 0; m < MAX_SERVERS && newNetwork.dns[m]; m++) + lockIP(newNetwork.dns[m]); + } + + if (bindfailed) + cfig.failureCount++; + else + cfig.failureCount = 0; + + closeConn(); + newNetwork.maxFD++; + memcpy(&network, &newNetwork, sizeof(data1)); + + //printf("%i %i %i\n", network.dhcpConn[0].ready, network.dnsUdpConn[0].ready, network.dnsTcpConn[0].ready); + + if ((dhcpService && !network.dhcpConn[0].ready) + || (dnsService && !(network.dnsUdpConn[0].ready && network.dnsTcpConn[0].ready))) { + sprintf(logBuff, "No Static Interface ready, Waiting..."); + logMess(logBuff, 1); + continue; + } + + if (dhcpService && network.httpConn.ready) { + sprintf(logBuff, + "Lease Status URL: http://%s:%u", + IP2String(ipbuff, network.httpConn.server), + network.httpConn.port); + logMess(logBuff, 1); + } + + for (int i = 0; i < MAX_SERVERS && network.listenServers[i]; i++) { + for (MYBYTE j = 0; j < MAX_SERVERS; j++) { + if (!network.dhcpConn[j].server && !network.dnsUdpConn[j].server) + break; + else if (network.dhcpConn[j].server == network.listenServers[i] + || network.dnsUdpConn[j].server == network.listenServers[i]) { + sprintf(logBuff, "Listening On: %s", IP2String(ipbuff, network.listenServers[i])); + logMess(logBuff, 1); + break; + } + } + } + + } while (kRunning && detectChange()); + + pthread_exit(nullptr); +} + +bool detectChange() { + char logBuff[256]; + network.ready = true; + network.readyForChange = false; + + while (kRunning) { + sleep(20); + //printf("Checking Networks (failue count=%u, failue cycle=%u)..\n", cfig.failureCount, cfig.failureCycle); + + if (cfig.failureCount) { + cfig.failureCycle++; + + if (kRunning && cfig.failureCycle == (MYDWORD)pow(2, cfig.failureCount)) { + sprintf(logBuff, "Retrying failed Listening Interfaces.."); + logMess(logBuff, 1); + break; + } + } else if (getInterfaces(&newNetwork)) { + memcpy(cfig.oldservers, newNetwork.allServers, (MAX_SERVERS * sizeof(MYDWORD))); + sprintf(logBuff, "Network changed, re-detecting Listening Interfaces.."); + logMess(logBuff, 1); + break; + } else + cfig.failureCycle = 0; + } + + network.ready = false; + + while (kRunning && !network.readyForChange) + sleep(1); + + return (kRunning); +} + +bool getInterfaces(data1 *netinfo) { + char logBuff[256]; + char ipbuff[32]; + memset(netinfo, 0, sizeof(data1)); + + Ifc.ifc_len = sizeof(IfcBuf); + Ifc.ifc_buf = (char *)IfcBuf; + + if (ioctl(cfig.fixedSocket, SIOCGIFCONF, &Ifc) >= 0) { + MYDWORD addr, mask; + short flags; + struct ifreq pIfr {}; + MYBYTE numInterfaces = Ifc.ifc_len / sizeof(ifreq); + + for (MYBYTE i = 0; i < numInterfaces; i++) { + memcpy(&pIfr, &(IfcBuf[i]), sizeof(ifreq)); + + if (!ioctl(cfig.fixedSocket, SIOCGIFADDR, &pIfr)) + addr = ((struct sockaddr_in *)&pIfr.ifr_addr)->sin_addr.s_addr; + else + addr = 0; + + if (!ioctl(cfig.fixedSocket, SIOCGIFNETMASK, &pIfr)) + mask = ((struct sockaddr_in *)&pIfr.ifr_addr)->sin_addr.s_addr; + else + mask = 0; + + if (!ioctl(cfig.fixedSocket, SIOCGIFFLAGS, &pIfr)) + flags = pIfr.ifr_flags; + else + flags = 0; + + if (addr && mask && (flags & IFF_RUNNING) && (flags & IFF_UP) && !(flags & IFF_LOOPBACK) + && !(flags & IFF_POINTOPOINT)) { + addServer(netinfo->allServers, MAX_SERVERS, addr); + + if (!(flags & IFF_DYNAMIC)) { + MYBYTE k = addServer(netinfo->staticServers, MAX_SERVERS, addr); + + if (k < MAX_SERVERS) + netinfo->staticMasks[k] = mask; + } + } + } + } + + if (!memcmp(cfig.oldservers, netinfo->allServers, (MAX_SERVERS * sizeof(MYDWORD)))) + return false; + + if (cfig.specifiedServers[0]) { + for (MYBYTE i = 0; i < MAX_SERVERS && cfig.specifiedServers[i]; i++) { + MYBYTE j = 0; + + for (; j < MAX_SERVERS && netinfo->staticServers[j]; j++) { + if (netinfo->staticServers[j] == cfig.specifiedServers[i]) { + MYBYTE k = addServer(netinfo->listenServers, MAX_SERVERS, netinfo->staticServers[j]); + + if (k < MAX_SERVERS) + netinfo->listenMasks[k] = netinfo->staticMasks[j]; + + break; + } + } + + if (j == MAX_SERVERS || !netinfo->staticServers[j]) { + if (findServer(netinfo->allServers, MAX_SERVERS, cfig.specifiedServers[i])) + sprintf(logBuff, + "Warning: Section [LISTEN_ON] Interface %s is not static, ignored", + IP2String(ipbuff, cfig.specifiedServers[i])); + else + sprintf(logBuff, + "Warning: Section [LISTEN_ON] Interface %s is not found, ignored", + IP2String(ipbuff, cfig.specifiedServers[i])); + + logMess(logBuff, 2); + } + } + } else { + for (MYBYTE i = 0; i < MAX_SERVERS && netinfo->allServers[i]; i++) { + MYBYTE j = 0; + + for (; j < MAX_SERVERS && netinfo->staticServers[j]; j++) { + if (netinfo->staticServers[j] == netinfo->allServers[i]) { + MYBYTE k = addServer(netinfo->listenServers, MAX_SERVERS, netinfo->staticServers[j]); + + if (k < MAX_SERVERS) + netinfo->listenMasks[k] = netinfo->staticMasks[j]; + + break; + } + } + + if (j == MAX_SERVERS || !netinfo->staticServers[j]) { + sprintf( + logBuff, "Warning: Interface %s is not Static, ignored", IP2String(ipbuff, netinfo->allServers[i])); + logMess(logBuff, 2); + } + } + } + + if (!cfig.zone[0]) { + getdomainname(cfig.zone, sizeof(cfig.zone)); + cfig.zLen = strlen(cfig.zone); + } + + if (dnsService) { + if (cfig.specifiedDnsServers[0]) { + for (int i = 0; i < MAX_SERVERS && cfig.specifiedDnsServers[i]; i++) { + if (!findServer(netinfo->allServers, MAX_SERVERS, cfig.specifiedDnsServers[i])) + addServer(netinfo->dns, MAX_SERVERS, cfig.specifiedDnsServers[i]); + } + } else { + FILE *f = fopen("/etc/resolv.conf", "rt"); + char buff[256]; + + while (f && fgets(buff, 255, f)) { + myTokenize(buff, buff, nullptr, true); + + if (!strcasecmp(myGetToken(buff, 0), "nameserver")) { + MYDWORD addr = inet_addr(myGetToken(buff, 1)); + + if (!findServer(netinfo->allServers, MAX_SERVERS, addr)) + addServer(netinfo->dns, MAX_SERVERS, addr); + } else if (!strcasecmp(myGetToken(buff, 0), "search")) { + if (!strncmp(cfig.zone, "(none)", 6) || !cfig.zone[0]) { + strcpy(cfig.zone, myGetToken(buff, 1)); + cfig.zLen = strlen(cfig.zone); + } + } + } + + if (f) + fclose(f); + } + } + + gethostname(cfig.servername, sizeof(cfig.servername)); + char *ptr = strchr(cfig.servername, '.'); + + if (ptr) { + *ptr = 0; + + if (!strncmp(cfig.zone, "(none)", 6) || !cfig.zone[0]) { + ptr++; + strcpy(cfig.zone, ptr); + cfig.zLen = strlen(cfig.zone); + } + } + + if (!strncmp(cfig.zone, "(none)", 6) || !cfig.zone[0]) { + strcpy(cfig.zone, "workgroup"); + cfig.zLen = strlen(cfig.zone); + } + + return true; +} + +void *updateStateFile(void *lparam) { + pthread_mutex_lock(&mutStateFile); + + auto *dhcpEntry = (data7 *)lparam; + data8 dhcpData{}; + memset(&dhcpData, 0, sizeof(data8)); + MYBYTE bp_hlen = 16; + getHexValue(dhcpData.bp_chaddr, dhcpEntry->mapname, &bp_hlen); + dhcpData.bp_hlen = bp_hlen; + dhcpData.ip = dhcpEntry->ip; + dhcpData.subnetFlg = dhcpEntry->subnetFlg; + dhcpData.expiry = dhcpEntry->expiry; + dhcpData.local = dhcpEntry->local; + strcpy(dhcpData.hostname, dhcpEntry->hostname); + + if (!dhcpEntry->dhcpInd) { + cfig.dhcpInd += 1; + dhcpEntry->dhcpInd = cfig.dhcpInd; + } + + dhcpData.dhcpInd = dhcpEntry->dhcpInd; + FILE *f = fopen(leaFile, "rb+"); + + if (f) { + if (fseek(f, (long)((dhcpData.dhcpInd - 1) * sizeof(data8)), SEEK_SET) >= 0) + fwrite(&dhcpData, sizeof(data8), 1, f); + + fclose(f); + } + + pthread_mutex_unlock(&mutStateFile); + pthread_exit(nullptr); +} + +MYWORD gdmess(data9 *req, MYBYTE sockInd) { + char ipbuff[16]; + char logBuff[256]; + memset(req, 0, sizeof(data9)); + errno = 0; + + if (sockInd == 255) { + int msgflags = 0; + req->iov[0].iov_base = req->raw; + req->iov[0].iov_len = sizeof(dhcp_packet); + req->msg.msg_iov = req->iov; + req->msg.msg_iovlen = 1; + req->msg.msg_name = &req->remote; + req->msg.msg_namelen = sizeof(sockaddr_in); + req->msg.msg_control = &req->msgcontrol; + req->msg.msg_controllen = sizeof(msg_control); + req->msg.msg_flags = msgflags; + + int flags = 0; + req->bytes = (int)recvmsg(network.dhcpListener.sock, &req->msg, flags); + + if (errno || req->bytes <= 0) + return 0; + + //printf("%u\n", req->msg.msg_controllen); + //msgcontrol = (msg_control*)msg.msg_control; + + //struct in_addr local_addr; + //struct in_addr rem_addr; + + //local_addr = msgcontrol->pktinfo.ipi_addr; + //rem_addr = msgcontrol->pktinfo.ipi_spec_dst; + + //printf("IF = %u\n", req->msgcontrol.pktinfo.ipi_ifindex); + //printf("LADDR = %s\n", inet_ntoa(req->msgcontrol.pktinfo.ipi_addr)); + //printf("RADDR = %s\n", inet_ntoa(req->msgcontrol. pktinfo.ipi_spec_dst)); + + MYDWORD addr = req->msgcontrol.pktinfo.ipi_spec_dst.s_addr; + + //printf("%s\n",IP2String(tempbuff, addr)); + + if (!addr) + return 0; + + for (int i = 0;; i++) { + if (i == MAX_SERVERS || !network.dhcpConn[i].server) + return 0; + else if (addr == network.dhcpConn[i].server) { + req->sockInd = i; + break; + } + } + } else { + req->sockInd = sockInd; + req->sockLen = sizeof(req->remote); + errno = 0; + + req->bytes = (int)recvfrom( + network.dhcpConn[sockInd].sock, req->raw, sizeof(dhcp_packet), 0, (sockaddr *)&req->remote, &req->sockLen); + + if (errno || req->bytes <= 0) + return 0; + } + + if (req->dhcpp.header.bp_op != BOOTP_REQUEST) + return 0; + + hex2String(req->chaddr, req->dhcpp.header.bp_chaddr, req->dhcpp.header.bp_hlen); + + data3 *op; + MYBYTE *raw = req->dhcpp.vend_data; + MYBYTE *rawEnd = raw + (req->bytes - sizeof(dhcp_header)); + + for (; raw < rawEnd && *raw != DHCP_OPTION_END;) { + op = (data3 *)raw; + //printf("OpCode=%u,MessType=%u\n", op->opt_code, op->value[0]); + + switch (op->opt_code) { + case DHCP_OPTION_PAD: + raw++; + continue; + + case DHCP_OPTION_PARAMREQLIST: + for (int ix = 0; ix < op->size; ix++) + req->paramreqlist[op->value[ix]] = 1; + break; + + case DHCP_OPTION_MESSAGETYPE: + req->req_type = op->value[0]; + break; + + case DHCP_OPTION_SERVERID: + req->server = fIP(op->value); + break; + + case DHCP_OPTION_IPADDRLEASE: + req->lease = fUInt(op->value); + break; + + case DHCP_OPTION_MAXDHCPMSGSIZE: + req->messsize = fUShort(op->value); + break; + + case DHCP_OPTION_REQUESTEDIPADDR: + req->reqIP = fIP(op->value); + break; + + case DHCP_OPTION_HOSTNAME: + memcpy(req->hostname, op->value, op->size); + req->hostname[op->size] = 0; + req->hostname[64] = 0; + + if (char *ptr = strchr(req->hostname, '.')) + *ptr = 0; + + break; + + case DHCP_OPTION_VENDORCLASSID: + memcpy(&req->vendClass, op, op->size + 2); + break; + + case DHCP_OPTION_USERCLASS: + memcpy(&req->userClass, op, op->size + 2); + break; + + case DHCP_OPTION_RELAYAGENTINFO: + memcpy(&req->agentOption, op, op->size + 2); + break; + + case DHCP_OPTION_CLIENTID: + memcpy(&req->clientId, op, op->size + 2); + break; + + case DHCP_OPTION_SUBNETSELECTION: + memcpy(&req->subnet, op, op->size + 2); + req->subnetIP = fIP(op->value); + break; + + case DHCP_OPTION_DNS: + req->dns = fIP(op->value); + break; + + case DHCP_OPTION_REBINDINGTIME: + req->rebind = fUInt(op->value); + break; + } + raw += 2; + raw += op->size; + } + + if (!req->subnetIP) + req->subnetIP = req->dhcpp.header.bp_giaddr; + + if (!req->messsize) { + if (req->req_type == DHCP_MESS_NONE) + req->messsize = req->bytes; + else + req->messsize = sizeof(dhcp_packet); + } + + // if (!req->hostname[0] && req->dhcpp.header.bp_ciaddr) + // { + // data7* cache = findDNSEntry(IP2String(ipbuff, htonl(req->dhcpp.header.bp_ciaddr)), DNS_TYPE_PTR); + // + // if (cache) + // strcpy(req->hostname, cache->hostname); + // } + // + // if ((req->req_type == 1 || req->req_type == 3) && cfig.dhcpLogLevel == 3) + // { + // data9 *req1 = (data9*)calloc(1, sizeof(data9)); + // memcpy(req1, req, sizeof(data9)); + // } + + if (verbatim || cfig.dhcpLogLevel >= 2) { + if (req->req_type == DHCP_MESS_NONE) { + if (req->dhcpp.header.bp_giaddr) + sprintf(logBuff, + "BOOTPREQUEST for %s (%s) from RelayAgent %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, req->dhcpp.header.bp_giaddr)); + else + sprintf(logBuff, + "BOOTPREQUEST for %s (%s) from interface %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, network.dhcpConn[req->sockInd].server)); + + logDHCPMess(logBuff, 2); + } else if (req->req_type == DHCP_MESS_DISCOVER) { + if (req->dhcpp.header.bp_giaddr) + sprintf(logBuff, + "DHCPDISCOVER for %s (%s) from RelayAgent %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, req->dhcpp.header.bp_giaddr)); + else + sprintf(logBuff, + "DHCPDISCOVER for %s (%s) from interface %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, network.dhcpConn[req->sockInd].server)); + + logDHCPMess(logBuff, 2); + } else if (req->req_type == DHCP_MESS_REQUEST) { + if ((!req->server) || req->server == network.dhcpConn[req->sockInd].server) { + if (req->dhcpp.header.bp_giaddr) + sprintf(logBuff, + "DHCPREQUEST for %s (%s) from RelayAgent %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, req->dhcpp.header.bp_giaddr)); + else + sprintf(logBuff, + "DHCPREQUEST for %s (%s) from interface %s received", + req->chaddr, + req->hostname, + IP2String(ipbuff, network.dhcpConn[req->sockInd].server)); + + logDHCPMess(logBuff, 2); + } + } + } + + req->vp = req->dhcpp.vend_data; + memset(req->vp, 0, sizeof(dhcp_packet) - sizeof(dhcp_header)); + //printf("end bytes=%u\n", req->bytes); + + return 1; +} + +void logDHCPMess(const char *title, const char *mess) { + char t1[512]; + sprintf(t1, "%s %s", title, mess); + logDHCPMess(t1, 1); +} + +void logMess(const char *title, const char *mess) { + char t1[512]; + sprintf(t1, "%s %s", title, mess); + logMess(t1, 1); +} + +#if 0 +void debug(const char *mess) { + char t1[254]; + sprintf(t1, "%s", mess); + logMess(t1, 1); +} + +void debug(const char *title, int i) { + char t1[254]; + sprintf(t1, "%s: %i", title, i); + logMess(t1, 1); +} + +void debug(const char *title, const char *mess) { + char t1[254]; + sprintf(t1, "%s: %s", title, mess); + logMess(t1, 1); +} +#endif +void *logThread(void *lpParam) { + pthread_mutex_lock(&mutLogFile); + char *mess = (char *)lpParam; + time_t local_t = time(nullptr); + tm *ttm = localtime(&local_t); + char buffer[256]; + strftime(buffer, sizeof(buffer), logFile, ttm); + + if (strcmp(cfig.logFileName, buffer) != 0) { + if (cfig.logFileName[0]) { + FILE *f = fopen(cfig.logFileName, "at"); + + if (f) { + fprintf(f, "Logging Continued on file %s\n", buffer); + fclose(f); + } + + strcpy(cfig.logFileName, buffer); + f = fopen(cfig.logFileName, "at"); + + if (f) { + fprintf(f, "%s\n\n", sVersion); + fclose(f); + } + } + + strcpy(cfig.logFileName, buffer); + } + + FILE *f = fopen(cfig.logFileName, "at"); + + if (f) { + strftime(buffer, sizeof(buffer), "%d-%b-%y %X", ttm); + fprintf(f, "[%s] %s\n", buffer, mess); + fclose(f); + } else if (verbatim) { + printf("Failed top open log file %s", cfig.logFileName); + cfig.dhcpLogLevel = 0; + } else { + syslog(LOG_MAKEPRI(LOG_LOCAL1, LOG_CRIT), "Failed top open log file %s", cfig.logFileName); + cfig.dhcpLogLevel = 0; + } + + free(mess); + pthread_mutex_unlock(&mutLogFile); + pthread_exit(nullptr); +} + +void logMess(char *logBuff, MYBYTE logLevel) { + if (verbatim) + printf("%s\n", logBuff); + + if (logFile[0] && (logLevel <= cfig.dnsLogLevel || logLevel <= cfig.dhcpLogLevel)) { + char *mess = cloneString(logBuff); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, logThread, mess); + pthread_attr_destroy(&attr); + } +} + +void logDHCPMess(char *logBuff, MYBYTE logLevel) { + if (verbatim) + printf("%s\n", logBuff); + + if (logFile[0] && logLevel <= cfig.dhcpLogLevel) { + char *mess = cloneString(logBuff); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, logThread, mess); + pthread_attr_destroy(&attr); + } +} + +void logDNSMess(char *logBuff, MYBYTE logLevel) { + if (verbatim) + printf("%s\n", logBuff); + + if (logFile[0] && logLevel <= cfig.dnsLogLevel) { + char *mess = cloneString(logBuff); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, logThread, mess); + pthread_attr_destroy(&attr); + } +} + +void logDNSMess(data5 *req, char *logBuff, MYBYTE logLevel) { + if (verbatim) + printf("%s\n", logBuff); + + if (logFile[0] && logLevel <= cfig.dnsLogLevel) { + char *mess = (char *)calloc(1, 512); + sprintf(mess, "Client %s, %s", inet_ntoa(req->remote.sin_addr), logBuff); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, logThread, mess); + pthread_attr_destroy(&attr); + } +} + +void logTCPMess(data5 *req, char *logBuff, MYBYTE logLevel) { + if (verbatim) + printf("%s\n", logBuff); + + if (logFile[0] && logLevel <= cfig.dnsLogLevel) { + char *mess = (char *)calloc(1, 512); + sprintf(mess, "TCP Client %s, %s", inet_ntoa(req->remote.sin_addr), logBuff); + pthread_t threadId; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int errcode = pthread_create(&threadId, &attr, logThread, mess); + pthread_attr_destroy(&attr); + } +} + +data7 *createCache(data71 *pLump) { + if (!pLump->mapname || !pLump->cacheType) + return nullptr; + + MYWORD dataSize = 5 + sizeof(data7) + strlen(pLump->mapname); + data7 *cache = nullptr; + + switch (pLump->cacheType) { + case CTYPE_DHCP_ENTRY: { + dataSize += 64; + dataSize += pLump->optionSize; + cache = (data7 *)calloc(1, dataSize); + + if (!cache) + return nullptr; + + MYBYTE *dp = &cache->data; + cache->mapname = (char *)dp; + strcpy(cache->mapname, pLump->mapname); + myLower(cache->mapname); + dp += strlen(cache->mapname); + dp++; + cache->hostname = (char *)dp; + + if (pLump->hostname) + strcpy(cache->hostname, pLump->hostname); + + dp += 65; + + if (pLump->options && pLump->optionSize >= 3) { + cache->options = dp; + memcpy(cache->options, pLump->options, pLump->optionSize); + } + break; + } + + case CTYPE_QUEUE: { + //debug("about to create queue"); + dataSize += strlen(pLump->query); + dataSize += sizeof(SOCKADDR_IN); + cache = (data7 *)calloc(1, dataSize); + + if (!cache) + return nullptr; + + cache->cacheType = pLump->cacheType; + cache->dnsType = pLump->dnsType; + MYBYTE *dp = &cache->data; + cache->mapname = (char *)dp; + cache->name = (char *)dp; + strcpy(cache->mapname, pLump->mapname); + //myLower(cache->mapname); + dp += strlen(cache->mapname); + dp++; + cache->query = (char *)dp; + strcpy(cache->query, pLump->query); + //debug(cache->query); + //debug(strlen(cache->query)); + dp += strlen(cache->query); + dp++; + //debug((int)pLump->addr); + cache->addr = (SOCKADDR_IN *)dp; + memcpy(cache->addr, pLump->addr, sizeof(SOCKADDR_IN)); + //debug("done create queue"); + break; + } + + case CTYPE_CACHED: { + dataSize += pLump->bytes; + cache = (data7 *)calloc(1, dataSize); + + if (!cache) + return nullptr; + + cache->cacheType = pLump->cacheType; + cache->dnsType = pLump->dnsType; + MYBYTE *dp = &cache->data; + cache->mapname = (char *)dp; + setMapName(cache->mapname, pLump->mapname, pLump->dnsType); + dp++; + cache->name = (char *)dp; + dp += strlen(pLump->mapname); + dp++; + cache->response = dp; + cache->bytes = pLump->bytes; + memcpy(cache->response, pLump->response, cache->bytes); + break; + } + + case CTYPE_LOCAL_PTR_AUTH: + case CTYPE_LOCAL_PTR_NAUTH: + case CTYPE_LOCALHOST_PTR: + case CTYPE_SERVER_PTR_AUTH: + case CTYPE_SERVER_PTR_NAUTH: + case CTYPE_STATIC_PTR_AUTH: + case CTYPE_STATIC_PTR_NAUTH: + case CTYPE_LOCAL_CNAME: + case CTYPE_EXT_CNAME: { + dataSize += strlen(pLump->mapname); + dataSize += strlen(pLump->hostname); + cache = (data7 *)calloc(1, dataSize); + + if (!cache) + return nullptr; + + cache->cacheType = pLump->cacheType; + cache->dnsType = pLump->dnsType; + MYBYTE *dp = &cache->data; + cache->mapname = (char *)dp; + setMapName(cache->mapname, pLump->mapname, pLump->dnsType); + dp += strlen(pLump->mapname); + dp += 2; + cache->name = (char *)dp; + strcpy(cache->name, pLump->mapname); + dp += strlen(pLump->mapname); + dp++; + cache->hostname = (char *)dp; + strcpy(cache->hostname, pLump->hostname); + break; + } + + default: { + dataSize += strlen(pLump->mapname); + cache = (data7 *)calloc(1, dataSize); + + if (!cache) + return nullptr; + + cache->cacheType = pLump->cacheType; + cache->dnsType = pLump->dnsType; + MYBYTE *dp = &cache->data; + cache->mapname = (char *)dp; + setMapName(cache->mapname, pLump->mapname, pLump->dnsType); + dp += strlen(pLump->mapname); + dp += 2; + cache->name = (char *)dp; + strcpy(cache->name, pLump->mapname); + break; + } + } + /* + if (pLump->cacheType != CTYPE_DHCP_ENTRY) + { + char logBuff[256]; + sprintf(logBuff, "New Cache %p datasize=%d cacheType=%d dnsType=%u name=%s hostname=%s", cache, dataSize, cache->cacheType, cache->dnsType, cache->name, cache->hostname); + logMess(logBuff, 1); + } +*/ + return cache; +} + +#pragma clang diagnostic pop \ No newline at end of file diff --git a/srcs/dual_server/dualserverd.h b/srcs/dual_server/dualserverd.h new file mode 100644 index 0000000..673f3be --- /dev/null +++ b/srcs/dual_server/dualserverd.h @@ -0,0 +1,1121 @@ +/************************************************************************** +* Copyright (C) 2005 by Achal Dhir * +* achaldhir@gmail.com * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +//This file defines all structures and constants +//for both DHCP and DNS Servers +#define MAX_SERVERS 125 +#define MAX_DHCP_RANGES 125 +#define MAX_DNS_RANGES 32 +#define MAX_RANGE_SETS 125 +#define MAX_RANGE_FILTERS 32 +#define MAX_COND_FORW 125 +#define MAX_TCP_CLIENTS 16 +#define MAX_WILD_HOSTS 256 + +#ifndef LOG_MAKEPRI +#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) +#endif + +#ifndef SIOCGIFCONF +#include +#endif + +#ifndef _UIO_H_ +#include +#endif + +/* +//#ifndef _LINUX_IN_H +//#ifndef _NETINET_IN_H +struct in_pktinfo +{ + unsigned int ipi_ifindex; // Interface index + struct in_addr ipi_spec_dst; // Local address + struct in_addr ipi_addr; // Header Destination address +}; +typedef struct in_pktinfo IN_PKTINFO; +//#endif +//#endif +*/ + +#ifndef INADDR_NONE +#define INADDR_NONE UINT_MAX +#endif + +#ifndef IFF_DYNAMIC +#define IFF_DYNAMIC 0x8000 +#endif + +#define MYWORD unsigned short +#define MYBYTE unsigned char +#define MYDWORD unsigned int +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#define SOCKADDR_IN sockaddr_in +#define SOCKADDR sockaddr +#define SOCKET int +#define BOOL bool +#define LPSOCKADDR sockaddr* +#define closesocket close + +#define RCODE_NOERROR 0 +#define RCODE_FORMATERROR 1 +#define RCODE_SERVERFAIL 2 +#define RCODE_NAMEERROR 3 +#define RCODE_NOTIMPL 4 +#define RCODE_REFUSED 5 +#define RCODE_YXDOMAIN 6 +#define RCODE_YXRRSET 7 +#define RCODE_NXRRSET 8 +#define RCODE_NOTAUTH 9 +#define RCODE_NOTZONE 10 + +#define OPCODE_STANDARD_QUERY 0 +#define OPCODE_INVERSE_QUERY 1 +#define OPCODE_SRVR_STAT_REQ 2 +#define OPCODE_NOTIFY 4 +#define OPCODE_DYNAMIC_UPDATE 5 + +#define DNS_TYPE_A 1 +#define DNS_TYPE_NS 2 +#define DNS_TYPE_MD 3 +#define DNS_TYPE_MF 4 +#define DNS_TYPE_CNAME 5 +#define DNS_TYPE_SOA 6 +#define DNS_TYPE_MB 7 +#define DNS_TYPE_MG 8 +#define DNS_TYPE_MR 9 +#define DNS_TYPE_NULL 10 +#define DNS_TYPE_WKS 11 +#define DNS_TYPE_PTR 12 +#define DNS_TYPE_HINFO 13 +#define DNS_TYPE_MINFO 14 +#define DNS_TYPE_MX 15 +#define DNS_TYPE_TXT 16 +#define DNS_TYPE_AAAA 28 +#define DNS_TYPE_IXFR 251 +#define DNS_TYPE_AXFR 252 +#define DNS_TYPE_MAILB 253 +#define DNS_TYPE_MAILA 254 +#define DNS_TYPE_ANY 255 + +#define DNS_CLASS_IN 1 +#define DNS_CLASS_CS 2 +#define DNS_CLASS_CH 3 +#define DNS_CLASS_HS 4 +#define DNS_CLASS_NONE 254 +#define DNS_CLASS_ANY 255 + +#define IPPORT_DNS 53 + +enum +{ + CTYPE_NONE, + CTYPE_DHCP_ENTRY, + CTYPE_LOCAL_A, + CTYPE_LOCAL_PTR_AUTH, + CTYPE_LOCAL_PTR_NAUTH, + CTYPE_LOCALHOST_A, + CTYPE_LOCALHOST_PTR, + CTYPE_SERVER_A_AUTH, + CTYPE_SERVER_PTR_AUTH, + CTYPE_SERVER_A_NAUTH, + CTYPE_SERVER_PTR_NAUTH, + CTYPE_LOCAL_CNAME, + CTYPE_EXT_CNAME, + CTYPE_STATIC_A_AUTH, + CTYPE_STATIC_PTR_AUTH, + CTYPE_STATIC_A_NAUTH, + CTYPE_STATIC_PTR_NAUTH, + CTYPE_NS, + CTYPE_SOA, + CTYPE_AXFR, + CTYPE_CACHED, + CTYPE_NON_CACHED, + CTYPE_QUEUE, + CTYPE_DNS_CHECK, + QTYPE_IP, + QTYPE_HOSTNAME, + QTYPE_A_EXT, + QTYPE_A_BARE, + QTYPE_A_LOCAL, + QTYPE_A_ZONE, + QTYPE_P_EXT, + QTYPE_P_LOCAL, + QTYPE_P_ZONE, + QTYPE_A_SUBZONE, + QTYPE_P_SUBZONE, + QTYPE_CHILDZONE +}; + +#if defined(__hppa__) || \ + defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ + (defined(__MIPS__) && defined(__MISPEB__)) || \ + defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ + defined(__sparc__) +struct dnsHeader +{ + unsigned xid :16; //query identification number + /* byte boundry */ + unsigned qr: 1; //response flag + unsigned opcode: 4; //option code + unsigned aa: 1; //authoritive answer + unsigned tc: 1; //truncated message + unsigned rd: 1; //recursion desired + /* byte boundry */ + unsigned ra: 1; //recursion available + unsigned unused :1; //unused + unsigned at: 1; //authentic data from named + unsigned cd: 1; //checking disabled by resolver + unsigned rcode :4; //response code + /* byte boundry */ + union + { + struct + { + unsigned qdcount :16; //number of question entries + unsigned ancount :16; //number of answer entries + unsigned nscount :16; //number of authority entries + unsigned adcount :16; //number of additional entries + }; + struct + { + unsigned zcount :16; //number of question entries + unsigned prcount :16; //number of answer entries + unsigned ucount :16; //number of authority entries + unsigned arcount :16; //number of additional entries + }; + }; +}; +#else +struct dnsHeader +{ + unsigned xid :16; //query identification number + /* byte boundry */ + unsigned rd: 1; //recursion desired + unsigned tc: 1; //truncated message + unsigned aa: 1; //authoritive answer + unsigned opcode: 4; //option code + unsigned qr: 1; //response flag + /* byte boundry */ + unsigned rcode :4; //response code + unsigned cd: 1; //checking disabled by resolver + unsigned at: 1; //authentic data from named + unsigned unused :1; //unused + unsigned ra: 1; //recursion available + /* byte boundry */ + union + { + struct + { + unsigned qdcount :16; //number of question entries + unsigned ancount :16; //number of answer entries + unsigned nscount :16; //number of authority entries + unsigned adcount :16; //number of additional entries + }; + struct + { + unsigned zcount :16; //number of question entries + unsigned prcount :16; //number of answer entries + unsigned ucount :16; //number of authority entries + unsigned arcount :16; //number of additional entries + }; + }; +}; +#endif + +struct dnsPacket +{ + struct dnsHeader header; + char data; +}; + +struct data10 +{ + char zone[256]; + MYWORD zLen; + MYDWORD dns[2]; + MYBYTE currentDNS; + MYBYTE lastDNS; +}; + +struct data18 +{ + MYBYTE currentInd; + bool done; +}; + +struct data16 +{ + char wildcard[256]; + MYDWORD ip; +}; + +struct data7 //cache +{ + char *mapname; + time_t expiry; + union + { + struct + { + MYBYTE cacheType; + MYBYTE dnsType; + MYBYTE sockInd; + MYBYTE dnsIndex; + }; + struct + { + unsigned fixed: 1; + unsigned local: 1; + unsigned display: 1; + unsigned subnetFlg: 1; + signed rangeInd: 8; + unsigned dhcpInd: 20; + }; + }; + union + { + char *name; + MYBYTE *options; + }; + union + { + int bytes; + MYDWORD ip; + SOCKADDR_IN *addr; + }; + union + { + MYBYTE *response; + char *hostname; + char *query; + }; + MYBYTE data; +}; + +struct data71 //Lump +{ + char *mapname; + MYBYTE *response; + char *hostname; + char *query; + SOCKADDR_IN *addr; + MYBYTE *options; + MYWORD optionSize; + int bytes; + MYBYTE cacheType; + MYBYTE dnsType; +}; + +typedef multimap hostMap; +typedef std::map dhcpMap; +typedef multimap expiryMap; + +struct data5 //dns request +{ + dnsPacket *dnsp; + char *dp; + char raw[2048]; + char extbuff[264]; + char query[256]; + char cname[256]; + char mapname[256]; + char tempname[512]; + MYWORD qLen; + hostMap::iterator iterBegin; + SOCKET sock; + SOCKADDR_IN addr; + SOCKADDR_IN remote; + socklen_t sockLen; + linger ling; + int bytes; + MYWORD qclass; + MYBYTE dnsType; + MYBYTE qType; + MYBYTE cacheType; + MYBYTE sockInd; + MYBYTE dnsIndex; + MYBYTE respType; +}; + +struct data12 //dns range +{ + MYDWORD rangeStart; + MYDWORD rangeEnd; +}; + +struct dns_rr +{ + char *name; + MYWORD type, _class; + MYDWORD ttl; + MYWORD rdlength; + char *rdata; + union { + struct + { + long address; + } a; + struct + { + char *cname; + } cname; + struct + { + char *cpu, *os; + } hinfo; + struct + { + char *madname; + } mb; + struct + { + char *madname; + } md; + struct + { + char *madname; + } mf; + struct + { + char *mgmname; + } mg; + struct + { + char *rmailbx, *emailbx; + } minfo; + struct + { + char *newname; + } mr; + struct + { + int preference; + char *exchange; + } mx; + struct + { + char *nsdname; + } ns; + struct + { + char *data; + } null; + struct + { + char *ptrdname; + } ptr; + struct + { + char *mname, *rname; + unsigned serial, refresh, retry, expire, minimum; + } soa; + struct + { + char **txt_data; + } txt; + struct + { + int address; + MYBYTE protocol; + int bitmapsize; + char *bitmap; + } wks; + } data; +}; + +struct data11 +{ + char hostname[256]; + MYWORD pref; +}; + +struct ConnType +{ + SOCKET sock; + SOCKADDR_IN addr; + MYDWORD server; + MYWORD port; + bool loaded; + bool ready; +}; + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define DHCP_MESS_NONE 0 +#define DHCP_MESS_DISCOVER 1 +#define DHCP_MESS_OFFER 2 +#define DHCP_MESS_REQUEST 3 +#define DHCP_MESS_DECLINE 4 +#define DHCP_MESS_ACK 5 +#define DHCP_MESS_NAK 6 +#define DHCP_MESS_RELEASE 7 +#define DHCP_MESS_INFORM 8 + + +// DHCP OPTIONS +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_NETMASK 1 +#define DHCP_OPTION_TIMEOFFSET 2 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_TIMESERVER 4 +#define DHCP_OPTION_NAMESERVER 5 +#define DHCP_OPTION_DNS 6 +#define DHCP_OPTION_LOGSERVER 7 +#define DHCP_OPTION_COOKIESERVER 8 +#define DHCP_OPTION_LPRSERVER 9 +#define DHCP_OPTION_IMPRESSSERVER 10 +#define DHCP_OPTION_RESLOCSERVER 11 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_BOOTFILESIZE 13 +#define DHCP_OPTION_MERITDUMP 14 +#define DHCP_OPTION_DOMAINNAME 15 +#define DHCP_OPTION_SWAPSERVER 16 +#define DHCP_OPTION_ROOTPATH 17 +#define DHCP_OPTION_EXTSPATH 18 +#define DHCP_OPTION_IPFORWARD 19 +#define DHCP_OPTION_NONLOCALSR 20 +#define DHCP_OPTION_POLICYFILTER 21 +#define DHCP_OPTION_MAXREASSEMBLE 22 +#define DHCP_OPTION_IPTTL 23 +#define DHCP_OPTION_PATHMTUAGING 24 +#define DHCP_OPTION_PATHMTUPLATEAU 25 +#define DHCP_OPTION_INTERFACEMTU 26 +#define DHCP_OPTION_SUBNETSLOCAL 27 +#define DHCP_OPTION_BCASTADDRESS 28 +#define DHCP_OPTION_MASKDISCOVERY 29 +#define DHCP_OPTION_MASKSUPPLIER 30 +#define DHCP_OPTION_ROUTERDISCOVERY 31 +#define DHCP_OPTION_ROUTERSOLIC 32 +#define DHCP_OPTION_STATICROUTE 33 +#define DHCP_OPTION_TRAILERENCAPS 34 +#define DHCP_OPTION_ARPTIMEOUT 35 +#define DHCP_OPTION_ETHERNETENCAPS 36 +#define DHCP_OPTION_TCPTTL 37 +#define DHCP_OPTION_TCPKEEPALIVEINT 38 +#define DHCP_OPTION_TCPKEEPALIVEGRBG 39 +#define DHCP_OPTION_NISDOMAIN 40 +#define DHCP_OPTION_NISSERVERS 41 +#define DHCP_OPTION_NTPSERVERS 42 +#define DHCP_OPTION_VENDORSPECIFIC 43 +#define DHCP_OPTION_NETBIOSNAMESERV 44 +#define DHCP_OPTION_NETBIOSDGDIST 45 +#define DHCP_OPTION_NETBIOSNODETYPE 46 +#define DHCP_OPTION_NETBIOSSCOPE 47 +#define DHCP_OPTION_X11FONTS 48 +#define DHCP_OPTION_X11DISPLAYMNGR 49 +#define DHCP_OPTION_REQUESTEDIPADDR 50 +#define DHCP_OPTION_IPADDRLEASE 51 +#define DHCP_OPTION_OVERLOAD 52 +#define DHCP_OPTION_MESSAGETYPE 53 +#define DHCP_OPTION_SERVERID 54 +#define DHCP_OPTION_PARAMREQLIST 55 +#define DHCP_OPTION_MESSAGE 56 +#define DHCP_OPTION_MAXDHCPMSGSIZE 57 +#define DHCP_OPTION_RENEWALTIME 58 +#define DHCP_OPTION_REBINDINGTIME 59 +#define DHCP_OPTION_VENDORCLASSID 60 +#define DHCP_OPTION_CLIENTID 61 +#define DHCP_OPTION_NETWARE_IPDOMAIN 62 +#define DHCP_OPTION_NETWARE_IPOPTION 63 +#define DHCP_OPTION_NISPLUSDOMAIN 64 +#define DHCP_OPTION_NISPLUSSERVERS 65 +#define DHCP_OPTION_TFTPSERVER 66 +#define DHCP_OPTION_BOOTFILE 67 +#define DHCP_OPTION_MOBILEIPHOME 68 +#define DHCP_OPTION_SMTPSERVER 69 +#define DHCP_OPTION_POP3SERVER 70 +#define DHCP_OPTION_NNTPSERVER 71 +#define DHCP_OPTION_WWWSERVER 72 +#define DHCP_OPTION_FINGERSERVER 73 +#define DHCP_OPTION_IRCSERVER 74 +#define DHCP_OPTION_STSERVER 75 +#define DHCP_OPTION_STDASERVER 76 +#define DHCP_OPTION_USERCLASS 77 +#define DHCP_OPTION_SLPDIRAGENT 78 +#define DHCP_OPTION_SLPDIRSCOPE 79 +#define DHCP_OPTION_CLIENTFQDN 81 +#define DHCP_OPTION_RELAYAGENTINFO 82 +#define DHCP_OPTION_I_SNS 83 +#define DHCP_OPTION_NDSSERVERS 85 +#define DHCP_OPTION_NDSTREENAME 86 +#define DHCP_OPTION_NDSCONTEXT 87 +#define DHCP_OPTION_AUTHENTICATION 90 +#define DHCP_OPTION_CLIENTSYSTEM 93 +#define DHCP_OPTION_CLIENTNDI 94 +#define DHCP_OPTION_LDAP 95 +#define DHCP_OPTION_UUID_GUID 97 +#define DHCP_OPTION_USER_AUTH 98 +#define DHCP_OPTION_P_CODE 100 +#define DHCP_OPTION_T_CODE 101 +#define DHCP_OPTION_NETINFOADDRESS 112 +#define DHCP_OPTION_NETINFOTAG 113 +#define DHCP_OPTION_URL 114 +#define DHCP_OPTION_AUTO_CONFIG 116 +#define DHCP_OPTION_NAMESERVICESEARCH 117 +#define DHCP_OPTION_SUBNETSELECTION 118 +#define DHCP_OPTION_DOMAINSEARCH 119 +#define DHCP_OPTION_SIPSERVERSDHCP 120 +#define DHCP_OPTION_CLASSLESSSTATICROUTE 121 +#define DHCP_OPTION_CCC 122 +#define DHCP_OPTION_GEOCONF 123 +#define DHCP_OPTION_V_IVENDORCLASS 124 +#define DHCP_OPTION_V_IVENDOR_SPECIFIC 125 +#define DHCP_OPTION_TFPTSERVERIPADDRESS 128 +#define DHCP_OPTION_CALLSERVERIPADDRESS 129 +#define DHCP_OPTION_DISCRIMINATIONSTRING 130 +#define DHCP_OPTION_REMOTESTATISTICSSERVER 131 +#define DHCP_OPTION_802_1PVLANID 132 +#define DHCP_OPTION_802_1QL2PRIORITY 133 +#define DHCP_OPTION_DIFFSERVCODEPOINT 134 +#define DHCP_OPTION_HTTPPROXYFORPHONE_SPEC 135 +#define DHCP_OPTION_SERIAL 252 +#define DHCP_OPTION_BP_FILE 253 +#define DHCP_OPTION_NEXTSERVER 254 +#define DHCP_OPTION_END 255 + +//#define DHCP_VENDORDATA_SIZE 272 +//#define DHCP_VENDORDATA_SIZE 64 +//#define DHCP_VENDORDATA_SIZE 784 +//#define DHCP_PACKET_SIZE 1024 +//#define DHCP_MIN_SIZE 44 +//#define DHCP_MAX_CLIENTS 254 +#define IPPORT_DHCPS 67 +#define IPPORT_DHCPC 68 +#define VM_STANFORD 0x5354414EUL +#define VM_RFC1048 0x63825363UL + +struct data3 +{ + MYBYTE opt_code; + MYBYTE size; + MYBYTE value[256]; +}; + +struct data4 +{ + char opName[40]; + MYBYTE opTag; + MYBYTE opType; + bool required; +}; + +struct data13 //dhcp range +{ + MYBYTE rangeSetInd; + MYDWORD rangeStart; + MYDWORD rangeEnd; + MYDWORD mask; + MYBYTE *options; + time_t *expiry; + data7 **dhcpEntry; +}; + +struct data14 //rangeSet +{ + MYBYTE active; + MYBYTE *macStart[MAX_RANGE_FILTERS]; + MYBYTE *macEnd[MAX_RANGE_FILTERS]; + MYBYTE macSize[MAX_RANGE_FILTERS]; + MYBYTE *vendClass[MAX_RANGE_FILTERS]; + MYBYTE vendClassSize[MAX_RANGE_FILTERS]; + MYBYTE *userClass[MAX_RANGE_FILTERS]; + MYBYTE userClassSize[MAX_RANGE_FILTERS]; + MYDWORD subnetIP[MAX_RANGE_FILTERS]; + MYDWORD targetIP; +}; + +struct data17 +{ + MYBYTE macArray[MAX_RANGE_SETS]; + MYBYTE vendArray[MAX_RANGE_SETS]; + MYBYTE userArray[MAX_RANGE_SETS]; + MYBYTE subnetArray[MAX_RANGE_SETS]; + bool macFound; + bool vendFound; + bool userFound; + bool subnetFound; +}; + +struct data19 +{ + SOCKET sock; + SOCKADDR_IN remote; + socklen_t sockLen; + linger ling; + int bytes; + int memSize; + char contentType[32]; + char *dp; +}; + +struct msg_control +{ + ulong cmsg_len; + int cmsg_level; + int cmsg_type; + in_pktinfo pktinfo; +}; + +#if defined(__hppa__) || \ + defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ + (defined(__MIPS__) && defined(__MISPEB__)) || \ + defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ + defined(__sparc__) + +struct dhcp_header +{ + MYBYTE bp_op; + MYBYTE bp_htype; + MYBYTE bp_hlen; + MYBYTE bp_hops; + MYDWORD bp_xid; + struct + { + unsigned bp_secs:16; + unsigned bp_broadcast:1; + unsigned bp_spare:7; + unsigned bp_spare1:8; + }; + MYDWORD bp_ciaddr; + MYDWORD bp_yiaddr; + MYDWORD bp_siaddr; + MYDWORD bp_giaddr; + MYBYTE bp_chaddr[16]; + char bp_sname[64]; + MYBYTE bp_file[128]; + MYBYTE bp_magic_num[4]; +}; + +#else + +struct dhcp_header +{ + MYBYTE bp_op; + MYBYTE bp_htype; + MYBYTE bp_hlen; + MYBYTE bp_hops; + MYDWORD bp_xid; + struct + { + unsigned bp_secs:16; + unsigned bp_spare:7; + unsigned bp_broadcast:1; + unsigned bp_spare1:8; + }; + MYDWORD bp_ciaddr; + MYDWORD bp_yiaddr; + MYDWORD bp_siaddr; + MYDWORD bp_giaddr; + MYBYTE bp_chaddr[16]; + char bp_sname[64]; + MYBYTE bp_file[128]; + MYBYTE bp_magic_num[4]; +}; +#endif + +struct dhcp_packet +{ + dhcp_header header; + MYBYTE vend_data[1024 - sizeof(dhcp_header)]; +}; + +struct data20 +{ + MYBYTE options[sizeof(dhcp_packet)]; + MYWORD optionSize; + MYDWORD ip; + MYDWORD mask; + MYBYTE rangeSetInd; +}; + +struct data9 //dhcpRequst +{ + MYDWORD lease; + union + { + char raw[sizeof(dhcp_packet)]; + dhcp_packet dhcpp; + }; + char hostname[256]; + char chaddr[64]; + MYDWORD server; + MYDWORD reqIP; + int bytes; + SOCKADDR_IN remote; + socklen_t sockLen; + MYWORD messsize; + MYBYTE *vp; + data7 *dhcpEntry; + data3 agentOption; + data3 clientId; + data3 subnet; + data3 vendClass; + data3 userClass; + MYDWORD subnetIP; + MYDWORD targetIP; + MYDWORD rebind; + MYDWORD dns; + msghdr msg; + iovec iov[1]; + msg_control msgcontrol; + MYBYTE paramreqlist[256]; + MYBYTE opAdded[256]; + MYBYTE req_type; + MYBYTE resp_type; + MYBYTE sockInd; +}; + +struct DhcpConnType +{ + SOCKET sock; + SOCKADDR_IN addr; + MYDWORD server; + MYWORD port; + bool loaded; + bool ready; + MYDWORD mask; + int reUseVal; + int reUseSize; + union + { + int broadCastVal; + bool pktinfoVal; + }; + union + { + int broadCastSize; + unsigned int pktinfoSize; + }; +}; + +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define MY_MAX_TIME UINT_MAX +#define MY_EXE_SIZE "64bit" +struct data8 //client +{ + union + { + MYDWORD filler; + struct + { + unsigned dhcpInd: 20; + unsigned bp_hlen: 8; + unsigned fixed: 1; + unsigned local: 1; + unsigned display: 1; + unsigned subnetFlg: 1; + }; + }; + MYDWORD ip; + time_t expiry; + MYBYTE bp_chaddr[16]; + char hostname[64]; +}; +#else +#define MY_MAX_TIME INT_MAX +#define MY_EXE_SIZE "32bit" +struct data8 //client +{ + union + { + MYDWORD filler; + struct + { + unsigned dhcpInd: 20; + unsigned bp_hlen: 8; + unsigned fixed: 1; + unsigned local: 1; + unsigned display: 1; + unsigned subnetFlg: 1; + }; + }; + MYDWORD ip; + time_t expiry; + MYDWORD filler1; + MYBYTE bp_chaddr[16]; + char hostname[64]; +}; +#endif + +/* +struct data8 //client +{ + MYWORD dhcpInd; + MYBYTE bp_hlen; + unsigned local: 8; + unsigned source: 16; + unsigned ip: 32; + unsigned expiry: 32; + MYBYTE bp_chaddr[16]; + char hostname[64]; +}; +*/ + +struct data1 +{ + DhcpConnType dhcpListener; + DhcpConnType dhcpConn[MAX_SERVERS]; + ConnType dnsUdpConn[MAX_SERVERS]; + ConnType forwConn; + ConnType dnsTcpConn[MAX_SERVERS]; + ConnType httpConn; + MYDWORD allServers[MAX_SERVERS]; + MYDWORD allMasks[MAX_SERVERS]; + char staticNames[MAX_SERVERS][256]; + MYDWORD listenServers[MAX_SERVERS]; + MYDWORD listenMasks[MAX_SERVERS]; + MYDWORD staticServers[MAX_SERVERS]; + MYDWORD staticMasks[MAX_SERVERS]; + MYDWORD dns[MAX_SERVERS]; + SOCKET maxFD; + SOCKET maxFDPlusOne; + MYBYTE currentDNS; + bool ready; + bool readyForChange; +}; + +struct data2 +{ + char zoneSmall[256]; + char zone[256]; + MYBYTE zLen; + char authoritySmall[256]; + char authority[256]; + MYBYTE aLen; + char nsP[256]; + char nsS[256]; + //char nsA[256]; + //char nsP[256]; + //char nsABare[256]; + //char nsPBare[256]; + char servername[128]; + char servername_fqn[256]; + ConnType dhcpReplConn; + MYDWORD zoneServers[MAX_TCP_CLIENTS]; + MYDWORD specifiedServers[MAX_SERVERS]; + MYDWORD specifiedDnsServers[MAX_SERVERS]; + MYDWORD httpClients[8]; + data11 mxServers[2][5]; + MYBYTE mxCount[2]; + MYDWORD mask; + MYDWORD lease; + MYDWORD serial1; + MYDWORD serial2; + MYDWORD refresh; + MYDWORD retry; + MYDWORD expire; + MYDWORD minimum; + MYWORD minCache; + MYWORD maxCache; + MYDWORD dhcpSize; + SOCKET fixedSocket; + pid_t ppid; + MYDWORD oldservers[MAX_SERVERS]; + time_t dhcpRepl; + time_t dnsRepl; + time_t dnsCheck; + //bool ifspecified; + //struct ifreq IfcBuf[MAX_SERVERS]; + //MYBYTE ifc_len; + time_t expireTime; + data10 dnsRoutes[MAX_COND_FORW]; + data16 wildHosts[MAX_WILD_HOSTS]; + data12 dnsRanges[MAX_DNS_RANGES]; + data13 dhcpRanges[MAX_DHCP_RANGES]; + data14 rangeSet[MAX_RANGE_SETS]; + MYDWORD rangeStart; + MYDWORD rangeEnd; + MYBYTE *options; + char logFileName[256]; + MYDWORD failureCount; + MYDWORD failureCycle; + MYWORD dhcpInd; + MYBYTE dhcpLogLevel; + MYBYTE rangeCount; + MYBYTE dnsLogLevel; + MYBYTE authorized; + MYBYTE replication; + MYBYTE hasFilter; +}; + +struct data15 +{ + union + { + MYDWORD ip; + //unsigned ip:32; + MYBYTE octate[4]; + }; +}; + +//Function Prototypes +FILE *openSection(const char *sectionName, MYBYTE serial); +MYBYTE fromBase64(MYBYTE *target, char *source); +MYBYTE fromUUE(MYBYTE *target, char *source); +MYBYTE getBaseValue(MYBYTE a); +MYBYTE makeLocal(char *mapname); +MYBYTE pIP(void *raw, MYDWORD data); +MYBYTE pUInt(void *raw, MYDWORD data); +MYBYTE pUShort(void *raw, MYWORD data); +MYBYTE addServer(MYDWORD *array, MYBYTE maxServers, MYDWORD ip); +MYDWORD *findServer(MYDWORD *array, MYBYTE maxServers, MYDWORD ip); +MYDWORD alad(data9 *req); +MYDWORD calcMask(MYDWORD rangeStart, MYDWORD rangeEnd); +MYDWORD chkaddr(data9 *req); +MYDWORD fIP(void *raw); +MYDWORD fUInt(void *raw); +MYDWORD getClassNetwork(MYDWORD ip); +MYDWORD getSerial(char *zone); +MYDWORD getZone(MYBYTE ind, char *zone); +MYDWORD resad(data9 *req); +MYDWORD sdmess(data9 *req); +MYDWORD sendRepl(data7 *dhcpEntry); +MYDWORD sendRepl(data9 *req); +MYWORD fQu(char *query, dnsPacket *mess, char *raw); +MYWORD fUShort(void *raw); +MYWORD fdnmess(data5 *req); +MYWORD frdnmess(data5 *req); +MYWORD gdmess(data9 *req, MYBYTE sockInd); +MYWORD gdnmess(data5 *req, MYBYTE sockInd); +MYWORD myTokenize(char *target, char *source, const char *sep, bool whiteSep); +MYWORD pQu(char *raw, char *query); +MYWORD qLen(char *query); +MYWORD recvTcpDnsMess(char *target, SOCKET sock, MYWORD targetSize); +MYWORD scanloc(data5 *req); +MYWORD sdnmess(data5 *req); +bool sendTCPmess(data5 *req); +bool checkIP(data9 *req, data17 *rangeData, MYDWORD ip); +bool checkMask(MYDWORD mask); +bool checkRange(data17 *rangeData, char rangeInd); +bool chkQu(char *query); +bool detectChange(); +bool getSecondary(); +bool getSection(const char *sectionName, char *buffer, MYBYTE serial, char *fileName); +bool isIP(char *str); +bool isInt(char *str); +bool isLocal(MYDWORD ip); +bool wildcmp(char *string, char *wild); +char *IP2Auth(MYDWORD ip); +char *IP2String(char *target, MYDWORD ip); +char *IP2String(char *target, MYDWORD ip, MYBYTE dnsType); +char *IP62String(char *target, MYBYTE *source); +char *cloneString(char *string); +char *genHostName(char *target, const MYBYTE *hex, MYBYTE bytes); +char *getHexValue(MYBYTE *target, char *source, MYBYTE *size); +char *hex2String(char *target, const MYBYTE *hex, MYBYTE bytes); +char *myLower(char *string); +char *myUpper(char *string); +char *readSection(char* buff, FILE *f); +char *setMapName(char *tempbuff, char *mapname, MYBYTE dnsType); +char *strquery(data5 *req); +char *toBase64(MYBYTE *source, MYBYTE length); +char *toUUE(char *tempbuff, MYBYTE *source, MYBYTE length); +char getRangeInd(MYDWORD ip); +char* getResult(data5 *req); +char* myGetToken(char* buff, MYBYTE index); +char* myTrim(char *target, char *source); +data7 *createCache(data71 *pLump); +data7 *findDHCPEntry(char *key); +data7 *findDNSEntry(char *key, MYBYTE dnsType); +data7 *findDNSEntry(char *key, MYBYTE dnsType, MYBYTE cacheType); +data7 *findQueue(const char *key); +int getIndex(char rangeInd, MYDWORD ip); +void* checkZone(void *lpParam); +void* init(void *lpParam); +void* logDebug(void *lpParam); +void* logThread(void *lpParam); +void* sendHTTP(void *lpParam); +void* sendToken(void *lpParam); +void* updateStateFile(void *lpParam); +void* delayClose(void *lpParam); +void add2Cache(char *hostname, MYDWORD ip, time_t expiry, MYBYTE aType, MYBYTE pType); +void addDHCPRange(char *dp); +void addDNSEntry(data7 *entry); +void addHostNotFound(char *hostname); +void addMacRange(MYBYTE rangeSetInd, char *macRange); +void addOptions(data9 *req); +void addRRA(data5 *req); +void addRRAOne(data5 *req); +void addRRAd(data5 *req); +void addRRAny(data5 *req); +void addRRCNOne(data5 *req); +void addRRCache(data5 *req, data7 *cache); +void addRREmpty(data5 *req); +void addRRError(data5 *req, MYBYTE rcode); +void addRRExt(data5 *req); +void addRRLocalhostA(data5 *req, data7 *cache); +void addRRLocalhostPtr(data5 *req, data7 *cache); +void addRRMX(data5 *req); +void addRRMXOne(data5 *req, MYBYTE m); +void addRRNS(data5 *req); +void addRRNone(data5 *req); +void addRRPtr(data5 *req); +void addRRPtrOne(data5 *req); +void addRRSOA(data5 *req); +void addRRSTAOne(data5 *req); +void addRRWildA(data5 *req, MYDWORD ip); +void addUserClass(MYBYTE rangeSetInd, char *userClass, MYBYTE userClassSize); +void addVendClass(MYBYTE rangeSetInd, char *vendClass, MYBYTE vendClassSize); +void calcRangeLimits(MYDWORD ip, MYDWORD mask, MYDWORD *rangeStart, MYDWORD *rangeEnd); +void checkSize(); +void closeConn(); +void debug(const char *mess); +void debug(const char *title, const char *mess); +void debug(const char *title, int i); +void delDnsEntry(data7* cache); +void emptyCache(MYBYTE ind); +void expireEntry(MYDWORD ip); +bool getInterfaces(data1 *netinfo); +void holdIP(MYDWORD ip); +void installService(); +void listCache(); +void listDhcpCache(); +void loadDHCP(); +void loadOptions(FILE *f, const char *sectionName, data20 *optionData); +void lockIP(MYDWORD ip); +void lockOptions(FILE *f); +void logDHCPMess(char *logBuff, MYBYTE logLevel); +void logDHCPMess(const char *title, const char *mess); +void logDNSMess(char *logBuff, MYBYTE logLevel); +void logDNSMess(data5 *req, char *logBuff, MYBYTE logLevel); +void logDirect(char *mess); +void logMess(char *logBuff, MYBYTE logLevel); +void logMess(const char *title, const char *mess); +void logTCPMess(data5 *req, char *logBuff, MYBYTE logLevel); +void mySplit(char *name, char *value, const char *source, char splitChar); +void procHTTP(data19 *req); +void procTCP(data5 *req); +void pvdata(data9 *req, data3 *op); +void recvRepl(data9 *req); +void runProg(); +void runService(); +void sendScopeStatus(data19 *req); +void sendServerName(); +void sendStatus(data19 *req); +void setLeaseExpiry(data7 *dhcpEntry); +void setLeaseExpiry(data7 *dhcpEntry, MYDWORD lease); +void setTempLease(data7 *dhcpEntry); +void showError(MYDWORD enumber); +void uninstallService(); +void updateDNS(data9 *req); +void catch_int(int sig_num); +FILE *pullZone(SOCKET sock); diff --git a/srcs/dual_server/dualsvr.h b/srcs/dual_server/dualsvr.h new file mode 100644 index 0000000..7e32c35 --- /dev/null +++ b/srcs/dual_server/dualsvr.h @@ -0,0 +1,18 @@ +// +// Created by xajhuang on 2022/10/26. +// + +#ifndef VCPE_PROJECT_DUALSVR_H +#define VCPE_PROJECT_DUALSVR_H +#define API_PUBLIC __attribute__((visibility("default"))) +#define API_EXPORT API_PUBLIC + +#ifdef __cplusplus +extern "C" { +#endif + +API_EXPORT int dual_server_main(int argc, char **argv); +#ifdef __cplusplus +} +#endif +#endif//VCPE_PROJECT_DUALSVR_H