На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: Oleg2004
  
    > Организация алгоритма протокола определения адрессов, Протокол ARP
      Здравствуйте.

      Помогите пожалуйста разобраться с алгоритмом протокала определения адресов Ethernet (ARP).

      Имеется следующее задание (перевод с англ. возможно что не так прошу меня извинить):
      Цитата

      Программирование Ethernet, IP и C

      Кратко, задача состоит в том, чтобы cпроектировать рабочий алгоритм протокола определения адресов, подходящий для выполнения в связанном сетью хосте с единственным{отдельным} сетевым адаптером.
      Протокол определения адресов (ARP) главным образом используется устройствами, связанными с сетью Ethernet. ARP - протокол, используется для нахождения аппаратного адреса, соответствующего определенному IP адресу. Два устройства, соединенные в сети Ethernet, должны знать адрес аппаратных средств передачи. ARP решает эту проблему динамически.
      Тестовое задание должно быть выполнено на язык программирования - чистый ANSI C. Не разрешается использование C++ или встроенного ассемблерного кода. Допустимые источники - RFC 826, “An Ethernet ARP” (включенные в этот архив), RFC 791, “ Internet Протокол ”, и файлы руководств/справки для стандартных libc-функций.

      Следующий раздел требует чтения и понимания RFC 826.
      Генерал
      Тест не требует интерфейса сетевой связи. Множество включенных функций будет эмулировать сетевую функциональность и деятельность. Кроме того, тест не требует множественный сетевой интерфейс.
      Программа должна быть способна ответить на полученные запросы ARP (протокола определения адресов), так же как и быть способной послать ему собственные запросы.
      Размер ARP кэша ограничен восьмью входами для упрощенной диагностики, хотя это будет обычно содержать тысячи входов.
      "Время жизни" для входа ARP ограничено 30 секундами для упрощенной диагностики, хотя это - обычно не менее 10 раз этого значения.
      Код ANSI C должен быть понятный и откомпилирован с наивысшим уровнем предупреждения, без генерирования предупреждений, например с " - wall" в GCC или 3-м уровнем предупреждения в MSVC. (однако 4-й уровень, генерирует предупреждения заголовках libc-файлов.)
      Код должен быть отказоустойчивым, рабочий и доступный. Все возможные ошибки должны управляться в пути, которым компьютер продолжит работать с минимальными сбоями в процессе связи.
      Не допускается использование malloc (), free() или аналогичных функций. Единственным исключением является функции ARP_Init() и/или ARP_Cleanup().
      Код должен брать ”упорядочивающий байт” в рассмотрение. Все определенные числа протокола должны быть “наиболее значительным первым байтом”, в соответствии с сетевыми стандартами.
      Основные типы данных
      Следующие основные типы данных определены в ”typedefs.h”:
      BYTE - символ без знака
      WORD - короткий int без знака
      DWORD - длинный int без знака
      PVOID - пусто *

      IPADDR - struct {BYTE v [4];}
      PIPADDR - IPADDR *
      ENETADDR - struct {BYTE v [6];}
      PENETADDR - ENETADDR *
      Ethernet
      Каждый пакет, который посылают в сеть Ethernet, имеет общую структуру в пределах первых четырнадцати байтов; заголовок Ethernet. Этот заголовок содержит "Адрес Назначения" полей, “Адрес Отправителя” и "Протокол". Адреса - адреса Ethernet на 48 битов, поле протокола - 16-разрядное целое число. Единственный протокол, представляющий интерес в этом испытании 0x0806 (ARP).
      typedef struct tagENETHDR
      {
      ENETADDR HwDest;
      ENETADDR HwSender;
      WORD wProto;
      } ENETHDR, *PENETHDR;
      Предопределенные Функции
      Некоторые функции уже написаны, чтобы снабдить Вас стандартным интерфейсом. Вы не должны читать код для этих функций, и не при каких обстоятельствах не изменять их.
      PIPADDR Iface_GetIPAddress (void)
      Возвращает указатель на IPADDR struct, содержащий адрес IP компьютера. Эта функция принята, чтобы быть быстрым и надежным.
      PENETADDR Iface_GetENetAddress (void)
      Возвращает указатель на ENETADDR struct, содержащий аппаратный адрес сетевого интерфейса. Эта функция принята, чтобы быть быстрым и надежным.
      void Iface_Send (PVOID pData, DWORD dwLen)
      Посылает пакет, содержащий необработанные данные Ethernet. Данные приняты, чтобы начаться с заголовка Ethernet. Функция не будет автоматически устанавливать исходный адрес в заголовке Ethernet.
      int main (int argc, char *argv [])
      Эта функция вызывает ARP_Init(), UserLoop() и ARP_CleanUp().
      void UserLoop (void)
      Эта функция содержит интерфейс командной строки. Это также вызовет функцию ARP_SecondProcessing каждую секунду.
      char* IPAddrToA (PIPADDR pIPAddr)
      Эта функция переводит бинарный IP адрес в строку. Функция использует внутренние буфера, которые будут разрушены каждым запросом.
      char* ENetAddrToA (PENETADDR pENetAddr)
      Эта функция переводит бинарный аппаратный адрес к строке. Функция использует внутренние буфера, которые будут разрушены каждым запросом.
      WORD htons (WORD wHostOrder)
      WORD ntohs (WORD wNetOrder)
      Переводит 16-разрядное целое число от ведущего упорядочения байта до сетевого упорядочения байта и наоборот.
      DWORD htonl (DWORD dwHostOrder)
      DWORD ntohl (DWORD dwNetOrder)
      Переводит 32-разрядное целое число от ведущего упорядочения байта до сетевого упорядочения байта и наоборот.
      DWORD Time (void)
      Возвращает текущее время в секундах с 1-ого января 1970. Эта функция принята, чтобы быть медленным.
      НЕ объявленные функции
      Следующие функции только объявлены, и должны быть определены в файле ARP.C.
      void ARP_SecondProcessing (void)
      Функцию вызывает UserLoop() каждую секунду. Вы определяете, как это должно использоваться.
      void ARP_ProcessIncoming (PVOID pData, DWORD dwLen)
      Эту функцию вызывают, когда прибыл пакет с протоколом типа 0x0806 (ARP). Никакие тесты не были выполнены на входящих данных. ARP_ProcessIncoming(), как ожидается, исполнит все необходимые испытания. pData - указатель на буфер, содержащий необработанные данные Ethernet.
      void ARP_Init (void)
      Эту функцию вызывают, при запуске программы, и может, например, содержать код для распределения памяти.
      void ARP_Cleanup (void)
      Эта функция должна освободить всю распределенную память и исполнить все другие задачи, требуемые для программы закончиться и/или перезапущенный правильным способом.
      PENETADDR ARP_Query (PIPADDR pIPAddr)
      Эта функция должна искать кэш протокола определения адресов, чтобы узнать аппаратный адрес для данного адреса IP. Если кэш не содержит информацию относительно адреса, функция должна послать запрос на сети и возвращении (PENETADDR) 0. При решении для данных сбоев адреса IP (который является; если целевой хост не существует или недоступен), функция должна возвратиться (PENETADDR)-1.
      void ARP_PrintAll (void)
      Эта функция должна вывести все входы в кэше протокола определения адресов на пульт (экран). Поля, чтобы вывести: Состояние, адрес IP, Ethernet обращается и Целая жизнь мгновенно. Поле состояния должно указать, содержит ли вход допустимую трансляцию или если решение терпело неудачу. Это может также содержать другие значения состояния, необходимые для Вас решить это испытание. Значение Life Time должно указать, сколько секунд вход правилен{допустим}, это никогда не может превышать 30 или быть ниже 0.
      Отклонения от реального мира
      • Пожалуйста обратите внимание, что не возможно послать целенаправленные запросы протокола определения адресов: посылка запросов радиопередачи будет работать, но посылка их к определенному адресу МАКИНТОША не будет работать.
      • Аппаратный адрес отправителя в заголовках Ethernet датаграмм, которые Вы получаете, будет всегда быть полностью случайным аппаратным адресом; Вы никогда не будете вероятно видеть тот же самый адрес, используемый дважды.



      Также есть следующий листинг программы:

      ARP.CPP
      ExpandedWrap disabled
        #include <stdio.h>
        #include <stdlib.h>
        #include "typedefs.h"
        #include "utils.h"
        #include "arp.h"
        /************************************************************************
        * This is where you write your ARP implementation.
        ************************************************************************/
        void ARP_ProcessIncoming(PVOID pData, DWORD dwLen)
        {
          printf("ARP_ProcessIncoming not done.\r\n");
        }
        void ARP_Init(void)
        {
          printf("ARP_Init not done.\r\n");
        }
        void ARP_Cleanup(void)
        {
          printf("ARP_Cleanup not done.\r\n");
        }
        void ARP_SecondProcessing(void)
        {
          /* Whatever... */
        }
        void ARP_PrintAll(void)
        {
          printf("ARP_PrintAll not done.\r\n");
        }
        PENETADDR ARP_Query(PIPADDR pIPAddr)
        {
          printf("ARP_Query not done.\r\n");
          return (PENETADDR)0;
        }


      ARP.H
      ExpandedWrap disabled
        #ifndef __ARP_H__
        #define __ARP_H__
        /************************************************************************
         * Here, you may add definitions needed for your implementation.
         ************************************************************************/
        void ARP_Init(void);
        void ARP_Cleanup(void);
        void ARP_SecondProcessing(void);
        void ARP_PrintAll(void);
        PENETADDR ARP_Query(PIPADDR pIPAddr);
        void ARP_ProcessIncoming(PVOID pData, DWORD dwLen);
        #endif /* __ARP_H__ */

      SECRET.C
      ExpandedWrap disabled
        #include <stdio.h>
        #include <stdlib.h>
        #include <memory.h>
        #include <time.h>
        #include "typedefs.h"
        #include "utils.h"
        #include "arp.h"
        /************************************************************************
        * DO NOT READ THE CONTENTS OF THIS FILE!!!!!
        ************************************************************************/
        #define C6(od,s) Cn(od,s,6)
        #define C4(od,s) Cn(od,s,4)
        #define Cn(od,s,n) memcpy(chBuf+od,s,n)
        #define S6(od, ch) memset(chBuf+od, ch, 6)
        #define WP(p) ((WORD*)(p))
        #define nWP(p) (*WP(p))
        char q[256];
        int ql=0;
        #ifdef _DEV
        #include "dev/dev.inl"
        #endif
        void Iface_Send(PVOID pData, DWORD dwLen)
        {
          /* If, after all, you're reading this. DON'T code this way.
           * It just looks this way to make it hard for you to read the code :) */
         
        void ARP_SimulatReceivedQuery(void);
        {
           BYTE *pch=pData;
           if(nWP(pch+16)==8 && dwLen>=42 &&  pch[0]==255 && pch[1]==255 && pch[19]==4 &&
              !memcmp(pch+6, (char*)Iface_GetENetAddress(), 6) &&
              nWP(pch+12)==0x0608 && pch[4]==255 && pch[5]==255 && nWP(pch+14)==256 &&
              pch[18]==6 && nWP(pch+20)==256 && (rand()&15)!=0 && pch[2]==255 && pch[3]==255 )
           {
            ql=42;
            memcpy(q, pch, 42);
            q[6]=rand();
            q[7]=rand();
            q[8]=rand();
            q[9]=rand();
            q[10]=rand();
            q[11]=rand();
            memcpy(q, pch+6, 6);
            memcpy(q+22, pch+32, 10);
            memcpy(q+32, pch+22, 10);
            memcpy(q+22, q+6, 6);
            nWP(q+20)=512;
           }
         }
        }
         
        PIPADDR Iface_GetIPAddress(void)
        {
        static BYTE c[4]={192,168,11,1};
        return (PIPADDR) c;
        }
         
        PENETADDR Iface_GetENetAddress(void)
        {
        static BYTE c[6]={0,32, 0x1a, 0x22, 0x7f, 0x9b};  
        return (PENETADDR) c;
        }
         
        void ARP_SimulateReceivedQuery(void)
        {
        BYTE chBuf[42];
        int n;
        for(n=0;n<42;n++)
        chBuf[n]=(BYTE)rand();
        C6(22,chBuf);
        S6((n&129),0xff);
        S6((n=32), 0);
        nWP(chBuf+12)=(193<<3);
        n+=6;
        C4(n,Iface_GetIPAddress());
        n-=6;
        chBuf[-13+n]=4;
        chBuf[50-n]=chBuf[(n>>1)+3]+2;
        nWP(chBuf+16)=8;
        nWP(chBuf+14)=nWP(chBuf+(n>>1)+4)=256;
        ARP_ProcessIncoming(chBuf, 42);
        }
         
        void Secret_SecondProcessing(void)
        {
          if(ql)
          {
             ARP_ProcessIncoming(q, ql);
             ql=0;
          }
        }


      TYPEDEFS.H
      ExpandedWrap disabled
        #ifndef __TYPEDEFS_H__
        #define __TYPEDEFS_H__
        /*************** Do NOT alter this file!! *****************/
        #define TRUE  (1)
        #define FALSE  (0)
         
        typedef int BOOL;
        typedef unsigned char BYTE;
        typedef unsigned short int WORD;
        typedef unsigned long int DWORD;
        typedef void *PVOID;
        typedef struct tagIPADDR
        {
          BYTE v[4];
        } IPADDR, *PIPADDR;
        typedef struct tagENETADDR
        {
          BYTE v[6];
        } ENETADDR, *PENETADDR;
        typedef struct tagENETHDR
        {
          ENETADDR HwDest;
          ENETADDR HwSender;
          WORD wProto;
        } ENETHDR, *PENETHDR;
        #endif /* __TYPEDEFS_H__ */

      UTILS.C
      ExpandedWrap disabled
        #include <stdio.h>
        #include <stdlib.h>
        #include <memory.h>
        #include <time.h>
        #include "typedefs.h"
        #include "utils.h"
        #include "arp.h"
        /*************** BELOW MAY NEED TO BE CHANGED FOR YOUR PLATFORM!!!! */
        #include <conio.h>
        BOOL KBHit(void)
        {
          return (BOOL)kbhit();
        }
        int Getch(void)
        {
          return getch();
        }
        DWORD Time(void)
        {
          return (DWORD)time(NULL);
        }
        /*************** ABOVE MAY NEED TO BE CHANGED FOR YOUR PLATFORM!!!! */
        /* Forward declarations of functions exported from secret.c */
        void ARP_SimulateReceivedQuery(void);
        void Secret_SecondProcessing(void);
        /****************************************************************************
         * Function : __ntohs, __ntohl
         * Purpose  : Change byte order of a short and long int, respectively
         * Returns  : The byte (and word) swapped result of the original value
         ***************************************************************************/
        WORD __ntohs(WORD w)
        {
          return (w<<8) | (w>>8);
        }
        DWORD __ntohl(DWORD dw)
        {
          return (dw<<24) | (dw>>24) | ( (dw&0x00ff0000) >> 8 ) | ( (dw&0x0000ff00) << 8);
        }
        /****************************************************************************
        * Function : ENetAddrToA
        * Purpose  : Translate an ENETADDR value to an ASCIIZ string
         *            The result is stored in an internal, static buffer
         *            that is overwritten each time this function is called.
         *            It is not suitable for multithreading, and cannot
         *            be called multiple times in the same parsing context.
        * Returns  : A char pointer to a static buffer containing the result string
        ***************************************************************************/
        char* ENetAddrToA(PENETADDR p)
        {
          static char szBuf[20];
          sprintf(szBuf, "%02x%02x:%02x%02x:%02x%02x",
            ((BYTE*)p)[0],
            ((BYTE*)p)[1],
            ((BYTE*)p)[2],
            ((BYTE*)p)[3],
            ((BYTE*)p)[4],
            ((BYTE*)p)[5]
          );
          return szBuf;
        }
        /****************************************************************************
        * Function : IPAddrToA
        * Purpose  : Translate an IPADDR value to an ASCIIZ string
         *            The result is stored in an internal, static buffer
         *            that is overwritten each time this function is called.
         *            It is not suitable for multithreading, and cannot
         *            be called multiple times in the same parsing context.
        * Returns  : A char pointer to a static buffer containing the result string
        ***************************************************************************/
        char* IPAddrToA(PIPADDR p)
        {
          static char szBuf[20];
          sprintf(szBuf, "%i.%i.%i.%i",
            ((BYTE*)p)[0],
            ((BYTE*)p)[1],
            ((BYTE*)p)[2],
            ((BYTE*)p)[3]
          );
          return szBuf;
        }
        /****************************************************************************
        * Function : UserLoop
        * Purpose  : Prompt the user for input, take appropriate action
         *            Call the various xxxx_SecondProcessing() functions
         *            once per second.
        * Returns  : -
        ***************************************************************************/
        void UserLoop(void)
        {
          static int c;
          static DWORD dwNow=0;
          static IPADDR aIPAddr[10]=
          {
            {192,168,22,5},
            {192,168,22,15},
            {192,168,22,17},
            {192,168,22,19},
            {192,168,22,33},
            {192,168,22,35},
            {192,168,22,47},
            {192,168,22,99},
            {192,168,22,195},
            {192,168,22,222}
          };
          srand((unsigned int)Time());
          printf("ARP Algorithm Tester\r\n");
          printf("Press keys 0--9 to have this computer query the network\r\n"
                 "   for one of ten IP addresses\r\n");
          printf("Press R to simulate receiving an ARP query.\r\n");
          printf("Press L to list ARP cache contents\r\n");
          printf("Press [esc] to exit\r\n");
          printf("\r\n>");
          while(TRUE)
          {
            if(Time()!=dwNow)
            {
              int nRand=rand()&1;
              dwNow=Time();
              if(nRand)
                Secret_SecondProcessing();
              ARP_SecondProcessing();
              if(!nRand)
                Secret_SecondProcessing();
            }
            if(!KBHit())
              continue;
            c=Getch();
            if(c==27)
            {
              printf("\r   \r\n");
              return;
            }
            else if(c>='0' && c<='9')
            {
              int n = c-'0';
              PENETADDR pENetAddr;
              printf("Query for address %s returns : ", IPAddrToA(aIPAddr+n));
              pENetAddr = ARP_Query(aIPAddr+n);
              if(pENetAddr == (PENETADDR) 0)
                printf("Address not resolved yet.\r\n");
              else if(pENetAddr == (PENETADDR) -1)
                printf("Address could not be resolved.\r\n");
              else
                printf("%s\r\n", ENetAddrToA(pENetAddr));
            }
            else if(c=='r' || c=='R')
            {
              ARP_SimulateReceivedQuery();
            }
            else if(c=='l' || c=='L')
            {
              printf("Contents of the ARP cache:\r\n");
              ARP_PrintAll();
              printf("\r\n>");
            }
          }
        }
        /****************************************************************************
        * Function : main
        * Purpose  : Call ARP_Init, UserLoop and then ARP_Cleanup
        * Returns  : 0
        ***************************************************************************/
         
        int main(int argc, char *argv[])
        {
          ARP_Init();
          UserLoop();
          ARP_Cleanup();
          return 0;
        }


      UTILS.H
      ExpandedWrap disabled
        #ifndef __UTILS_H__
        #define __UTILS_H__
        /*************** Do NOT alter this file!! *****************/
        DWORD Time(void);
        char* IPAddrToA(PIPADDR pIPAddr);
        char* ENetAddrToA(PENETADDR pENetAddr);
        PIPADDR Iface_GetIPAddress(void);
        PENETADDR Iface_GetENetAddress(void);
        void Iface_Send(PVOID pData, DWORD dwLen);
        WORD __ntohs(WORD w);
        DWORD __ntohl(DWORD dw);
        #if 1
          /* Use 1 if host byte ordering is different from network byte ordering
           * Otherwise use 0
           * "1" is necessary for Intel CPU's, for instance.   */
            #define htons(x) __ntohs(x)
          #define ntohs(x) __ntohs(x)
            #define htonl(x) __ntohl(x)
          #define ntohl(x) __ntohl(x)
        #else
            #define htons(x) (x)
          #define ntohs(x) (x)
            #define htonl(x) (x)
          #define ntohl(x) (x)
        #endif
        BOOL KBHit(void);
        int Getch(void);
        #endif /* __UTILS_H__ */


      Если я правильно понял в файле ARP.C нужно заполнить следующие методы для организации работы ARP:
      ExpandedWrap disabled
        void ARP_ProcessIncoming(PVOID pData, DWORD dwLen)
        void ARP_Init(void)
        void ARP_Cleanup(void)
        void ARP_SecondProcessing(void)
        void ARP_PrintAll(void)
        PENETADDR ARP_Query(PIPADDR pIPAddr)


      С сетями иметь дело не доводилось, а из прочтенных RFC 826 и RFC 971 я ничего не поял.

      Подскажите пожалуйста как можно выполнить это задание и если е трудно предоставить пример на ANSII C, без использоваия С++ и встроенного ассемблерного кода.

      Буду примного благодарен.

      Если есть какие ссылки на источники то укажите пожалуйста.

      Спасибо.
        did you still have the issue
        1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script Execution time: 0,0929 ]   [ 15 queries used ]   [ Generated: 23.10.19, 03:24 GMT ]