ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Window 에서 패킷 스니핑 프로그램. (TCP/IP 헤더부 출력)
    Programming/TCP/IP 2008. 10. 20. 15:57



    pcap용 헤더파일과 라이브러리 경로를 추가후 win32 콘솔에서 작성


    /////////////////////////    IP_Data.h   /////////////////////////




    #define ETH_ALEN 6                // 출발및 도착지 주소의 크기 정의
    struct MEC_Ether_header
    {
      u_int8_t  ether_dhost[ETH_ALEN];      // 도착지 이더넷 주소
      u_int8_t  ether_shost[ETH_ALEN];      // 출발지 이더넷 주소
      u_int16_t ether_type;            // 패킷 타입 ID 필드

    };



    #pragma pack(push,1)

    struct MEC_Ip_header{

      unsigned char  ip_hl:4;        // 헤더 길이
      unsigned char  ip_v:4;          // 버전

      unsigned char  ip_tos:8;          // 서비스 타입
      u_short      ip_len;          // 전체길이
      u_short      ip_id;          // 식별자
      u_short      ip_off;          // 플래그, 오프셋 필드
      
      u_int8_t    ip_ttl;          // TTL
      u_int8_t    ip_p;          // 프로토콜
      u_short      ip_sum;          // 체크섬

      struct in_addr ip_src;          // 출발지 IP주소
      struct in_addr ip_dst;          // 도착지 IP주소

    };
    #pragma pack(pop)








    /////////////////////////    main.c   /////////////////////////



    #include "pcap.h"
    #include "remote-ext.h"
    #include "IP_Data.h"

    #pragma comment(lib,"Ws2_32.lib")    // 라이브러리파일 수동 추가 
    #pragma comment(lib,"wpcap.lib")    // 라이브러리파일 수동 추가 

    #define MY_PACKETTIME 1000          // 패킷 Timeout ms단위
                        //(0이면 패킷이들어올때까지 기다림)

    void HexPrint( void * , u_int );    // 사용자정의 함수


    int        iCnt;          // For문 계산용

    int main()
    {
      pcap_if_t *    alldevs;      // 네트워크관련 모든 장치
      pcap_if_t *    devsTemp;      // 장치출력을 위한 TEMP포인터
      pcap_t *    adhandle;      // 사용할장치 핸들러

      int        inum;        // 장치번호 선택 입력용
      int        i=0;        // 장치번호 선택 출력용
      int        res;
      

      char      errbuf[PCAP_ERRBUF_SIZE];  // 에러를 위한 char *
      char      timestr[16];      // 시간출력을 위한 char *
      const u_char *  pkt_data;        // 실제 모든 패킷

      time_t      local_tv_sec;      // 시간 ms
      struct tm *    ltime;          // 현재시간단위 구조체

      struct pcap_pkthdr *header;        // 시간, 길이를 가지고있는 구조체
      struct MEC_Ether_header *  pEth;    // 이더넷 헤더 *
      struct MEC_Ip_header *    pIph;    // IP헤더 * 

      

      if (pcap_findalldevs(&alldevs, errbuf) == -1)
      {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
      }


      // 전체 장치의 이름과 경로 획득
      for(devsTemp=alldevs; NULL != devsTemp; devsTemp=devsTemp->next)
      {
        printf("%d.  name  [%s]\n", ++i, devsTemp->name);
        if (devsTemp->description)
          printf("   랜카드 [%s]\n\n", devsTemp->description);
        else
          printf(" (No description available)\n");
      }



      if(i==0)    // 연결된 장치가 없을때 종료
      {
        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return -1;
      }


      // 전체 장치의 이름과 경로 획득
      printf("Enter the interface number (1-%d):",i);

      scanf_s("%d"&inum);      // 몇번 장치로부터 읽을껀지 입력받는다

      if(inum < 1 || inum > i)    // 장치번호 입력이 잘못되었을때 종료
      {
        printf("\nInterface number out of range.\n");
        pcap_freealldevs(alldevs);                
        return -1;
      }



      // 장치선택
      for(devsTemp=alldevs, i=0; i< inum-1 ;devsTemp=devsTemp->next, i++);



      // 선택된 장치 열기
      adhandle= pcap_open(devsTemp->name,    // name of the device
        1500,                // 읽어들일때 최대 크기 (1500 == Ether)
        PCAP_OPENFLAG_PROMISCUOUS,      // (난잡한)모드 - 내컴퓨터 and 다른사람 컴퓨터
        MY_PACKETTIME,            // 패킷 TimeOut 설정 
        NULL,                // authentication on the remote machine   
        errbuf                // 열때 잘못되면 에러를 여기에 넣어준다 
        ); 
      
      
      if ( adhandle == NULL)          // 장치를 열지 못하면 종료
      {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", devsTemp->name);
        pcap_freealldevs(alldevs);
        return -1;                  
      }

      printf("\n[%s] 로부터 읽는중...\n", devsTemp->description);    // "읽는중...." 출력  

      pcap_freealldevs(alldevs);                // 장치 연후 필요가 없으므로 해제



      /* 실제 패킷 캡처 */
      // (연 장치핸들러, 시간및 길이 구조체, 실제 패킷)
      res = pcap_next_ex(adhandle, &header, &pkt_data);    


      if(res <= 0)  // 캡쳐한 패킷이 없으면 종료 
      {
        printf("패킷을 얻지 못했습니다.\n");
        printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
        return -1;
      }



      local_tv_sec = header->ts.tv_sec;            // 캡쳐했을때의 시스템 시간
      ltime=localtime(&local_tv_sec);              // 현재의 시간으로 바꾼다
      strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);  // 시, 분, 초로 바꾼다

      // Micro Sec ,  len:( 건져올린 Data의 길이 )  시간 출력 
      printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);    








      // 이더넷 헤더를 구조체 포인터에 대입 (Eth 헤더 구조체)
      pEth = (struct MEC_Ether_header *)pkt_data;    

      // 이더넷 헤더를 읽고난뒤의 주소   (Ip 헤더 구조체)
      pIph = (struct MEC_Ip_header*)(pkt_data + sizeof(*pEth));  







      /* Eth 헤더 출력부 시작 */

      printf("============================ETH HEADER==========================\n");  

      fprintf(stdout, "DESTINATION Physical Address - [");        // 도착지 Eth주소 출력
      for(iCnt = 0 ; iCnt < 6 ; ++iCnt)
      {
        fprintf(stdout, "%02X:", pEth->ether_dhost[iCnt]);
      }
      fprintf(stdout, "\b]\t\t\n");



      fprintf(stdout, "SOURCE      Physical Address - [");        // 출발지 Eth주소 출력
      for(iCnt = 0 ; iCnt < 6 ; ++iCnt)
      {
        fprintf(stdout, "%02X:", pEth->ether_shost[iCnt]);
      }
      fprintf(stdout, "\b]\n");


      // 프로토콜 16진수
      fprintf(stdout, "next protocal                - [0x%04x]   (", ntohs(pEth->ether_type));


      // 프로토콜 형식 출력
      switch(ntohs(pEth->ether_type))
      {
        case 0x0800:
        fprintf(stdout, "IP) 입니다.\n");
        break;

        case 0x0200:
        fprintf(stdout, "PUP) 입니다.\n");
        fprintf(stdout, "해석하지못하여 프로그램을 종료합니다. -_-;\n");
        return -100;

        case 0x0860:
        fprintf(stdout, "ARP) 입니다.\n");
        fprintf(stdout, "해석하지못하여 프로그램을 종료합니다. -_-;\n");
        return -100;

        case 0x8035:
        fprintf(stdout, "RARP) 입니다.\n");
        fprintf(stdout, "해석하지못하여 프로그램을 종료합니다. -_-;\n");
        return -100;

        default:
        fprintf(stdout,"...) 알수없는 형식입니다.\n");
        fprintf(stdout, "해석하지못하여 프로그램을 종료합니다. -_-;\n");
        return -100;
      }
      
      printf("================================================================\n\n");

      /* Eth 헤더 출력부 끝 */





      /* Ip 헤더 출력부 시작*/
      printf("=============================IP HEADER===========================\n");
      
      /* 버전표시 시작*/
      fprintf(stdout, "VERS                    - [%d]    ", pIph->ip_v);  
      switch(pIph->ip_v)
      {
      case 4:
        fprintf(stdout, "(IPv4)");
        break;

      case 6:
        fprintf(stdout, "(IPv6)");
        break;

      default:
        fprintf(stdout, "(알수없는 버전)");
        break;
      }
      printf("\n");                            
      /* 버전표시 끝*/



      if(20 <= ((pIph->ip_hl)*4) )  // 헤더의 길이 (5x4)Byte  20보다 클경우 출력
      {
        fprintf(stdout, "H.LEN                   - [%d Byte]\n", (pIph->ip_hl)*4);    
      }
      else              // 20보다 작을경우 종료
      {
        fprintf(stdout, "패킷이 잘못된거 같아서 프로그램을 종료합니다.\n");
        return -100;
      }



      /*서비스 타입 체크 시작*/ 
      fprintf(stdout, "SERVICE TYPE            - [0x%X]  (",pIph->ip_tos);      
      switch(pIph->ip_tos)
      {
        case 0x1E:
          fprintf(stdout, "IPTOS_TOS_MASK");

        case 0x10:
          fprintf(stdout, "IPTOS_LOWDELAY");
          break;

        case 0x08:
          fprintf(stdout, "IPTOS_THROUGHPUT");
          break;

        case 0x04:
          fprintf(stdout, "IPTOS_RELIABILITY");
          break;

        case 0x02:
          fprintf(stdout, "IPTOS_MINCOST");
          break;

        default:
          fprintf(stdout, "BASE");
          break;
      }
      fprintf(stdout,")\n");                              
      /*서비스 타입 체크 끝*/ 




      // 헤더 + Data의 전체길이
      fprintf(stdout, "TOTAL LENGTH            - [%d Byte]\n", pIph->ip_len);       

      // 식별 ID
      fprintf(stdout, "IDENTIFICATION          - [0x%X]\n", pIph->ip_id);       





      // Do Not Fragment
      fprintf(stdout, "(Flag)Do not Fragment   - ");
      if0x4000  == ((ntohs(pIph->ip_off)) & 0x4000) )
      {
        fprintf(stdout, "[1]  (해당 패킷을 폐기)");
      }
      else
      {

        fprintf(stdout, "[0]  (정상 단편화된 패킷)");
      }
      printf("\n");



      // More Fragment
      fprintf(stdout, "(Flag)More Fragment     - ");
      if0x2000  == ((ntohs(pIph->ip_off)) & 0x2000) )
      {
        fprintf(stdout, "[1]  (단편화된 패킷 더 있습니다.)");
      }
      else
      {
        fprintf(stdout, "[0]  (마지막 패킷 입니다.)");
      }  
      printf("\n");



      // 단편화된 Data의 길이
      fprintf(stdout, "FRAGMENT OFFSET         - [%x Byte]\n",  htons(0x1FFF & ntohs(pIph->ip_off)));  
      

      // Time To Live
      fprintf(stdout, "TIME TO LIVE            - [%d]\n", pIph->ip_ttl);    // 오프셋    



      // 프로토콜
      fprintf(stdout, "TYPE                    - ['");    
      switch(pIph->ip_p)
      {
      case 1:
        fprintf(stdout, "ICMP");
        break;

      case 2:
        fprintf(stdout, "IGMP");
        break;

      case 6:
        fprintf(stdout, "TCP");
        break;

      case 17:
        fprintf(stdout, "UDP");
        break;

      default:
        fprintf(stdout, "아직 못배운");
        break;
      }
      fprintf(stdout, "' 형식입니다.]\n");


      // 체크섬 헤더값을 16비트 1's  Complement 합 계산 후 결과값을 1's Complement로 저장
      fprintf(stdout, "HEADER CHECKSUM         - [%d]\n", pIph->ip_sum );        
      

      
      // 출발지 IP
      fprintf(stdout, "SOURCE ADDRESS          - [%s]\n", inet_ntoa(pIph->ip_src));

      // 도착지 IP
      fprintf(stdout, "DESTINATION ADDRESS     - [%s]\n", inet_ntoa(pIph->ip_dst));


      printf("=================================================================\n\n");
      /* Ip 헤더 출력부 끝*/


      
      // Hex값 출력을 위한 사용자 정의 함수
      HexPrint( (void *)pkt_data , header->len);



      if(0 == header->len)
      {
        printf("\n(error) 읽은 데이터가 없습니다...\n\n");
        return -1;  
      }


      return 0;
    }



    void HexPrint( void *Data, u_int len)
    {

      int iLin;

      fprintf(stdout, "\n=================================================================================\n");
      fprintf(stdout, "[  Addr  ]  00 01 02 03 04 05 06 07   08 09 0A 0B 0C 0D 0E 0F | \n");
      fprintf(stdout, "---------------------------------------------------------------------------------\n");



      for(iLin = 0 ; iLin < len ; iLin+=16)
      {
        fprintf(stdout, "[%08x] ", iLin);
        for(iCnt = 0 ; iCnt < 16  ; ++iCnt)
        {
          if(iCnt == 8)
          {
            fprintf(stdout, "  ");
          }  

          if((iCnt + iLin) < len)
          {
            fprintf(stdout, " %02X", * ( (u_char*)Data+iCnt + iLin) );
          }
          else
          {
            fprintf(stdout, "   ");

          }
        }


        printf(| ");



        for(iCnt = 0 ; iCnt < 16  ; ++iCnt)
        {
          if(iCnt == 8)
          {
            fprintf(stdout, " ");
          }  


          if((iCnt + iLin) < len)
          {
            
            if( ((*((u_char*)Data+iCnt + iLin)) >= 33&& ((*((u_char*)Data+iCnt + iLin)) <= 126) )        
            {
              fprintf(stdout, "%c", * ( (u_char*)Data+iCnt + iLin) );
            }
            else
            {
              printf(".");
            }
          }
          else
          {
            printf(" ");
          }

        }
      
        printf("\n");
      }

      fprintf(stdout, "=================================================================================\n\n");


    }




    SOURCE MADE BY SIGI

    댓글

Designed by Tistory.