diff --git a/Simple DHCP Server (C++)/Arduino.cpp b/Simple DHCP Server (C++)/Arduino.cpp new file mode 100644 index 0000000..ac8d90d --- /dev/null +++ b/Simple DHCP Server (C++)/Arduino.cpp @@ -0,0 +1 @@ +#include "Arduino.h" diff --git a/Simple DHCP Server (C++)/Arduino.h b/Simple DHCP Server (C++)/Arduino.h new file mode 100644 index 0000000..a508818 --- /dev/null +++ b/Simple DHCP Server (C++)/Arduino.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include +class Arduino +{ +public: + static unsigned int millis() { + return (unsigned int)(GetTickCount64() % 0xFFFFFFFF); + } +}; + diff --git a/Simple DHCP Server (C++)/DHCP.cpp b/Simple DHCP Server (C++)/DHCP.cpp new file mode 100644 index 0000000..4696b27 --- /dev/null +++ b/Simple DHCP Server (C++)/DHCP.cpp @@ -0,0 +1,331 @@ +#include "DHCP.h" + + + +static const unsigned char MAGIC_COOKIE_Data[] = { 0x63, 0x82, 0x53, 0x63 }; +const unsigned char* DHCP::MAGIC_COOKIE = MAGIC_COOKIE_Data; + +unsigned int DHCPLeaseTime = 900; + +std::vector DNSServers; + +unsigned char maxLeases = 32; + +unsigned char localAddress1 = 192; +unsigned char localAddress2 = 168; +unsigned char localAddress3 = 250; +unsigned char deviceIP = 1; + +unsigned char leaseStart = 2; + +unsigned char localSubnet1 = 255; +unsigned char localSubnet2 = 255; +unsigned char localSubnet3 = 255; +unsigned char localSubnet4 = 0; + +DHCP::DHCPEntry* DHCPEntries; + +//std::vector DHCPEntries(maxLeases); + + +std::vector DHCP::Generate_DHCP_Option(unsigned char option, unsigned char clientIP) { + std::vector s; + s.push_back(option); + s.push_back(0); + unsigned char length = 0; + // Subnet + if (option == 1) { + s.push_back(localSubnet1); + s.push_back(localSubnet2); + s.push_back(localSubnet3); + s.push_back(localSubnet4); + length = 4; + } + else if (option == 3) { + s.push_back(localAddress1); + s.push_back(localAddress2); + s.push_back(localAddress3); + s.push_back(deviceIP); + length = 4; + } + else if (option == 6) { + if (DNSServers.size() > 0) { + for (size_t i = 0; i < DNSServers.size(); i++) + { + if (DNSServers[i] != 0) + { + s.push_back((size_t)(DNSServers[i] >> 24)); + s.push_back((size_t)(DNSServers[i] >> 16)); + s.push_back((size_t)(DNSServers[i] >> 8)); + s.push_back((size_t)DNSServers[i]); + length += 4; + } + } + } + else return std::vector(0); + } + else if (option == 51) { + long time = 0; + if (clientIP == 255) { + time = DHCPLeaseTime; + } + else { + time = DHCPEntries[clientIP - leaseStart].expiry - (Arduino::millis() / 1000); + } + s.push_back((unsigned char)(time >> 24)); + s.push_back((unsigned char)(time >> 16)); + s.push_back((unsigned char)(time >> 8)); + s.push_back((unsigned char)time); + length = 4; + } + else if (option == 54) { + s.push_back(localAddress1); + s.push_back(localAddress2); + s.push_back(localAddress3); + s.push_back(deviceIP); + length = 4; + } + else return std::vector(0); + s[1] = length; + return s; +} + +unsigned char DHCP::FindPosByMac(Net::MACAddress MAC, DHCP::DHCPEntry* entries, unsigned char entries_size) { + for (size_t i = 0; i < entries_size; i++) + { + if (entries[i].MAC.equals(MAC)) { + return i; + } + } + return 255; +} + + + +std::vector> DHCP::ProcessDHCP(std::vector rxBuffer) { + unsigned char txBuffer[Net::TYPICAL_MTU] = {}; // ensure we have base zeros + u_long destAddress = ULLONG_MAX; + if (rxBuffer[236] == DHCP::MAGIC_COOKIE[0] && rxBuffer[237] == DHCP::MAGIC_COOKIE[1] && rxBuffer[238] == DHCP::MAGIC_COOKIE[2] && rxBuffer[239] == DHCP::MAGIC_COOKIE[3]) { + unsigned int position = 240; + // Find all options + std::vector RXOptions; + while (rxBuffer[position] != 0xFF && position < Net::TYPICAL_MTU) { + unsigned char option = rxBuffer[position++]; + unsigned char dataLength = rxBuffer[position++]; + DHCP::DHCPOption newOption = DHCP::DHCPOption(); + newOption.option = option; + newOption.dataLength = dataLength; + + while (dataLength > 0) { + newOption.DHCPData.push_back(rxBuffer[position++]); + dataLength--; + } + RXOptions.push_back(newOption); + } + // Check first option is DHCP + if (RXOptions[0].option == 53) { + Net::MACAddress clientMAC = Net::MACAddress((rxBuffer.data() + 28)); + unsigned char leaseIndex = DHCP::FindPosByMac(clientMAC, DHCPEntries, maxLeases); + unsigned char clientIP; + if (leaseIndex == 255) { + leaseIndex = FindPosByMac(Net::MACAddress::GetEmpty(), DHCPEntries, maxLeases); + if (leaseIndex == 255) { + return std::vector>(0); + } + } + clientIP = leaseIndex + leaseStart; + txBuffer[0] = 2; + for (unsigned char i = 1; i < 240; i++) + { + if (i == 12) { + i = 28; + } + else if (i == 44) { + i = 236; + } + txBuffer[i] = rxBuffer[i]; + } + // Clear the rxBuffer, we have read all we need + rxBuffer.clear(); + + txBuffer[16] = localAddress1; + txBuffer[17] = localAddress2; + txBuffer[18] = localAddress3; + txBuffer[19] = clientIP; + txBuffer[20] = localAddress1; + txBuffer[21] = localAddress2; + txBuffer[22] = localAddress3; + txBuffer[23] = deviceIP; + + position = 240; + // DHCP option + if (RXOptions[0].DHCPData[0] == 1) { + std::cout << "D"; + std::vector prl; + for (size_t i = 0; i < RXOptions.size(); i++) + { + if (RXOptions[i].option == 50) { + unsigned char requestSuffix = RXOptions[i].DHCPData[RXOptions[i].dataLength - 1]; + if (DHCPEntries[requestSuffix - leaseStart].MAC.equals(Net::MACAddress::GetEmpty())) { + clientIP = requestSuffix; + txBuffer[19] = clientIP; + } + } + else if (RXOptions[i].option == 55) { + prl.resize(RXOptions[i].dataLength); + for (size_t r = 0; r < RXOptions[i].dataLength; r++) + { + prl[r] = RXOptions[i].DHCPData[r]; + } + } + } + DHCPEntries[clientIP - leaseStart].MAC = clientMAC; + DHCPEntries[clientIP - leaseStart].requestedItems = prl; + DHCPEntries[clientIP - leaseStart].expiry = (Arduino::millis() / 1000) + 30; + + txBuffer[position++] = 53; + txBuffer[position++] = 1; + txBuffer[position++] = 2; + std::vector r = Generate_DHCP_Option(54, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + r = Generate_DHCP_Option(51, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + for (size_t i = 0; i < prl.size(); i++) + { + r = Generate_DHCP_Option(prl[i], clientIP); + if (r.size() > 0) { + for (size_t b = 0; b < r.size(); b++) + { + txBuffer[position++] = r[b]; + } + } + } + std::cout << "O"; + } + else if (RXOptions[0].DHCPData[0] == 3) { + std::cout << "R"; + bool optionsMatch = true; + for (size_t i = 0; i < RXOptions.size(); i++) + { + if (RXOptions[i].option == 50) { + if (clientIP != RXOptions[i].DHCPData[RXOptions[i].dataLength - 1] && !DHCPEntries[clientIP - 2].MAC.equals(Net::MACAddress::GetEmpty())) { + optionsMatch = false; + break; + } + } + else if (RXOptions[i].option == 54) { + if (deviceIP != RXOptions[i].DHCPData[RXOptions[i].dataLength - 1]) { + optionsMatch = false; + break; + } + } + else if (RXOptions[i].option == 55) { + DHCPEntries[clientIP - leaseStart].requestedItems.clear(); + DHCPEntries[clientIP - leaseStart].requestedItems.resize(RXOptions[i].dataLength); + for (size_t r = 0; r < RXOptions[i].dataLength; r++) { + DHCPEntries[clientIP - leaseStart].requestedItems[r] = RXOptions[i].DHCPData[r]; + } + + } + } + if (optionsMatch) { + // Ack + DHCPEntries[clientIP - leaseStart].expiry = (Arduino::millis() / 1000) + DHCPLeaseTime; + + txBuffer[position++] = 53; + txBuffer[position++] = 1; + txBuffer[position++] = 5; // ACK + std::vector r = Generate_DHCP_Option(54, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + r = Generate_DHCP_Option(51, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + for (size_t i = 0; i < DHCPEntries[clientIP - leaseStart].requestedItems.size(); i++) + { + r = Generate_DHCP_Option(DHCPEntries[clientIP - leaseStart].requestedItems[i], clientIP); + if (r.size() > 0) { + for (size_t b = 0; b < r.size(); b++) + { + txBuffer[position++] = r[b]; + } + } + } + std::cout << "A\n"; + } + else { + txBuffer[position++] = 53; + txBuffer[position++] = 1; + txBuffer[position++] = 5; // ACK + std::vector r = Generate_DHCP_Option(54, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + r = Generate_DHCP_Option(51, clientIP); + for (size_t i = 0; i < r.size(); i++) + { + txBuffer[position++] = r[i]; + } + for (size_t i = 0; i < DHCPEntries[clientIP - leaseStart].requestedItems.size(); i++) + { + r = Generate_DHCP_Option(DHCPEntries[clientIP - leaseStart].requestedItems[i], clientIP); + if (r.size() > 0) { + for (size_t b = 0; b < r.size(); b++) + { + txBuffer[position++] = r[b]; + } + } + } + std::cout << "N\n"; + } + } + else { + std::cout << " " << RXOptions[0].DHCPData[0] << "\n"; + } + } + txBuffer[position++] = 255; + std::vector returnBuffer(position); + for (size_t i = 0; i < position; i++) + { + returnBuffer[i] = txBuffer[i]; + } + + return std::vector> {std::vector {(unsigned char)(destAddress >> 24), (unsigned char)(destAddress >> 16), (unsigned char)(destAddress >> 8), (unsigned char)destAddress}, returnBuffer}; + } +} +DHCP::DHCP(unsigned char* deviceAddress, unsigned char* subnetMask, unsigned char maxLeases, unsigned char leaseStart, unsigned int leaseTime, unsigned int* dnsServers, unsigned char dnsServerCount) { + localAddress1 = deviceAddress[0]; + localAddress2 = deviceAddress[1]; + localAddress3 = deviceAddress[2]; + deviceIP = deviceAddress[3]; + + localSubnet1 = subnetMask[0]; + localSubnet2 = subnetMask[1]; + localSubnet3 = subnetMask[2]; + localSubnet4 = subnetMask[3]; + + this->maxLeases = maxLeases; + this->leaseStart = leaseStart; + DHCPLeaseTime = leaseTime; + DHCPEntries = new DHCP::DHCPEntry[maxLeases]; + DNSServers.resize(dnsServerCount); + for (size_t i = 0; i < dnsServerCount; i++) + { + DNSServers[i] = dnsServers[i]; + } +} + +DHCP::~DHCP() { + delete[] DHCPEntries; +} \ No newline at end of file diff --git a/Simple DHCP Server (C++)/DHCP.h b/Simple DHCP Server (C++)/DHCP.h new file mode 100644 index 0000000..a132e5a --- /dev/null +++ b/Simple DHCP Server (C++)/DHCP.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include "Net.h" +#include "Arduino.h" + + +class DHCP +{ +public: + + static const unsigned char* MAGIC_COOKIE; + unsigned int DHCPLeaseTime; + + std::vector DNSServers; + + unsigned char maxLeases; + + unsigned char localAddress1; + unsigned char localAddress2; + unsigned char localAddress3; + unsigned char deviceIP; + + unsigned char leaseStart; + + unsigned char localSubnet1; + unsigned char localSubnet2; + unsigned char localSubnet3; + unsigned char localSubnet4; + + + + struct DHCPOption { + unsigned char option = 0; + std::vector DHCPData; + unsigned char dataLength = 0; + }; + + class DHCPEntry { + public: + Net::MACAddress MAC = Net::MACAddress::GetEmpty(); + unsigned int expiry = 0; + std::vector requestedItems; + }; + DHCPEntry* DHCPEntries; + + //std::vector DHCPEntries; + + unsigned char FindPosByMac(Net::MACAddress MAC, DHCPEntry* entries, unsigned char entries_size); + + std::vector Generate_DHCP_Option(unsigned char option, unsigned char clientIP); + + std::vector> ProcessDHCP(std::vector rxBuffer); + + DHCP(unsigned char* deviceAddress, unsigned char* subnetMask, unsigned char maxLeases, unsigned char leaseStart, unsigned int leaseTime, unsigned int* dnsServers, unsigned char dnsServerCount); + ~DHCP(); +}; + diff --git a/Simple DHCP Server (C++)/Net.cpp b/Simple DHCP Server (C++)/Net.cpp new file mode 100644 index 0000000..c6527a2 --- /dev/null +++ b/Simple DHCP Server (C++)/Net.cpp @@ -0,0 +1,128 @@ +#include "Net.h" +Net::IPAddress::IPAddress() +{ + address[0] = 0; + address[1] = 0; + address[2] = 0; + address[3] = 0; +} +Net::IPAddress::IPAddress(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4) { + address[0] = c1; + address[1] = c2; + address[2] = c3; + address[3] = c4; +} + +Net::IPAddress::IPAddress(unsigned char* IP) { + address[0] = *IP; + address[1] = *(IP + 1); + address[2] = *(IP + 2); + address[3] = *(IP + 3); +} + +Net::IPAddress Net::IPAddress::Empty() { + return IPAddress::IPAddress(); +} + +bool Net::IPAddress::Equals(IPAddress other) { + for (unsigned char i = 0; i < 4; i++) + { + if (address[i] != other.address[i]) { + return false; + } + } + return true; +} + +Net::IPEndPoint::IPEndPoint(unsigned char* IP, unsigned short Port) { + Address = IPAddress(IP); + socks.sin_family = AF_INET; + socks.sin_addr.S_un.S_addr = (IP[3] << 24) | (IP[2] << 16) | (IP[1] << 8) | IP[0]; // Order of the IP bytes is swapped, so 192.168.1.32 would be 32.1.168.192 + socks.sin_port = htons(Port); // Likewise, the port is also byte-order reversed. +} + +Net::UdpClient::UdpClient() { + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2, 2); + int err = WSAStartup(wVersionRequested, &wsaData); + if (err < 0) { + + } + // We're a UDP Client; set socket mode to IPv4 UDP Datagrams + this->Client.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +} + +void Net::UdpClient::Socket::Bind(IPEndPoint ep) { + int r = bind(sock, (SOCKADDR*)&ep.socks, sizeof(ep.socks)); + int reslt = WSAGetLastError(); + if (r < 0) { + + throw std::system_error(reslt, std::system_category(), "Could not bind socket"); + } + int broadcast = 1; + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof broadcast); +} + +void Net::UdpClient::Socket::Bind(unsigned char* IP, unsigned short Port) { + IPEndPoint ep = IPEndPoint(IP, Port); + Bind(ep); +} + +std::vector Net::UdpClient::Recieve(IPEndPoint* remote, unsigned short BufferSize) { + std::vector recievedBytes; + char* buffer = new char[BufferSize]; + // As recvfrom is blocking, this space must be reserved in memory pretty much at all times(typically 1480 bytes) + int remoteSize = sizeof(remote->socks); + int r = recvfrom(Client.sock, buffer, BufferSize, 0, (SOCKADDR*)&remote->socks, &remoteSize); + if (r > 0) { + recievedBytes.resize(r); + for (int i = 0; i < r; i++) + { + recievedBytes[i] = buffer[i]; + } + } + delete[] buffer; + return recievedBytes; +} +int Net::UdpClient::Send(std::vector Datagram, int dGramSize, IPEndPoint ep) { + return sendto(Client.sock, (char*)Datagram.data(), dGramSize, 0, (SOCKADDR*)&ep.socks, sizeof(ep.socks)); +} + +int Net::UdpClient::Send(std::vector Datagram, int dGramSize, std::vector DestinationIP, int DestPort) { + IPEndPoint ep = IPEndPoint(DestinationIP.data(), (u_short)DestPort); + return Send(Datagram, dGramSize, ep); +} + +Net::MACAddress::MACAddress(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6) +{ + macBytes[0] = c1; + macBytes[1] = c2; + macBytes[2] = c3; + macBytes[3] = c4; + macBytes[4] = c5; + macBytes[5] = c6; +} +Net::MACAddress::MACAddress(unsigned char* byteArray) { + for (size_t i = 0; i < MACSize; i++) + { + macBytes[i] = byteArray[i]; + } +} +Net::MACAddress::MACAddress(std::vector bytes) { + for (size_t i = 0; i < MACSize; i++) + { + macBytes[i] = bytes[i]; + } +} + +bool Net::MACAddress::equals(MACAddress other) { + for (unsigned char i = 0; i < MACSize; i++) + { + if (macBytes[i] != other.macBytes[i]) { + return false; + } + } + return true; +} + diff --git a/Simple DHCP Server (C++)/Net.h b/Simple DHCP Server (C++)/Net.h new file mode 100644 index 0000000..4fcc9eb --- /dev/null +++ b/Simple DHCP Server (C++)/Net.h @@ -0,0 +1,67 @@ +#pragma once +#include +#include +#include +#include +#include +#pragma comment(lib, "WS2_32.lib") +class Net { +public: + static const unsigned short TYPICAL_MTU = 1480; + static const unsigned char MACSize = 6; + + struct IPAddress { + private: + unsigned char address[4]; + public: + IPAddress(); + IPAddress(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4); + + IPAddress(unsigned char* IP); + + static IPAddress Empty(); + + bool Equals(IPAddress other); + }; + + struct IPEndPoint { + struct sockaddr_in socks; + IPAddress Address; + + IPEndPoint(unsigned char* IP, unsigned short Port); + }; + + class UdpClient { + struct Socket { + struct sockaddr_in socks; + SOCKET sock; + void Bind(IPEndPoint ep); + + void Bind(unsigned char* IP, unsigned short Port); + }; + + public: + Socket Client; + UdpClient(); + + std::vector Recieve(IPEndPoint* remote, unsigned short BufferSize = 1480); + int Send(std::vector Datagram, int dGramSize, IPEndPoint ep); + + int Send(std::vector Datagram, int dGramSize, std::vector DestinationIP, int DestPort); + }; + + struct MACAddress { + unsigned char macBytes[6]; + MACAddress(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6); + MACAddress(unsigned char* byteArray); + MACAddress(std::vector bytes); + + bool equals(MACAddress other); + + static MACAddress GetEmpty() { + return MACAddress(0, 0, 0, 0, 0, 0); + } + }; +}; + + diff --git a/Simple DHCP Server (C++)/Simple DHCP Server (C++).cpp b/Simple DHCP Server (C++)/Simple DHCP Server (C++).cpp index cd0ed18..428f583 100644 --- a/Simple DHCP Server (C++)/Simple DHCP Server (C++).cpp +++ b/Simple DHCP Server (C++)/Simple DHCP Server (C++).cpp @@ -1,537 +1,34 @@ // Simple DHCP Server (C++).cpp : This file contains the 'main' function. Program execution begins and ends there. // - #include -#include -#include #include #include -#pragma comment(lib, "WS2_32.lib") - -const unsigned char MAGIC_COOKIE[] = { 0x63, 0x82, 0x53, 0x63 }; -const short STANDARD_MTU = 1480; - -static unsigned int DHCPLeaseTime = 900; - -static std::vector DNSServers = {16843009}; - -static unsigned char maxLeases = 32; - -static unsigned char localAddress1 = 192; -static unsigned char localAddress2 = 168; -static unsigned char localAddress3 = 250; -static unsigned char deviceIP = 1; - -static unsigned char leaseStart = 2; - -static unsigned char localSubnet1 = 255; -static unsigned char localSubnet2 = 255; -static unsigned char localSubnet3 = 255; -static unsigned char localSubnet4 = 0; - -struct MACAddress { -private: - char MACSize; - std::vector MACBytes; -public: - MACAddress(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, unsigned char c5, unsigned char c6) - { - MACBytes = std::vector{c1,c2,c3,c4,c5,c6}; - MACSize = 6; - } - MACAddress(unsigned char *byteArray, char length) { - MACBytes = std::vector(length); - for (char i = 0; i < length; i++) - { - MACBytes[i] = *byteArray; - byteArray++; - } - MACSize = length; - } - MACAddress(std::vector bytes) { - MACBytes = bytes; - MACSize = bytes.size(); - } - char getMACSize() { - return MACSize; - } - std::vector getMACBytes() { - return MACBytes; - } - - bool equals(MACAddress other) { - if (MACSize != other.getMACSize()) { - return false; - } - for (unsigned char i = 0; i < MACSize; i++) - { - if (MACBytes[i] != other.getMACBytes()[i]) { - return false; - } - } - return true; - } - static MACAddress GetEmpty() { - return MACAddress(0, 0, 0, 0, 0, 0); - } -}; - -struct DHCPOption { - unsigned char option = 0; - std::vector DHCPData; - unsigned char dataLength = 0; -}; - -class DHCPEntry { -public: - MACAddress MAC = MACAddress::GetEmpty(); - unsigned int expiry = 0; - std::vector requestedItems; -}; - - -static std::vector DHCPEntries(maxLeases); +#include "Net.h" +#include "DHCP.h" // Maintain a C#-esque network client for simple handling // As per https://stackoverflow.com/questions/14665543/how-do-i-receive-udp-packets-with-winsock-in-c // A handler class is helpful. This implementation is based on the implementation in .NET -struct IPAddress { -private: - u_char address[4]; -public: - IPAddress() - { - address[0] = 0; - address[1] = 0; - address[2] = 0; - address[3] = 0; - } - IPAddress(u_char c1, u_char c2, u_char c3, u_char c4) { - address[0] = c1; - address[1] = c2; - address[2] = c3; - address[3] = c4; - } - IPAddress(u_char* IP) { - address[0] = *IP; - address[1] = *(IP+1); - address[2] = *(IP+2); - address[3] = *(IP+3); - } - - static IPAddress Empty() { - return IPAddress(); - } - - bool Equals(IPAddress other) { - for (byte i = 0; i < 4; i++) - { - if (address[i] != other.address[i]) { - return false; - } - } - return true; - } -}; - -struct IPEndPoint { - struct sockaddr_in socks; - IPAddress Address; - - IPEndPoint(u_char* IP, u_short Port) { - Address = IPAddress(IP); - //std::string strIP = std::to_string(IP[0]) + std::to_string('.') + std::to_string(IP[1]) + std::to_string('.') + std::to_string(IP[2]) + std::to_string('.') + std::to_string(IP[3]); - socks.sin_family = AF_INET; - u_char c1 = IP[0]; - u_char c2 = IP[1]; - u_char c3 = IP[2]; - u_char c4 = IP[3]; - u_long r = (c4 << 24) | (c3 << 16) | (c2 << 8) | c1; // Are these swapped? - socks.sin_addr.S_un.S_addr = r;// inet_pton(AF_INET, strIP, );//inet_addr(IP); - socks.sin_port = htons(Port); - } -}; - -class UdpClient { - struct Socket { - struct sockaddr_in socks; - SOCKET sock; - void Bind(IPEndPoint ep) { - int r = bind(sock, (SOCKADDR*)&ep.socks, sizeof(ep.socks)); - int reslt = WSAGetLastError(); - if (r < 0) { - - throw std::system_error(reslt, std::system_category(), "Could not bind socket"); - } - int broadcast = 1; - setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof broadcast); - } - - void Bind(u_char *IP, u_short Port) { - IPEndPoint ep = IPEndPoint(IP, Port); - Bind(ep); - } - }; - -public: - Socket Client; - UdpClient() { - // We're a UDP Client; set socket mode to IPv4 UDP Datagrams - this->Client.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - } - - std::vector Recieve(IPEndPoint* remote) { - std::vector recievedBytes; - char buffer[1024]; - int remoteSize = sizeof(remote->socks); - int r = recvfrom(Client.sock, buffer, 1024, 0, (SOCKADDR*)&remote->socks, &remoteSize); - if (r > 0) { - recievedBytes.resize(r); - for (int i = 0; i < r; i++) - { - recievedBytes[i] = buffer[i]; - } - } - return recievedBytes; - } - void Send(std::vector Datagram, int dGramSize, IPEndPoint ep) { - char dgData[STANDARD_MTU]; - for (size_t i = 0; i < dGramSize; i++) - { - dgData[i] = Datagram[i]; - } - int result = sendto(Client.sock, dgData, dGramSize, 0, (SOCKADDR*)&ep.socks, sizeof (ep.socks)); - int reslt = WSAGetLastError(); - int g = 200; - } - - void Send(std::vector Datagram, int dGramSize, std::vector DestinationIP, int DestPort) { - IPEndPoint ep = IPEndPoint(DestinationIP.data(), (u_short)DestPort); - Send(Datagram, dGramSize, ep); - } - - -}; - -static u_int millis() { - return (u_int)(GetTickCount64() % UINT32_MAX); -} - -static u_char FindPosByMac(MACAddress MAC, std::vector entries, u_char entries_size) { - for (size_t i = 0; i < entries_size; i++) - { - if (entries[i].MAC.equals(MAC)) { - return i; - } - } - return 255; -} - -static std::vector Generate_DHCP_Option(u_char option, u_char clientIP) { - std::vector s; - s.push_back(option); - s.push_back(0); - u_char length = 0; - // Subnet - if (option == 1) { - s.push_back(localSubnet1); - s.push_back(localSubnet2); - s.push_back(localSubnet3); - s.push_back(localSubnet4); - length = 4; - } - else if (option == 3) { - s.push_back(localAddress1); - s.push_back(localAddress2); - s.push_back(localAddress3); - s.push_back(deviceIP); - length = 4; - } - else if (option == 6) { - if (DNSServers.size() > 0) { - for (size_t i = 0; i < DNSServers.size(); i++) - { - if (DNSServers[i] != 0) - { - s.push_back((size_t)(DNSServers[i] >> 24)); - s.push_back((size_t)(DNSServers[i] >> 16)); - s.push_back((size_t)(DNSServers[i] >> 8)); - s.push_back((size_t)DNSServers[i]); - length += 4; - } - } - } - else return std::vector(0); - } - else if (option == 51) { - long time = 0; - if (clientIP == 255) { - time = DHCPLeaseTime; - } - else { - time = DHCPEntries[clientIP - leaseStart].expiry - (millis() / 1000); - } - s.push_back((u_char)(time >> 24)); - s.push_back((u_char)(time >> 16)); - s.push_back((u_char)(time >> 8)); - s.push_back((u_char)time); - length = 4; - } - else if (option == 54) { - s.push_back(localAddress1); - s.push_back(localAddress2); - s.push_back(localAddress3); - s.push_back(deviceIP); - length = 4; - } - else return std::vector(0); - s[1] = length; - return s; -} - -std::vector> ProcessDHCP(std::vector rxBuffer) { - u_char txBuffer[STANDARD_MTU] = {}; // ensure we have base zeros - u_long destAddress = ULLONG_MAX; - if (rxBuffer[236] == MAGIC_COOKIE[0] && rxBuffer[237] == MAGIC_COOKIE[1] && rxBuffer[238] == MAGIC_COOKIE[2] && rxBuffer[239] == MAGIC_COOKIE[3]) { - u_int position = 240; - // Find all options - std::vector RXOptions; - while (rxBuffer[position] != 0xFF && position < STANDARD_MTU) { - u_char option = rxBuffer[position++]; - u_char dataLength = rxBuffer[position++]; - DHCPOption newOption = DHCPOption(); - newOption.option = option; - newOption.dataLength = dataLength; - - while (dataLength > 0) { - newOption.DHCPData.push_back(rxBuffer[position++]); - dataLength--; - } - RXOptions.push_back(newOption); - } - // Check first option is DHCP - if (RXOptions[0].option == 53) { - MACAddress clientMAC = MACAddress((rxBuffer.data()+28), 6); - u_char leaseIndex = FindPosByMac(clientMAC, DHCPEntries, maxLeases); - u_char clientIP; - if (leaseIndex == 255) { - leaseIndex = FindPosByMac(MACAddress::GetEmpty(), DHCPEntries, maxLeases); - if (leaseIndex == 255) { - return std::vector>(0); - } - } - clientIP = leaseIndex + leaseStart; - txBuffer[0] = 2; - for (u_char i = 1; i < 240; i++) - { - if (i == 12) { - i = 28; - } - else if (i == 44) { - i = 236; - } - txBuffer[i] = rxBuffer[i]; - } - txBuffer[16] = localAddress1; - txBuffer[17] = localAddress2; - txBuffer[18] = localAddress3; - txBuffer[19] = clientIP; - txBuffer[20] = localAddress1; - txBuffer[21] = localAddress2; - txBuffer[22] = localAddress3; - txBuffer[23] = deviceIP; - - position = 240; - // DHCP option - if (RXOptions[0].DHCPData[0] == 1) { - std::cout << "D"; - std::vector prl; - for (size_t i = 0; i < RXOptions.size(); i++) - { - if (RXOptions[i].option == 50) { - u_char requestSuffix = RXOptions[i].DHCPData[RXOptions[i].dataLength - 1]; - if (DHCPEntries[requestSuffix - leaseStart].MAC.equals(MACAddress::GetEmpty())) { - clientIP = requestSuffix; - txBuffer[19] = clientIP; - } - } - else if (RXOptions[i].option == 55) { - prl.resize(RXOptions[i].dataLength); - for (size_t r = 0; r < RXOptions[i].dataLength; r++) - { - prl[r] = RXOptions[i].DHCPData[r]; - } - } - } - DHCPEntries[clientIP - leaseStart].MAC = clientMAC; - DHCPEntries[clientIP - leaseStart].requestedItems = prl; - DHCPEntries[clientIP - leaseStart].expiry = (millis() / 1000) + 30; - - txBuffer[position++] = 53; - txBuffer[position++] = 1; - txBuffer[position++] = 2; - std::vector r = Generate_DHCP_Option(54, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - r = Generate_DHCP_Option(51, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - for (size_t i = 0; i < prl.size(); i++) - { - r = Generate_DHCP_Option(prl[i], clientIP); - if (r.size() > 0) { - for (size_t b = 0; b < r.size(); b++) - { - txBuffer[position++] = r[b]; - } - } - } - std::cout << "O"; - } - else if (RXOptions[0].DHCPData[0] == 3) { - std::cout << "R"; - bool optionsMatch = true; - for (size_t i = 0; i < RXOptions.size(); i++) - { - if (RXOptions[i].option == 50) { - if (clientIP != RXOptions[i].DHCPData[RXOptions[i].dataLength - 1] && !DHCPEntries[clientIP - 2].MAC.equals(MACAddress::GetEmpty())) { - optionsMatch = false; - break; - } - } - else if (RXOptions[i].option == 54) { - if (deviceIP != RXOptions[i].DHCPData[RXOptions[i].dataLength - 1]) { - optionsMatch = false; - break; - } - } - else if (RXOptions[i].option == 55) { - DHCPEntries[clientIP - leaseStart].requestedItems.clear(); - DHCPEntries[clientIP - leaseStart].requestedItems.resize(RXOptions[i].dataLength); - for (size_t r = 0; r < RXOptions[i].dataLength; r++) { - DHCPEntries[clientIP - leaseStart].requestedItems[r] = RXOptions[i].DHCPData[r]; - } - - } - } - if (optionsMatch) { - // Ack - DHCPEntries[clientIP - leaseStart].expiry = (millis() / 1000) + DHCPLeaseTime; - - txBuffer[position++] = 53; - txBuffer[position++] = 1; - txBuffer[position++] = 5; // ACK - std::vector r = Generate_DHCP_Option(54, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - r = Generate_DHCP_Option(51, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - for (size_t i = 0; i < DHCPEntries[clientIP-leaseStart].requestedItems.size(); i++) - { - r = Generate_DHCP_Option(DHCPEntries[clientIP - leaseStart].requestedItems[i], clientIP); - if (r.size() > 0) { - for (size_t b = 0; b < r.size(); b++) - { - txBuffer[position++] = r[b]; - } - } - } - std::cout << "A\n"; - } - else { - txBuffer[position++] = 53; - txBuffer[position++] = 1; - txBuffer[position++] = 5; // ACK - std::vector r = Generate_DHCP_Option(54, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - r = Generate_DHCP_Option(51, clientIP); - for (size_t i = 0; i < r.size(); i++) - { - txBuffer[position++] = r[i]; - } - for (size_t i = 0; i < DHCPEntries[clientIP - leaseStart].requestedItems.size(); i++) - { - r = Generate_DHCP_Option(DHCPEntries[clientIP - leaseStart].requestedItems[i], clientIP); - if (r.size() > 0) { - for (size_t b = 0; b < r.size(); b++) - { - txBuffer[position++] = r[b]; - } - } - } - std::cout << "N\n"; - } - } - else { - std::cout << " " << RXOptions[0].DHCPData[0] << "\n"; - } - } - txBuffer[position++] = 255; - std::vector returnBuffer(position); - for (size_t i = 0; i < position; i++) - { - returnBuffer[i] = txBuffer[i]; - } - return std::vector> {std::vector {(u_char)(destAddress >> 24), (u_char)(destAddress >> 16), (u_char)(destAddress >> 8), (u_char)destAddress}, returnBuffer}; - } -} int main() { std::cout << "Creating DHCP Server...\n"; - WORD wVersionRequested; - WSADATA wsaData; - - /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ - wVersionRequested = MAKEWORD(2, 2); - - int err = WSAStartup(wVersionRequested, &wsaData); - // Does a vector need the items to be instanced? - /*for (unsigned char i = 0; i < maxLeases; i++) - { - DHCPEntries[i] = new - } */ - // This is platform-dependant; it opens a UDP socket and sends the packet data through - // Create an IPv4 UDP Datagram socket - UdpClient udpClient = UdpClient(); - udpClient.Client.Bind(IPEndPoint(new u_char[] {localAddress1, localAddress2, localAddress3, deviceIP}, 67)); - IPEndPoint remote = IPEndPoint(new u_char[] {0, 0, 0, 0}, 0); + DHCP dhcp = DHCP(new unsigned char[] {192, 168, 250, 1}, new unsigned char[] {255, 255, 255, 0}, 32, 2, 900, new unsigned int[] { 16843009 }, 1); + Net::UdpClient udpClient = Net::UdpClient(); + udpClient.Client.Bind(Net::IPEndPoint(new unsigned char[] {dhcp.localAddress1, dhcp.localAddress2, dhcp.localAddress3, dhcp.deviceIP}, 67)); + Net::IPEndPoint remote = Net::IPEndPoint(new unsigned char[] {0, 0, 0, 0}, 0); while (true) { - std::vector buffer = udpClient.Recieve(&remote); - std::vector> result = ProcessDHCP(buffer); + std::vector buffer = udpClient.Recieve(&remote, 1480); + std::vector> result = dhcp.ProcessDHCP(buffer); if (result.size() == 2) { - if (remote.Address.Equals(IPAddress::Empty())) { + if (remote.Address.Equals(Net::IPAddress::Empty())) { udpClient.Send(result[1], result[1].size(), result[0], 68); } else { udpClient.Send(result[1], result[1].size(), remote); - // Reply via return address } } } } - -// Run program: Ctrl + F5 or Debug > Start Without Debugging menu -// Debug program: F5 or Debug > Start Debugging menu - -// Tips for Getting Started: -// 1. Use the Solution Explorer window to add/manage files -// 2. Use the Team Explorer window to connect to source control -// 3. Use the Output window to see build output and other messages -// 4. Use the Error List window to view errors -// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project -// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file diff --git a/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj b/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj index 1656379..33bed3d 100644 --- a/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj +++ b/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj @@ -140,8 +140,16 @@ + + + + + + + + diff --git a/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj.filters b/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj.filters index a9963cc..c031d51 100644 --- a/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj.filters +++ b/Simple DHCP Server (C++)/Simple DHCP Server (C++).vcxproj.filters @@ -18,5 +18,25 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file