Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker Hacker

Dark-forum

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Dark-forum » Исходные коды » Небольшой DHCP сервер


Небольшой DHCP сервер

Сообщений 1 страница 20 из 284

1

Небольшой DHCP сервер

Иногда, нужен исходник простой DHCP-службы, чтобы добавить её функциональность к себе в проект, а не использовать для этого полноценный DHCP сервер. Например, в локальной сети, есть главный сервер DHCP, который выделяет компьютерам IP-адреса, и есть также небольшой сервер DHCP, который выделяет определённый IP-адрес только конкретному устройству. Так как DHCP-протокол работает через UPD, то данные можно посылать широковещательно (а не точка-точка), соответственно и подхватить их в сети можно легко. Для этого мы будем воспольльзуемся простым алгоритмом фильтрации, который будет фильтровать запросы и выдавать IP-адреса только разрешенным MAC-адресам.

Определение DHCP

DHCP расшифровывается как Dynamic Host Configuration Protocol и состоит из двух компонент: клиент DHCP (сетевое устройство запрашивающее IP-настройки), и DHCP-сервер (Интернет-узел, который возвращает параметры конфигурации запросившему клиенту).

Краткое описание того, как работает небольшой DHCP-сервер

DHCP-сервер обычно устанавливается в локальной сети, и используется для централизованного выделения конфигураций TCP-IP сетевым устройствам или компьютерам с установкой автоматического получения айпишника. DHCP-сервер ожидает запросы на UDP-порте номер 67 и отправляет данные клиентам так же на UDP-порт 67. Служба UDP использует асинхронный метод с использованием функции обратного вызова:

//эта функция запускает слушающий UDP-сервис

private void IniListnerCallBack()
{
    try
    {
        // start teh recieve call back method
        s.u.BeginReceive(new AsyncCallback(OnDataRecieved), s);
    }
    catch (Exception ex)
    {
        if (IsListening == true)
        Console.WriteLine(ex.Message);
    }
}

// Это коллбэк функция, которая вызывает в момент приёма данных.
// переменная asyn должна содержать экземпляр UPD-структуры (UDPstate)

public void OnDataRecieved(IAsyncResult asyn)
{   
    Byte[] receiveBytes;
    UdpClient u;
    IPEndPoint e;

    try
    {
        //получаем udp-пакет клиента

          u = (UdpClient)((UdpState)(asyn.AsyncState)).u;
        //get the endpoint (shall contain refernce about the  client)

          e = (IPEndPoint)((UdpState)(asyn.AsyncState)).e;
        //останавливаем коллбэк и получаем количество принятых байт

        receiveBytes = u.EndReceive(asyn, ref e);
        //генерируем событие с полученными данными в DHCP-класс

        DataRcvd(receiveBytes, e);
    }   
    catch (Exception ex)
    {
        if (IsListening == true)
            Console.WriteLine(ex.Message);
    }
    finally
    {
        u = null;
        e = null;
        receiveBytes = null;
        // Заново запускаем слушающий сервис

        IniListnerCallBack();
    }   
}
UDP-клиент должен быть запущен и слушать в сети входящие запросы. Каждое сообщение должно идентифицироваться уникальным МАС-адресом и номером транзакции (Transaction ID (D_xid) - это случайное число, сгенерированное клиентом). При обмене данные передаются как поток байтов и формат должен соответствовать следующей RFC-структуре:

public struct DHCPstruct
{
    public byte D_op; //Op код: 1 = bootRequest, 2 = BootReply

    public byte D_htype; //Тип физического адреса: 1 = 10MB эзернет

    public byte D_hlen; //длина физического адреса: длина MACID

    public byte D_hops; //физические опции

    public byte[] D_xid; //transaction id (5),

    public byte[] D_secs; //elapsed time from trying to boot (3)

    public byte[] D_flags; //флаги (3)

    public byte[] D_ciaddr; // IP клиента (5)

    public byte[] D_yiaddr; // IP вашего клиента (5)

    public byte[] D_siaddr; // IP сервера (5)

    public byte[] D_giaddr; // relay agent IP (5)

    public byte[] D_chaddr; // физический адрес клиента (16)

    public byte[] D_sname; // Необязательное имя сервера (64)

    public byte[] D_file; // имя бут-файла (128)

    public byte[] M_Cookie; // Магические кукисы (4)

    public byte[] D_options; //опции (rest)

}
Таким образом, данные передаются в DHCP-класс через событие как поток байтов. Для этого воспользуемся .NET-классом BinaryReader, чтобы помещать байты в соответствующем порядке. OPTION_OFFSET - константа, определяющая место, с которого начинаются данные DHCP-структуры:

//pass over a byte as convert it
//using the predefined stream reader function

//Data is an array containing the udp data sent.

