Programming/TCP/IP2008.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

Posted by 시긔양