static void Request(DHCPRequest dhcpRequest)
        {
            var type = dhcpRequest.GetMsgType();
            var mac = ByteArrayToString(dhcpRequest.GetChaddr());
            // IP for client
            IPAddress ip;
            if (!leases.TryGetValue(mac, out ip))
            {
                ip = new IPAddress(new byte[] { 10, 0, 0, nextIP++ });
                leases[mac] = ip;
            }
            Console.WriteLine(type.ToString() + " request from " + mac + ", it will be " + ip.ToString());

            var options = dhcpRequest.GetAllOptions();
            Console.Write("Options:");
            foreach (DHCPOption option in options.Keys)
            {
                Console.WriteLine(option.ToString() + ": " + ByteArrayToString(options[option]));
            }
            // Lets show some request info
            var requestedOptions = dhcpRequest.GetRequestedOptionsList();
            if (requestedOptions != null)
            {
                Console.Write("Requested options:");
                foreach (DHCPOption option in requestedOptions) Console.Write(" " + option.ToString());
                Console.WriteLine();
            }
            // Option 82 info
            var relayInfoN = dhcpRequest.GetRelayInfo();
            if (relayInfoN != null)
            {
                var relayInfo = (RelayInfo)relayInfoN;
                if (relayInfo.AgentCircuitID != null) Console.WriteLine("Relay agent circuit ID: " + ByteArrayToString(relayInfo.AgentCircuitID));
                if (relayInfo.AgentRemoteID != null) Console.WriteLine("Relay agent remote ID: " + ByteArrayToString(relayInfo.AgentRemoteID));
            }
            Console.WriteLine();

            var replyOptions = new DHCPReplyOptions();
            // Options should be filled with valid data. Only requested options will be sent.
            replyOptions.SubnetMask = IPAddress.Parse("255.255.255.0");
            replyOptions.DomainName = "SharpDHCPServer";
            replyOptions.ServerIdentifier = IPAddress.Parse("10.0.0.1");
            replyOptions.RouterIP = IPAddress.Parse("10.0.0.1");
            replyOptions.DomainNameServers = new IPAddress[] { IPAddress.Parse("192.168.100.2"), IPAddress.Parse("192.168.100.3") };
            // Some static routes
            replyOptions.StaticRoutes = new NetworkRoute[] {
                new NetworkRoute(IPAddress.Parse("10.0.0.0"), IPAddress.Parse("255.0.0.0"), IPAddress.Parse("10.0.0.1")),
                new NetworkRoute(IPAddress.Parse("192.168.0.0"), IPAddress.Parse("255.255.0.0"), IPAddress.Parse("10.0.0.1")),
                new NetworkRoute(IPAddress.Parse("172.16.0.0"), IPAddress.Parse("255.240.0.0"), IPAddress.Parse("10.0.0.1")),
                new NetworkRoute(IPAddress.Parse("80.252.130.248"), IPAddress.Parse("255.255.255.248"), IPAddress.Parse("10.0.0.1")),
                new NetworkRoute(IPAddress.Parse("80.252.128.88"), IPAddress.Parse("255.255.255.248"), IPAddress.Parse("10.0.0.1")),
            };

            // Lets send reply to client!
            if (type == DHCPMsgType.DHCPDISCOVER)
                dhcpRequest.SendDHCPReply(DHCPMsgType.DHCPOFFER, ip, replyOptions);
            if (type == DHCPMsgType.DHCPREQUEST)
                dhcpRequest.SendDHCPReply(DHCPMsgType.DHCPACK, ip, replyOptions);
        }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 /// <param name="otherForceOptions">Force reply options (will be sent anyway)</param>
 public void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData, Dictionary<DHCPOption, byte[]> otherForceOptions)
 {
     var replyBuffer = requestData;
     replyBuffer.op = 2; // Reply
     replyBuffer.yiaddr = ip.GetAddressBytes(); // Client's IP
     replyBuffer.options = CreateOptionStruct(msgType, replyData, otherForceOptions); // Options
     if (!string.IsNullOrEmpty(dhcpServer.ServerName))
     {
         var serverNameBytes = Encoding.ASCII.GetBytes(dhcpServer.ServerName);
         int len = (serverNameBytes.Length > 63) ? 63 : serverNameBytes.Length;
         Array.Copy(serverNameBytes, replyBuffer.sname, len);
         replyBuffer.sname[len] = 0;
     }
     lock (requestSocket)
     {
         IPEndPoint endPoint;
         if ((replyBuffer.giaddr[0] == 0) && (replyBuffer.giaddr[1] == 0) &&
             (replyBuffer.giaddr[2] == 0) && (replyBuffer.giaddr[3] == 0))
         {
             requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
             endPoint = new IPEndPoint(IPAddress.Broadcast, PORT_TO_SEND_TO_CLIENT);
         }
         else
         {
             requestSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
             endPoint = new IPEndPoint(new IPAddress(replyBuffer.giaddr), PORT_TO_SEND_TO_RELAY);
         }
         var DataToSend = BuildDataStructure(replyBuffer);
         requestSocket.SendTo(DataToSend, endPoint);
     }
 }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 public void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData)
 {
     SendDHCPReply(msgType, ip, replyData, null);
 }
        private byte[] CreateOptionStruct(DHCPMsgType msgType, DHCPReplyOptions replyOptions, Dictionary<DHCPOption, byte[]> otherForceOptions)
        {
            byte[] resultOptions = null;
            // Requested options
            var reqList = GetRequestedOptionsList();
            // Option82?
            var relayInfo = this.GetOptionData(DHCPOption.RelayInfo);
            CreateOptionElement(ref resultOptions, DHCPOption.DHCPMessageTYPE, new byte[] { (byte)msgType });
            // Server identifier - our IP address
            if ((replyOptions != null) && (replyOptions.ServerIdentifier != null))
                CreateOptionElement(ref resultOptions, DHCPOption.ServerIdentifier, replyOptions.ServerIdentifier.GetAddressBytes());

            // Requested options
            if ((reqList != null) && (replyOptions != null))
                foreach (DHCPOption i in reqList)
                {
                    byte[] optionData = null;
                    // If it's force option - ignore it. We'll send it later.
                    if ((otherForceOptions != null) && (otherForceOptions.TryGetValue(i, out optionData)))
                        continue;
                    switch (i)
                    {
                        case DHCPOption.SubnetMask:
                            if (replyOptions.SubnetMask != null)
                                optionData = replyOptions.SubnetMask.GetAddressBytes();
                            break;
                        case DHCPOption.Router:
                            if (replyOptions.RouterIP != null)
                                optionData = replyOptions.RouterIP.GetAddressBytes();
                            break;
                        case DHCPOption.DomainNameServers:
                            if (replyOptions.DomainNameServers != null)
                            {
                                optionData = new byte[] { };
                                foreach (var dns in replyOptions.DomainNameServers)
                                {
                                    var dnsserv = dns.GetAddressBytes();
                                    Array.Resize(ref optionData, optionData.Length + 4);
                                    Array.Copy(dnsserv, 0, optionData, optionData.Length - 4, 4);
                                }
                            }
                            break;
                        case DHCPOption.DomainName:
                            if (!string.IsNullOrEmpty(replyOptions.DomainName))
                                optionData = System.Text.Encoding.ASCII.GetBytes(replyOptions.DomainName);
                            break;
                        case DHCPOption.ServerIdentifier:
                            if (replyOptions.ServerIdentifier != null)
                                optionData = replyOptions.ServerIdentifier.GetAddressBytes();
                            break;
                        case DHCPOption.LogServer:
                            if (replyOptions.LogServerIP != null)
                                optionData = replyOptions.LogServerIP.GetAddressBytes();
                            break;
                        case DHCPOption.StaticRoutes:
                        case DHCPOption.StaticRoutesWin:
                            if (replyOptions.StaticRoutes != null)
                            {
                                optionData = new byte[] { };
                                foreach (var route in replyOptions.StaticRoutes)
                                {
                                    var routeData = route.BuildRouteData();
                                    Array.Resize(ref optionData, optionData.Length + routeData.Length);
                                    Array.Copy(routeData, 0, optionData, optionData.Length - routeData.Length, routeData.Length);
                                }
                            }
                            break;
                        default:
                            replyOptions.OtherRequestedOptions.TryGetValue(i, out optionData);
                            break;
                    }
                    if (optionData != null)
                        CreateOptionElement(ref resultOptions, i, optionData);
                }

            if (GetMsgType() != DHCPMsgType.DHCPINFORM)
            {
                // Lease time
                if (replyOptions != null)
                {
                    var leaseTime = new byte[4];
                    leaseTime[3] = (byte)(replyOptions.IPAddressLeaseTime);
                    leaseTime[2] = (byte)(replyOptions.IPAddressLeaseTime >> 8);
                    leaseTime[1] = (byte)(replyOptions.IPAddressLeaseTime >> 16);
                    leaseTime[0] = (byte)(replyOptions.IPAddressLeaseTime >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.IPAddressLeaseTime, leaseTime);
                    leaseTime[3] = (byte)(replyOptions.RenewalTimeValue_T1);
                    leaseTime[2] = (byte)(replyOptions.RenewalTimeValue_T1 >> 8);
                    leaseTime[1] = (byte)(replyOptions.RenewalTimeValue_T1 >> 16);
                    leaseTime[0] = (byte)(replyOptions.RenewalTimeValue_T1 >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.RenewalTimeValue_T1, leaseTime);
                    leaseTime[3] = (byte)(replyOptions.RebindingTimeValue_T2);
                    leaseTime[2] = (byte)(replyOptions.RebindingTimeValue_T2 >> 8);
                    leaseTime[1] = (byte)(replyOptions.RebindingTimeValue_T2 >> 16);
                    leaseTime[0] = (byte)(replyOptions.RebindingTimeValue_T2 >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.RebindingTimeValue_T2, leaseTime);
                }
            }
            // Other requested options
            if (otherForceOptions != null)
                foreach (var option in otherForceOptions.Keys)
                {
                    CreateOptionElement(ref resultOptions, option, otherForceOptions[option]);
                    if (option == DHCPOption.RelayInfo) relayInfo = null;
                }

            // Option 82? Send it back!
            if (relayInfo != null)
                CreateOptionElement(ref resultOptions, DHCPOption.RelayInfo, relayInfo);

            // Create the end option
            Array.Resize(ref resultOptions, resultOptions.Length + 1);
            Array.Copy(new byte[] { 255 }, 0, resultOptions, resultOptions.Length - 1, 1);
            return resultOptions;
        }
 /// <summary>
 /// Sends DHCP reply
 /// </summary>
 /// <param name="msgType">Type of DHCP message to send</param>
 /// <param name="ip">IP for client</param>
 /// <param name="replyData">Reply options (will be sent if requested)</param>
 public void SendDHCPReply(DHCPMsgType msgType, IPAddress ip, DHCPReplyOptions replyData)
 {
     SendDHCPReply(msgType, ip, replyData, null);
 }
        private byte[] CreateOptionStruct(DHCPMsgType msgType, DHCPReplyOptions replyOptions, Dictionary <DHCPOption, byte[]> otherForceOptions)
        {
            byte[] resultOptions = null;
            // Requested options
            var reqList = GetRequestedOptionsList();
            // Option82?
            var relayInfo = this.GetOptionData(DHCPOption.RelayInfo);

            CreateOptionElement(ref resultOptions, DHCPOption.DHCPMessageTYPE, new byte[] { (byte)msgType });
            // Server identifier - our IP address
            if ((replyOptions != null) && (replyOptions.ServerIdentifier != null))
            {
                CreateOptionElement(ref resultOptions, DHCPOption.ServerIdentifier, replyOptions.ServerIdentifier.GetAddressBytes());
            }

            // Requested options
            if ((reqList != null) && (replyOptions != null))
            {
                foreach (DHCPOption i in reqList)
                {
                    byte[] optionData = null;
                    // If it's force option - ignore it. We'll send it later.
                    if ((otherForceOptions != null) && (otherForceOptions.TryGetValue(i, out optionData)))
                    {
                        continue;
                    }
                    switch (i)
                    {
                    case DHCPOption.SubnetMask:
                        if (replyOptions.SubnetMask != null)
                        {
                            optionData = replyOptions.SubnetMask.GetAddressBytes();
                        }
                        break;

                    case DHCPOption.Router:
                        if (replyOptions.RouterIP != null)
                        {
                            optionData = replyOptions.RouterIP.GetAddressBytes();
                        }
                        break;

                    case DHCPOption.DomainNameServers:
                        if (replyOptions.DomainNameServers != null)
                        {
                            optionData = new byte[] { };
                            foreach (var dns in replyOptions.DomainNameServers)
                            {
                                var dnsserv = dns.GetAddressBytes();
                                Array.Resize(ref optionData, optionData.Length + 4);
                                Array.Copy(dnsserv, 0, optionData, optionData.Length - 4, 4);
                            }
                        }
                        break;

                    case DHCPOption.DomainName:
                        if (!string.IsNullOrEmpty(replyOptions.DomainName))
                        {
                            optionData = System.Text.Encoding.ASCII.GetBytes(replyOptions.DomainName);
                        }
                        break;

                    case DHCPOption.ServerIdentifier:
                        if (replyOptions.ServerIdentifier != null)
                        {
                            optionData = replyOptions.ServerIdentifier.GetAddressBytes();
                        }
                        break;

                    case DHCPOption.LogServer:
                        if (replyOptions.LogServerIP != null)
                        {
                            optionData = replyOptions.LogServerIP.GetAddressBytes();
                        }
                        break;

                    case DHCPOption.StaticRoutes:
                    case DHCPOption.StaticRoutesWin:
                        if (replyOptions.StaticRoutes != null)
                        {
                            optionData = new byte[] { };
                            foreach (var route in replyOptions.StaticRoutes)
                            {
                                var routeData = route.BuildRouteData();
                                Array.Resize(ref optionData, optionData.Length + routeData.Length);
                                Array.Copy(routeData, 0, optionData, optionData.Length - routeData.Length, routeData.Length);
                            }
                        }
                        break;

                    default:
                        replyOptions.OtherRequestedOptions.TryGetValue(i, out optionData);
                        break;
                    }
                    if (optionData != null)
                    {
                        CreateOptionElement(ref resultOptions, i, optionData);
                    }
                }
            }

            if (GetMsgType() != DHCPMsgType.DHCPINFORM)
            {
                // Lease time
                if (replyOptions != null)
                {
                    var leaseTime = new byte[4];
                    leaseTime[3] = (byte)(replyOptions.IPAddressLeaseTime);
                    leaseTime[2] = (byte)(replyOptions.IPAddressLeaseTime >> 8);
                    leaseTime[1] = (byte)(replyOptions.IPAddressLeaseTime >> 16);
                    leaseTime[0] = (byte)(replyOptions.IPAddressLeaseTime >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.IPAddressLeaseTime, leaseTime);
                    leaseTime[3] = (byte)(replyOptions.RenewalTimeValue_T1);
                    leaseTime[2] = (byte)(replyOptions.RenewalTimeValue_T1 >> 8);
                    leaseTime[1] = (byte)(replyOptions.RenewalTimeValue_T1 >> 16);
                    leaseTime[0] = (byte)(replyOptions.RenewalTimeValue_T1 >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.RenewalTimeValue_T1, leaseTime);
                    leaseTime[3] = (byte)(replyOptions.RebindingTimeValue_T2);
                    leaseTime[2] = (byte)(replyOptions.RebindingTimeValue_T2 >> 8);
                    leaseTime[1] = (byte)(replyOptions.RebindingTimeValue_T2 >> 16);
                    leaseTime[0] = (byte)(replyOptions.RebindingTimeValue_T2 >> 24);
                    CreateOptionElement(ref resultOptions, DHCPOption.RebindingTimeValue_T2, leaseTime);
                }
            }
            // Other requested options
            if (otherForceOptions != null)
            {
                foreach (var option in otherForceOptions.Keys)
                {
                    CreateOptionElement(ref resultOptions, option, otherForceOptions[option]);
                    if (option == DHCPOption.RelayInfo)
                    {
                        relayInfo = null;
                    }
                }
            }

            // Option 82? Send it back!
            if (relayInfo != null)
            {
                CreateOptionElement(ref resultOptions, DHCPOption.RelayInfo, relayInfo);
            }

            // Create the end option
            Array.Resize(ref resultOptions, resultOptions.Length + 1);
            Array.Copy(new byte[] { 255 }, 0, resultOptions, resultOptions.Length - 1, 1);
            return(resultOptions);
        }