public cDHCPStruct(byte[] Data)
{
    System.IO.BinaryReader rdr;
    System.IO.MemoryStream stm =
       new System.IO.MemoryStream(Data, 0, Data.Length);
    try
    {    //читаем данные

               dStruct.D_op = rdr.ReadByte();
               dStruct.D_htype = rdr.ReadByte();
               dStruct.D_hlen = rdr.ReadByte();
               dStruct.D_hops = rdr.ReadByte();
               dStruct.D_xid = rdr.ReadBytes(4);
               dStruct.D_secs = rdr.ReadBytes(2);
               dStruct.D_flags = rdr.ReadBytes(2);
               dStruct.D_ciaddr = rdr.ReadBytes(4);
               dStruct.D_yiaddr = rdr.ReadBytes(4);
               dStruct.D_siaddr = rdr.ReadBytes(4);
               dStruct.D_giaddr = rdr.ReadBytes(4);
               dStruct.D_chaddr = rdr.ReadBytes(16);
               dStruct.D_sname = rdr.ReadBytes(64);
               dStruct.D_file = rdr.ReadBytes(128);
               dStruct.M_Cookie = rdr.ReadBytes(4);
        //читаем остальные данные

               dStruct.D_options = rdr.ReadBytes(Data.Length - OPTION_OFFSET);
    }
    catch(Exception ex)
    {
        Console.WriteLine (ex.Message);
    }
}
Клиент, запрашивающий адрес IP также должен передать серверу список опций, которые сервер должен заполнить и передать обратно клиенту. Опции, которые можно передать в списке определены в RFC и могут содержать следующие значения:

public enum DHCPOptionEnum
{
    SubnetMask = 1,
    TimeOffset = 2,
    Router = 3,
    TimeServer = 4,
    NameServer = 5,
    DomainNameServer = 6,
    LogServer = 7,
    CookieServer = 8,
    LPRServer = 9,
    ImpressServer = 10,
    ResourceLocServer = 11,
    HostName = 12,
    BootFileSize = 13,
    MeritDump = 14,
    DomainName = 15,
    SwapServer = 16,
    RootPath = 17,
    ExtensionsPath = 18,
    IpForwarding = 19,
    NonLocalSourceRouting = 20,
    PolicyFilter = 21,
    MaximumDatagramReAssemblySize = 22,
    DefaultIPTimeToLive = 23,
    PathMTUAgingTimeout = 24,
    PathMTUPlateauTable = 25,
    InterfaceMTU = 26,
    AllSubnetsAreLocal = 27,
    BroadcastAddress = 28,
    PerformMaskDiscovery = 29,
    MaskSupplier = 30,
    PerformRouterDiscovery = 31,
    RouterSolicitationAddress = 32,
    StaticRoute = 33,
    TrailerEncapsulation = 34,
    ARPCacheTimeout = 35,
    EthernetEncapsulation = 36,
    TCPDefaultTTL = 37,
    TCPKeepaliveInterval = 38,
    TCPKeepaliveGarbage = 39,
    NetworkInformationServiceDomain = 40,
    NetworkInformationServers = 41,
    NetworkTimeProtocolServers = 42,
    VendorSpecificInformation = 43,
    NetBIOSoverTCPIPNameServer = 44,
    NetBIOSoverTCPIPDatagramDistributionServer = 45,
    NetBIOSoverTCPIPNodeType = 46,
    NetBIOSoverTCPIPScope = 47,
    XWindowSystemFontServer = 48,
    XWindowSystemDisplayManager = 49,
    RequestedIPAddress = 50,
    IPAddressLeaseTime = 51,
    OptionOverload = 52,
    DHCPMessageTYPE = 53,
    ServerIdentifier = 54,
    ParameterRequestList = 55,
    Message = 56,
    MaximumDHCPMessageSize = 57,
    RenewalTimeValue_T1 = 58,
    RebindingTimeValue_T2 = 59,
    Vendorclassidentifier = 60,
    ClientIdentifier = 61,
    NetworkInformationServicePlusDomain = 64,
    NetworkInformationServicePlusServers = 65,
    TFTPServerName = 66,
    BootfileName = 67,
    MobileIPHomeAgent = 68,
    SMTPServer = 69,
    POP3Server = 70,
    NNTPServer = 71,
    DefaultWWWServer = 72,
    DefaultFingerServer = 73,
    DefaultIRCServer = 74,
    StreetTalkServer = 75,
    STDAServer = 76,
    END_Option = 255
}
В массиве байтов список опций будет выглядеть следующим образом:

-------------------------------------------------
|a|len|Message|a|len|Message|........|END_OPTION|
-------------------------------------------------
где:

•"а" означает начало кода опции, как показано выше •len - длина сообщения в байтах •Message - передаваемое сообщение, длина которого определена в len •END_OPTION - означает конец сообщения с настройками

Тип сообщения (message type)

Тип сообщения находится в списке опций под номером 53 и определяет текущее соостояние переговоров клиента и сервера:
public enum DHCPMsgType //Типы сообщений, описанные в RFC

{
    DHCPDISCOVER = 1,   //клиент пытается найти dhcp-сервера

    DHCPOFFER = 2,     //сервер предлагает IP-адреса устройству

    DHCPREQUEST = 3,   //клиент согласен принять айпишник от DHCP-сервера

    DHCPDECLINE = 4,   //клиент отверг предложенный адрес

    DHCPACK = 5,       //server to client + committed IP address

    DHCPNAK = 6,       //server to client to state net address incorrect

    DHCPRELEASE = 7,   //graceful shutdown from client to Server

    DHCPINFORM = 8     //клиент запрашивает локальную информацию

}
В коде, это должно быть реализовано как сообщение из DHCP-класса в главную форму:

//an event has to call a delegate (function pointer)

#region "event Delegates"
    public delegate void AnnouncedEventHandler(cDHCPStruct d_DHCP,string MacId);
    public delegate void ReleasedEventHandler();//(cDHCPStruct d_DHCP);

    public delegate void RequestEventHandler(cDHCPStruct d_DHCP, string MacId);
    public delegate void AssignedEventHandler(string IPAdd,string MacID );
#endregion
    public event AnnouncedEventHandler Announced;
    public event RequestEventHandler Request;
Перед тем как назначить IP-адресс, необходимо воспользоваться фреймфорковский классом Ping, чтобы проверить, не используется ли уже это айпишник.

public static bool CheckAlive(string IpAdd)
{
    Ping pingSender = new Ping();
    IPAddress address;
    PingReply reply;

        try
        {
        address = IPAddress.Parse(IpAdd);//IPAddress.Loopback;

                reply = pingSender.Send(address,100);
                if (reply.Status == IPStatus.Success)
                {
                     Console.WriteLine("Address: {0}",
                                       reply.Address.ToString());
                     Console.WriteLine("RoundTrip time: {0}",
                                       reply.RoundtripTime);
                     Console.WriteLine("Time to live: {0}",
                                       reply.Options.Ttl);
                     Console.WriteLine("Don't fragment: {0}",
                                       reply.Options.DontFragment);
                     Console.WriteLine("Buffer size: {0}",
                                       reply.Buffer.Length);
                     return true;
                 }
                 else
                 {
                     Console.WriteLine(reply.Status);
                     return false;
                 }
     }
        catch (Exception ex)
        {
                 MessageBox.Show(ex.Message);
                return false;
        }
        finally
        {
                if (pingSender != null)  pingSender.Dispose();
                pingSender = null;
                address = null;
                reply = null;
        }
}
Затем наше приложение должно конвертировать данные из структуры в поток байтов, используя для этого класс Array:

//функция для преобразования структуры данных в массив байт

private byte[] BuildDataStructure(cDHCPStruct.DHCPstruct ddHcpS)       
{           
    byte[] mArray;
        try
    {
        mArray = new byte[0];
        AddOptionElement(new byte[] { ddHcpS.D_op }, ref mArray);
        AddOptionElement(new byte[] { ddHcpS.D_htype }, ref mArray);
        AddOptionElement(new byte[] { ddHcpS.D_hlen }, ref mArray);
        AddOptionElement(new byte[] { ddHcpS.D_hops }, ref mArray);
        AddOptionElement(ddHcpS.D_xid, ref mArray);
        AddOptionElement(ddHcpS.D_secs, ref mArray);
        AddOptionElement(ddHcpS.D_flags, ref mArray);
        AddOptionElement(ddHcpS.D_ciaddr, ref mArray);
        AddOptionElement(ddHcpS.D_yiaddr, ref mArray);
        AddOptionElement(ddHcpS.D_siaddr, ref mArray);
        AddOptionElement(ddHcpS.D_giaddr, ref mArray);
        AddOptionElement(ddHcpS.D_chaddr, ref mArray);
        AddOptionElement(ddHcpS.D_sname, ref mArray);
        AddOptionElement(ddHcpS.D_file, ref mArray);
        AddOptionElement(ddHcpS.M_Cookie, ref mArray);
        AddOptionElement(ddHcpS.D_options, ref mArray);
        return mArray;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        return false;
    }
    finally
    {
        marray = null;
    }
}

//function to grow an array, we shall pass
//the array back by using references

private void AddOptionElement(byte[] FromValue, ref byte[] TargetArray)   
{
    try
    {
        //меняем размер массива соответственно

        if (TargetArray != null)
            Array.Resize(ref TargetArray,
               TargetArray.Length + FromValue.Length );
        else
             Array.Resize(ref TargetArray, FromValue.Length );
        //копируем данные

        Array.Copy(FromValue, 0, TargetArray,
            TargetArray.Length - FromValue.Length,
            FromValue.Length);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Заключение

Приведённый в этой статье код делится на три основных класса: асинхронный UDP сервис, конвертор DHCP-структуры и главная форма. Общаются они между собой при помощи событий, однако, можно использовать и обратные вызовы (колбэки). Важно отметить, что при вызове управления из события, события должны быть мультикастовыми и необходимо использовать Invoke.

2

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

3

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

4

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

5

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

6

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

7

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

8

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

9

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

10

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

11

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

12

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

13

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

14

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

15

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

16

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

17

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

18

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

19

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.

20

Скрытый текст:

Для просмотра скрытого текста - войдите или зарегистрируйтесь.


Вы здесь » Dark-forum » Исходные коды » Небольшой DHCP сервер


Рейтинг форумов | Создать форум бесплатно