2014.10.07 19:35
by Beist Security Research Group 


Members of Beist Research Group : beist and anonymous people 
Members of Beist Study Group : beist, dars21, obhacker, passion, p-jackpot, jacaranda, cina

 

 

요약본 문서는 유저 레벨에서 패킷 헤더를 분석하는 방법과 특정 프로세스를 지정하여 볼 수 있는 패킷 스니핑 프로그램을 구현하는 방법을 소개합니다.

 

 

 

1. 개요

 

이 문서는 리눅스 환경을 대상으로 작성되었습니다본 문서에서 다룰특정 프로세스를 지정하여 패킷을 스니핑할 수 있는 프로그램은 현재 실행 중인 프로세스와 실행 시킬 프로그램에서 발생하는 패킷을 스니핑하는데 사용될 수 있습니다특히 본 문서에서 다루는 프로그램은 포트 기반으로 수행하는 스니핑이 아니라 프로세스 기반이기 때문에 한 프로세스에서 수시로 다른 포트를 사용할 경우에도 패킷 스니핑을 하기 유용합니다.

본 문서에서는 특정 프로세스에서 사용하고 있는 Port 번호를 알아내기 위하여 proc file system의 프로세스 정보 디렉토리네트워킹 정보 분석 방법데이터링크 액세스 인터페이스 시스템 콜을 이용하여 패킷의 헤더 정보를 알아내는 방법에 대해 다룰 것입니다.

 

 

 

2. 기술적인 내용

 

/proc 디렉토리에서 프로세스 id와 사용중인 포트번호를 추출한 후 해당 프로세스에서 발생하는 패킷의 헤더와 데이터를 분석하는 방법에 대해 알아보겠습니다본 문서에서 설명하는 프로그램은 2가지 방식으로 작동되는데프로그램을 실행할 때패킷을 감시할 프로세스 이름이나 프로세스 ID를 입력하는 방식으로 이루어집니다. (: ./proc_sniff 880 or ./proc_sniff program_name) 다음은 프로세스가 사용중인 Port 번호를 알아내는데 필요한 /proc 디렉토리에 대한 구체적인 내용입니다. (본 문서에서는 주로 TCP에 대해서 설명합니다.)

 

(1) /proc 디렉토리 분석

/proc 디렉토리 내에는 프로세스 정보커널 정보장치 정보네트워킹 정보 등과 같이 다양한 시스템 정보를 포함하고 있지만우리가 관심 있게 봐야 할 부분은 /proc/PID/stat, /proc/net/tcp 파일과 /proc/PID/fd 디렉토리 입니다텍스트 에디터를 사용하여 파일을 읽어보면 프로세스 정보와 네트워킹 정보를 확인할 수 있습니다.

 

 

1) /proc/PID/stat 파일 읽기

프로그램 이름을 실행 인자로 받았을 경우 실행된 프로그램의 프로세스 id 값을 추출하기 위해서 /proc/PID/stat 파일을 사용해야 합니다.여기서 PID /proc 디렉토리 내에 있는 여러 프로세스 ID를 말합니다해당 PID(:1872디렉토리 내의 stat파일은 다음과 같이 프로세스 상태에 관련된 내용을 가지고 있습니다.

 

[root@localhost root]# cat /proc/1872/stat

1872 (sshd) S 1742 1872 1872 0 -1 320 140 48 149 23 2153 982 5 0 15 0 0 0 16721 7065600 535 4294967295 134512640 1347876

80 3221219360 3221216780 3076439090 0 0 4096 73728 3222450524 0 0 17 0 0 0 2153 982 5 0

 

이 정보에서 bold체로 표시된 2번째 필드를 보면 프로세스 이름이 기록되어 있는 것을 확인할 수 있습니다이 정보를 토대로 프로그램 이름과 /proc 디렉토리 내에 있는 모든 PID 디렉토리의 stat 파일을 비교하여 프로세스 이름과 일치하는 파일을 찾아 프로세스 id를 추출할 수 있습니다.

 

 

 

2) /proc/PID/fd 디렉토리 내 파일 디스크립터 읽기

/proc/PID/fd 디렉토리 내에는 해당 PID(:1872프로세스에서 사용하고 있는 파일 디스크립터의 정보가 있습니다아래 예시는/proc/1872/fd 디렉토리의 내용입니다.

 

[root@localhost fd]# ls –l

합계 0

lrwx------    1 root     root           64  3  7 19:06 0 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 1 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 2 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 3 -> socket:[2177]

 

위의 정보를 보면 1872 프로세스의 0(표준입력), 1(표준출력), 2(표준에러파일 디스크립터는 /dev/null로 링크되어 있습니다. 3번 파일 디스크립터는 소켓 파일 디스크립터이고 해당 디스크립터에 링크되어있는 socket:[2177]은 커널에서 관리하고 있는 소켓 번호인 것을 알 수 있습니다이 번호를 이용하여 다음에 설명할 /proc/net 디렉토리 정보와 함께 포트 번호를 추출하는데 사용할 수 있습니다. 1872 프로세스는 위의 1)에서 /proc/1872/stat 파일 정보를 통해 ssh 데몬인 것을 파악했으므로 3번 파일 디스크립터는 ssh 통신을 위한 파일 디스크립터로 예상할 수 있습니다.

 

 

3) /proc/net 정보 얻기

IPv4에 관련된 /proc/net/tcp IPv6에 관련된 /proc/net/tcp6 파일을 통하여 현재 커널에서 관리 중인 소켓의 정보를 파악할 수 있습니다. (본 문서는 IPv4를 대상으로 설명합니다.) 다음의 /proc/net/tcp 파일의 정보인데 ssh 데몬(소켓번호:2177)에서 사용하는 소켓의 정보만 표현하고 다른 소켓 정보는 생략하였습니다.

 

[root@localhost net]# cat tcp

0: 0100007F:0016 0100007F:0BC9 01 00000000:00000000 02:0008A351 00000000     0 02177 2 c2253280 43 4 1 3 -1

 

위의 정보에서 진하게 설정된 부분이 주의 깊게 볼 부분입니다.

 

0100007F:0016 – 서버 측 네트워크 정보를 나타냅니다.

(hex 값을 10진수로 변환하면 127.0.0.1:22)

0100007F:0BC9 – 클라이언트 측 네트워크 주소를 나타냅니다.

(hex 값을 10진수로 변환하면 127.0.0.1:3017)

2177 – socket 번호 입니다.

 

(local network에서 local network으로 연결했기 때문에 서버와 클라이언트의 주소가 같습니다.)

 

 

4) Port 번호 알아내기 과정

프로그램 이름을 실행 인자로 받았을 경우 해당 프로그램을 실행시킨 후에실행된 프로세스가 사용하는 Port 번호를 알아내기 위한 작업의 과정을 종합하면 다음과 같습니다.

 

1. 실행 인자(프로그램 이름) /proc 디렉토리에 모든 /proc/PID/stat 파일의 프로세스 이름 정보를 비교하여 PID (프로세스 id) 정보를 알아냅니다..

2. 알아낸 PID(:1872)를 통해 /proc/1872/fd 의 소켓 파일 디스크립터에 링크된 소켓 번호(:2177)를 알아냅니다.

3. /proc/net/tcp 파일 정보에서 링크된 소켓 번호(2177)을 검색하면 해당 소켓번호의 소켓 정보를 통해 port번호를 알아낼 수 있습니다.0100007F:0016 에서 “0016” port 번호이고, 10진수로 변환하면 “0022” port번호임을 알 수 있습니다.

 

 

(2) Packet 헤더 정보 얻기

 

위의 방법을 통해 Port번호를 알아냈으면 이제 해당 Port 번호에 대한 패킷을 스니핑할 수 있습니다패킷 헤더 정보를 스니핑하기 위해서pcap 라이브러리를 사용하여 프로그램을 작성할 수 있지만본 문서에서는 공개된 라이브러리를 사용하지 않고 직접 시스템 콜을 이용하여 패킷의 헤더를 수신하는 방법에 대하여 알아보겠습니다.

 

1) Ethernet 헤더 열기

TCP, UDP packet의 간단한 구조는 Ethernet 헤더 - IP 헤더 – TCP 혹은 UDP 헤더 순으로 이루어집니다먼저 소켓 시스템 콜을 이용하여 네트워크를 통해 들어온 모든 패킷을 수신하는 방법에 대해 구체적으로 알아보겠습니다.

 

Ethernet 헤더 데이터부터 수신하기 위해서는 소켓을 다음과 같은 설정으로 오픈합니다.

 

sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL));

 

리눅스에서 지원하는 모든 프로토콜을 처리하기 위해 socket 시스템 콜을 호출할 때 1번째 PF_PACKET을 줍니다다음은 리눅스에서 지원하는 프로토콜 패밀리에 대한 안내입니다.

 

프로토콜 체계

정의

PF_INET

IPv4 인터넷 프로토콜

PF_INET6

IPv6 인터넷 프로토콜

PF_LOCAL

Local 통신을 위한 Unix 프로토콜

PF_PACKET

Low level socket을 위한 인터페이스

PF_IPX

IPX 노벨 프로토콜

 

2번째 인자인 소켓 타입에는 SOCK_PACKET을 줍니다이 타입은 모든 패킷을 수신할 수 있도록 하는 소켓의 데이터 전송 타입입니다. (참고로 TCP SOCK_STREAM, UDP SOCK_DGRAM을 사용합니다.)

3번째 인자인 프로토콜에는 ETH_P_ALL 을 줍니다이 프로토콜은 Ethernet 프로토콜을 통째로 다룰 수 있도록 하는 프로토콜입니다위의 소켓을 통하여 데이터를 수신할 경우 Ethernet 헤더 데이터도 수신할 수 있게 됩니다.

 

2) IP 헤더, TCP 헤더 열기

1)에서 설정한 socket 함수를 통해 수신된 데이터는 Ethernet 헤더와 IP 헤더, TCP 헤더 등 내용까지 포함되어 있습니다. Ethernet 헤더 바로 뒤에 IP 헤더가 붙기 때문에 IP헤더를 읽어오기 위해서는 수신된 데이터에서 Ethernet 헤더의 크기만큼 포인터를 이동해야 IP 헤더정보를 읽어올 수 있습니다.

 

/* packetFirst 변수는 수신한 패킷의 선두 포인터 값을 가지고 있음 */

packetPointer = packetFirst;

/* Ethernet 헤더 크기만큼 이동 */

packetPointer = packetPointer + sizeof (struct ether_header);

struct ip *ip_header = (struct ip *) packetPointer;

 

2-1) ip_header 포인터 변수를 통해 다음과 같은 ip 구조체의 멤버변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/ip.h>

 

ip_header->ip_hl          /* 헤더길이 */

  ip_header->ip_v;          /* 버전 */

ip_header->ip_tos;        /* type of service */

  ip_header->ip_len;        /* 전체 길이 */

ip_header->ip_id;         /* 식별id */

  ip_header->ip_off;        /* fragment 옵셋 필드 */

ip_header->ip_ttl;         /* time to live */

ip_header->ip_p;          /* protocol */

ip_header->ip_sum;       /* checksum */

  ip_header->ip_src         /* 출발 ip주소 */

ip_header->ip_dst;        /* 도착 ip주소 */

 

 

IP 헤더의 크기만큼 포인터를 이동하면 TCP 헤더 정보를 읽어올 수 있습니다. IP 헤더의 크기는 ip_header->ip_hl을 통해 알아낼 수 있는데 이 필드는 4비트 길이를 갖지만 단위가 4바이트 단위로 되어 있기 때문에 ip_header->ip_hl 값에 4를 곱해준 값이 IP 헤더의 크기가 됩니다일반적으로 특별한 옵션이 없는 한 ip_header->ip_hl의 값은 5입니다즉 이 값에 4를 곱하면 IP 헤더의 크기는 20바이트 크기인 것을 알 수 있습니다.

 

/* packetPointer 변수는 현재 IP 헤더정보를 가리키는 포인터 값을 가지고 있음 */

/* IP 헤더 크기만큼 이동 */

packetPointer = packetPointer + ((int)(ip->ip_hl) << 2); /* 곱을 쉬프트 연산으로 표현 */

tcp_header = (struct tcphdr *) packetPointer;

 

 

2-2) tcp_header 포인터 변수를 통해 다음과 같은 tcphdr 구조체의 멤버 변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/tcp.h>

 

tcp_header->th_sport;        /* 출발지 port */

 tcp_header->th_dport;        /* 목적지 port */

 tcp_header->th_seq;          /* sequence 번호 */

 tcp_header->th_ack;          /* acknowledgement 번호 */

tcp_header->th_x2;           /* (unused) */

 tcp_header->th_off;           /* 데이터 옵셋*/

tcp_header->th_flags;         /* 제어 플래그 */

 tcp_header->th_win;           /* window */

 tcp_header->th_sum;          /* checksum */

 tcp_header->th_urp;           /* 긴급 포인터 */

 

 

TCP 헤더 이후에 오는 내용은 실제 데이터 부분이 됩니다.

 

2-3) UDP 헤더일 경우 udp_header 포인터 변수를 사용하여 다음과 같은 udphdr 구조체의 멤버변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/udp.h>

 

udp_header->uh_sport;        /* 출발지 port */

 udp_header->uh_dport;        /* 목적지 port */

 udp_header->uh_ulen;         /* udp 길이*/

udp_header->uh_sum;         /* udp 체크섬*/

 

 

2-4) 다음은 TCP 헤더, UDP 헤더 뒤에 붙는 실제 데이터 포인터 위치를 가져오는 부분에 대한 설명입니다.

 TCP 헤더일 경우 TCP 헤더의 크기를 구하기 위해서 tcphdr 구조체의 th_off 구조체 변수를 사용합니다이 변수 값의 수치 단위는 4바이트이므로 4를 곱하여 tcp 헤더의 크기를 구합니다다음과 같이 현재 packetPointer 포인터의 위치를 tcp헤더의 크기만큼 옮기면packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 

packetPointer = packetPointer + ((int)(tcp->th_off) << 2);

 

UDP 헤더는 tcp헤더와 다르게 현재 packetPointer 포인터의 위치를 udphdr헤더의 사이즈만큼 옮기면 packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 다음과 같이 현재 packetPointer 포인터의 위치를 UDP헤더의 크기만큼 옮기면 packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 

packetPointer = packetPointer + sizeof(struct udphdr);

 

(3) 프로세스가 사용 중인 Port 번호를 추출하는 소스 설명

 

다음 소스는 (1) /proc 디렉토리 분석 에서 언급하였던  /proc 디렉토리 분석을 통하여 프로세스에서 사용하는 port 번호를 추출하는 부분에 대한 소스코드입니다.

 

1 /*

      2    /proc/net/tcp 정보에서 소켓 device 값과 비교하여 해당 소켓의 port번호를

      3    얻어온다

      4 */

      5 int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum)

      6 {

      7         DIR *directory;

      8         struct dirent *entry = NULL;

      9         char buffer[256];

     10         char *parsing;

     11         char hexPortNum[40];

     12         int culcount;

     13         int linecount;

     14         int find;

     15         FILE *fp;

     16

     17         culcount = linecount = find = 0;

     18         fp = fopen(ProcTcp, "r");

     19         if (fp == NULL)

     20         {

     21                 perror("/proc/net/tcp(6) error");

     22                 exit(0);

     23         }

     24

     25         linecount = 0;

     26         while(fgets(buffer,256, fp) != NULL)

     27         {

     28                 if(linecount == 0)

     29                 {

     30                         linecount++;

     31                         continue;

     32                 }

     33                 culcount = 0;

     34                 parsing = strtok(buffer, ": ");

     35                 while((parsing = strtok(NULL, ": ")) != NULL)

     36                 {

     37                         if(culcount == 1)

     38                         {

     39                                 strcpy(hexPortNum, parsing);

     40                         }

     41                        

     42                         if(!strncmp(parsing, sockdevnum, strlen(sockdevnum)))

     43                         {

     44                                 /*puts("동일");

     45                                 printf("p %s s %s\n", parsing, sockdevnum);*/

     46                                 find = 1;

     47                                 break;

     48                         }

     49                         else

     50                         {

     51                         }

     52                         culcount++;

     53                 }

     54                 if(find) break;

     55         }

     56

     57         if(find){

     58                 *processPortNum = HexToDecimal(hexPortNum);

     59                 return 1;

     60         }

     61         else

     62                 return 0;

     63 }

     64

     65 unsigned short FindPortNum(char* processID)

     66 {

     67         DIR *directory;

     68         struct dirent *entry = NULL;

     69         char procBuff[40];

     70         char sockBuff[40];

     71         char retBuff[40];

     72         char *sockdev;

     73         char *sockdevnum;

     74         char ProcTcp[20];

     75         int ret;

     76         unsigned short processPortNum;

     77

     78

     79         sprintf(procBuff,"/proc/%s/fd", processID);

     80

        81         if ((directory = opendir(procBuff)) == NULL)

     82         {               

     83                 perror("/proc opendir error");

     84                 exit(0);

     85         }                      

     86                                

     87         while((entry = readdir(directory)) != NULL)

     88         {               

     89                 if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0 &&

     90                         strcmp(entry->d_name, "0") != 0 && strcmp(entry->d_name, "1") !=0 && strcmp(entry->d_name, "2") != 0

     91                 {      

     92                         sprintf(sockBuff,"/proc/%s/fd/%s", processID, entry->d_name);

     93                         readlink(sockBuff, retBuff, sizeof(retBuff));

     94                         sockdev = strtok(retBuff, ":[");

     95                         if(strcmp(sockdev, "socket"))

     96                                 continue;

     97                        

     98                         sockdevnum = strtok(NULL, ":[]");

     99                         break;

    100                 }

    101         }      

    102

    103         sprintf(ProcTcp, "/proc/net/tcp");

    104         ret = SockMapPort(ProcTcp, sockdevnum, &processPortNum);

    105         if(ret == 0) // "/proc/net/tcp"에 정보가 없을 경우

    106         {

    107                 sprintf(ProcTcp, "/proc/net/tcp6");

    108                 SockMapPort(ProcTcp, sockdevnum, &processPortNum);

    109         }

    110        

    111         closedir(directory);

    112         return processPortNum;

    113 }      

    114        

    115 /*     

    116  * 프로세스 정보를 가져온다.

    117  * 그러기 위해서 /proc/[PID]/stat파일을 읽어들이고 이를

    118  * 필드별로 파싱한다파싱은 " "문자를 기준으로 한다

    119  * 또한 프로세스를 생성한 유저 이름도 얻어온다.

    120  */

    121 unsigned short FindProcInfo(char* process)

    122 {

    123     DIR *directory;

    124     struct dirent *entry = NULL;

    125     char proc_file[40];

    126     char proc_name[20];

    127     int processFlag = 0;

    128     unsigned short port;

    129

    130     if (IsDigit(process)) //process가 숫자이면

    131     {

    132             processFlag = 1;

    133     }

    134     else

    135     {

    136             sprintf(proc_name, "(%s)", process);

    137     }

    138

    139

    140     if(processFlag == 0) //실행인자가 프로세스명일 경우

    141     {

    142             system(process); //실행인자 프로그램을 실행 시킴

    143

    144             // proc 디렉토리를 열어서 파일(디렉토리포함)의 리스트를

    145             // 얻어온다.

    146             if ((directory = opendir("/proc")) == NULL)

    147             {

    148                 perror("/proc opendir error");

    149                 exit(0);

    150             }

    151

    152             while((entry = readdir(directory)) != NULL)

    153             {

    154                 if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0)

    155                 {

    156                     sprintf(proc_file,"/proc/%s/stat", entry->d_name);

    157                     // stat 파일이 존재하는지 확인하고 확인하고

    158                     if (access(proc_file, F_OK) != 0)

     159                     {

    160                         continue;

    161                     }

    162    

    163                     // 디렉토리 이름이 숫자인지 확인한다.

    164                     // 디렉토리 이름이 숫자라면 이를 파싱한다

    165                     if (IsDigit(entry->d_name))

    166                     {

    167                         if(ProcParser(proc_file, proc_name)) //디렉토리가 프로세스의 디렉토리 정보인지를 확인

    168                         {

    169                                 port = FindPortNum(entry->d_name);

    170                                 printf("processName : %s\nport : %d\n", process, port);

    171                                 break;

    172                         }

    173                     }

    174                     else

    175                     {

    176                     }

    177                 }

    178             }

    179    

    180             closedir(directory);

    181     }      

    182     else //실행인자가 프로세스id일 경우

    183     {      

    184             port = FindPortNum(process);

    185             printf("processID : %s\nport : %d\n", process, port);

    186     }      

    187                

    188     return port;

    189 }

    190          

191 /*                 

    192  * 파일이름이 숫자인지 확인한다.

    193  */

    194 int IsDigit(char *str)

    195 {

    196         int i;

    197         for (i = 0; i < strlen(str); i++)

    198         {

    199                 if (isdigit(str[i])==0)

    200                         return 0;

    201         }

    202         return 1;

    203 }

    204

    205  /*

    206  "/proc/pid/fd/stat"에서 프로세스명 정보를 비교함

    207  */

    208 int ProcParser(char *proc_file, char *proc_name)

    209 {

    210         FILE *fp;

    211         char buf[512] = {0x00,};    212         int pid;

    213         char *pname;

    214

    215         fp = fopen(proc_file, "r");

    216         if (fp == NULL)

    217         {

    218                 perror("error : ");

    219                 exit(0);

    220         }

    221

    222         fgets(buf, 511, fp);

    223         pid = atoi(strtok(buf, " "));

    224         pname = (char*)strtok(NULL, " ");

    225         fclose(fp);

    226         if(strncmp(pname, proc_name, strlen(proc_name)))

    227         {

    228                 return 0; //프로세스이름과 일치하지 않음

    229         }

    230         else

    231         {

    232                 return 1; //프로세스이름과 일치

    233         }

    234        

    235 }                                                                                 

 

 

 

 

1) 함수 요약 설명

FindProcInfo : 프로세스 id를 매개변수로 받았을 경우에는 바로 FindPortNum 함수에 프로세스 id를 넘겨 포트번호를 추출합니다.프로그램 명을 매개변수로 받았을 경우에는 프로그램을 실행시키고, /proc 디렉토리를 검색하여 ProcParser 함수로 프로세스 id를 알아냅니다이 프로세스 id를 FindPortNum 함수에 대입하여 port 번호를 추출합니다.

 

FindPortNum : 인수로 받은 프로세스 id를 토대로 /proc/pid/fd 디렉토리를 읽어들여 0, 1, 2 기본 파일 디스크립터를 제외한 파일 디스크립터 중에 심볼릭 링크된 값이 socket으로 링크된 디바이스 번호를 SockMapPort 함수에 매개변수로 넘겨 소켓의 포트 번호를 추출합니다.

 

SockMapPort : /proc/net/tcp나 /proc/net/tcp6 파일을 한 라인씩 읽어 들여 인자로 받은 디바이스 번호와 일치한 라인을 찾습니다찾은 라인의 3번째 필드 값이 포트 번호입니다이 값은 16진수로 되어 있기 때문에 10진수로 변환 후 포트번호를 리턴합니다.

 

ProcParser : 인수로 받은 /proc/pid/fd/stat 파일의 데이터에 프로세스 이름이 일치하는 확인하여 프로세스 id를 찾습니다.

 

IsDigit : 인수로 받은 str이 숫자인지 확인합니다.

 

 

2) 소스 해설

5 : SockMapPort 함수는  “/proc/net/tcp”나 “/proc/net/tcp6”을 가리키는 문자열과 소켓 디바이스 번호저장될 프로세스 포트 번호 변수를 인수로 받습니다.

18 : “/proc/net/tcp” 파일을 오픈합니다.

26 ~ 55행 : “/proc/net/tcp” 의 데이터를 한 라인씩 읽어들여 “:”로 토큰한 값 중에 소켓 디바이스 값과 일치하는지 비교하고일치하는 값을 찾으면 저장해 놓은 hexPortNum 값이 16진수로 표현된 포트번호입니다.

57 ~ 60행 : 16진수로 표현된 포트번호를 10진수로 변경합니다.

 

65 : FindPortNum 함수는 문자열로 표현된 프로세스 id를 인수로 받습니다.

79 : 프로세스id 문자열을 추가하여 “/proc/pid/fd” 문자열 값인 procBuf를 만듭니다.

81 : opendir 함수로 procBuff 디렉토리를 오픈하여 디렉토리 포인터를 directory 변수에 저장합니다.

87 ~ 101행 : readdir 함수로 directory 변수의 디렉토리 내에 있는 파일을 읽어 들입니다파일이름이 “.”, “..”, “0”, “1”, “2”를 제외한 파일을 readlink 함수를 사용하여 심볼릭 링크된 값을 retBuff에 저장합니다. retBuff에 저장된 값이 소켓 디바이스면 “socket:[802831]”로 표현되기 때문에 “:[]”로 토큰하여 중괄호 안에 있는 소켓 디바이스 값을 sockdevnum 변수에 저장합니다.

103 : “/proc/net/tcp” 문자열을 ProcTcp 변수에 저장합니다.

104 : 프로세스가 사용중인 포트번호를 추출하기 위해 SockMapPort 함수를 호출합니다.

105 ~ 109행 : 소켓 디바이스 번호와 맵핑 된 포트번호가 없으면 “/proc/net/tcp6”를 첫번째 매개변수로 SockMapPort를 재호출합니다.

111 : 오픈한 디렉토리를 닫습니다.

112 : 프로세스가 사용 중인 포트 번호를 리턴합니다.

 

121 : FindProcInfo 함수는 프로그램 명이나 process id를 인자로 받습니다.

130 ~ 137행 : IsDigit 함수를 사용하여 인수로 받은 process 값이 숫자인지 체크합니다숫자이면 프로세스 id이기 때문에processFlag 값을 1로 설정한다숫자가 아니면 프로그램 명이므로 나중에 proc/pid/stat와 비교 과정에서 프로세스 id를 알아내기 위해 프로그램 명에 “()”를 추가합니다.

142 : 인자로 받은 process 변수의 데이터가 프로그램 명인 경우에는 프로그램을 실행 시킵니다.

146 ~ 149행 : opendir함수를 사용하여 “/proc” 디렉토리를 오픈합니다.

152 ~ 178행 : “/proc” 디렉토리를 읽어 들여 ProcParser 함수에 “/proc” 디렉토리 내에

“/proc/pid/stat” 파일과 프로세스 이름을 매개변수로 넘겨 프로세스 id를 찾습니다프로세스

Id 를 찾으면 FindPortNum 함수에 프로세스 id를 매개변수로 넘겨 포트번호를 추출합니다.

180 : 오픈한 “/proc” 디렉토리를 닫습니다.

182 ~ 186행 : 인자로 받은 process 변수의 데이터가 프로세스 id 이므로  바로

FindPortNum 함수에 프로세스 id를 매개변수로 넘겨 포트번호를 추출합니다.

188 : 포트번호를 반환합니다.

 

194 ~ 203행 : 인자로 받은 str 변수의 데이터가 숫자 문자열인지를 체크합니다.

 

 

208 : ProcParser 함수는 “/proc/pid/fd/stat” 문자열을 가리키는 변수와 프로그램 명을 인자로 받습니다.

215 : “/proc/pid/fd/stat” 파일을 오픈합니다.

222 ~ 224행 : 오픈한 파일 포인터로부터 데이터를 읽어 들여 공백을 구분자로 2번 파싱합니다첫 번째 파싱하여 얻은 데이터는 pid이고두 번째 파싱하여 얻은 데이터는 프로세스 이름입니다.

226 ~ 233행 : 파싱하여 얻은 프로세스명(pname)과 프로그램 명(proc_name)이 일치하는지 확인하여 일치 여부를 반환합니다.

 

 

 

 

(4) Packet Header 추출하는 부분 소스 설명

다음 소스는 (2) Packet 헤더 정보 얻기 에서 언급하였던 소켓을 통해 ethernet 헤더부터 수신한 데이터를 분석하는 부분에 대한 소스코드입니다.

 

1 void packetCapture(unsigned short portnum, FILE *wfp)

2 {

3         struct ether_header *eth;

4         struct ether_arp *arp;

5         struct ip *ip;

6         struct icmp *icmp;

7         struct tcphdr *tcp;

8         struct udphdr *udp;

9         int s;

10         int len;

11         int c;                    // getopt()에서 취득한 문자  

12         char buff[MAXSIZE];       // 데이터 수신 버퍼                  

13         char *packetPointer;      // 헤더의 선두를 나타내는 작업용 포인터

14         char *packetFirst;        // 패킷의 선두를 나타내는 포인터     

15         char buf[BUFSIZE];

16         int i;

17         char data[BUFSIZE];

18

19         if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {

20                 perror("socket");

21                 exit(1);

22         }

23

24         while (1){

25                 if ((len = read(s, buff, MAXSIZE)) < 0) {

26                         perror("read");

27                         exit(1);

28                 }

29                 /* Ethernet 헤더선두에 포인터를 세트 */

30                 packetPointer = packetFirst = buff;

31

32                 eth = (struct ether_header *) packetPointer;

33                 packetPointer = packetPointer + sizeof (struct ether_header);

34                 

35

36                 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {

37                         ip = (struct ip *) packetPointer;

38                

39                         packetPointer = packetPointer + ((int)(ip->ip_hl) << 2);

40

41                         switch (ip->ip_p) {

42                                 case IPPROTO_TCP:

43                                         tcp = (struct tcphdr *) packetPointer;

44                                         if((portnum == ntohs(tcp->th_sport))

 || (portnum == ntohs(tcp->th_dport))){

45                                               

46                                                 print_ip(ip, wfp);

47                                                 print_tcp(tcp, wfp);

48                                                 dump_packet(packetFirst, len, wfp);

49                                                 printf("\n");

50                                                 sprintf(buf, "\n");

51                                                 fputs(buf, wfp);

52                                                 fflush(stdout);

53                                         }

54                                         break;

55                                 case IPPROTO_UDP:

56                                         udp = (struct udphdr *) packetPointer;

57                                         packetPointer = packetPointer

+ sizeof(struct udphdr);

58                                         if((portnum == ntohs(udp->uh_sport))

|| (portnum == ntohs(udp->uh_dport))){

59                                                 print_ip(ip, wfp);

60                                                 print_udp(udp);

61                                                dump_packet(packetFirst, len, wfp);

62                                                 printf("\n");

63                                                 sprintf(buf, "\n");

64                                                 fputs(buf, wfp);

65                                                 fflush(stdout);

66                                         }

67                                         break;

68                         }

69                 }

70         }

71

72 }

73

74

75

76 void dump_packet(unsigned char *buff, int len, FILE *fp)

77 {

78         int i, j;

79         char buf[BUFSIZE];

80

81         printf("Packet Dump:\n");

82         sprintf(buf, "Packet Dump\n");

83         fputs(buf, fp);

84         for (i = 0; i < len; i += 16) {

85                 // 16진수 덤프

86                 for (j = i; j < i + 16 && j < len; j++) {

87                         printf("%02x", buff[j]);

88                         sprintf(buf, "%02x", buff[j]);

89                         fputs(buf, fp);

90

91                         if (j % 2 == 1){

92                                 printf(" ");

93                                 sprintf(buf, " ");

94                                 fputs(buf, fp);

95                         }

96                 }

97

98                 // 제일 마지막 행의 끝 수를 정렬

99                 if (j == len && len % 16 != 0)

100                         for (j = 0; j < 40 - (len % 16)*2.5; j++){

101                                 printf(" ");

102                                 sprintf(buf, " ");

103                                 fputs(buf, fp);

104                         }

105                 printf(": ");

106                 sprintf(buf, ": ");

107                 fputs(buf, fp);

108

109                 // 아스키 문자 표시

110                 for (j = i; j < i + 16 && j < len; j++) {

111                         if ((buff[j] >= 0x20) && (buff[j] <= 0x7e)){

112                                 putchar(buff[j]);

113                                 sprintf(buf, "%c", buff[j]);

114                                 fputs(buf, fp);

115                         }

116                         else{

117                                 printf(".");

118                                 sprintf(buf, ".");

119                                 fputs(buf, fp);

120                         }

121                 }

122                 printf("\n");

123                 fputs("\n", fp);               

124         }                                      

125 }                                              

126                                         

127                                        

128 void tcp_ftoa(int flag, char *str)

129 {              

130         static char f[][3] = {"URG", "ACK", "PSH", "RST", "SYN", "FIN"}; //tcp플래그를 나타내는 문자

131         int length = 0;

132         u_int mask = 1 << 5;

133         int i;

134

135         for(i = 0;i<6;i++) {

136                 if (((flag << i) & mask) != 0)

137                 {

138                         strncat(str, f[i], 3);

139                         strncat(str, " ", 1);

140                 }

141                 else

142                 {

143                

144                 }

145         }      

146                

147         length = strlen(str);

148         str[length] = '\0';

149                        

150 }

151                        

152                                

153                                

154 void print_ip(struct ip *ip, FILE *fp)

155 {                      

156         char buf[BUFSIZE];

157         printf("Protocol: IP\n");

158         sprintf(buf, "Protocol: IP\n");

159         fputs(buf, fp);

160         printf("+-------------------------+--------+----------------+\n");

161         sprintf(buf, "+-------------------------+--------+----------------+\n");

162         fputs(buf, fp);        

163         printf("| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

164                         ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

165         sprintf(buf, "| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

166                         ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

167         fputs(buf, fp);

168         printf("+------------+------------+-------------------------+\n");

169         sprintf(buf, "+------------+------------+-------------------------+\n");

170         fputs(buf, fp);

171         printf("| Source IP Address:                 %15s|\n",

172                         inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

173         sprintf(buf, "| Source IP Address:                 %15s|\n",

174                         inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

175         fputs(buf, fp);

176         printf("+---------------------------------------------------+\n");

177         sprintf(buf, "+---------------------------------------------------+\n");

178         fputs(buf, fp);        

179         printf("| Destination IP Address:            %15s|\n",

180                         inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

181         sprintf(buf, "| Destination IP Address:            %15s|\n",

182                         inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

183         fputs(buf, fp);

184         printf("+---------------------------------------------------+\n");

185         sprintf(buf, "+---------------------------------------------------+\n");

186         fputs(buf, fp);

187 }

 

 

 

 

 

 

1) 함수 요약 설명

packetCapture : 소켓을 Ethernet 헤더부터 수신할 수 있는 옵션으로 오픈하고수신한 데이터를 각 헤더 별로 포인터 변수를 이용하여 분리합니다. Ip 헤더 포인터를 통해 ip를 체크하고, tcp 헤더 포인터를 통해 포트번호를 체크하여 print_ip, print_tcp, dump_packet 함수를 이용하여 각각의 헤더와 데이터 내용을 표준출력과 인자로 받은 파일포인터로 출력합니다. (파일명  :process_9553) – 숫자는 pid 나타냅니다.

 

- dump_packet : 16진수로 표현된 패킷의 데이터 버퍼의 내용을 ASCII 문자로 변환하여 표준출력과 인자로 받은 파일포인터로 출력합니다.

 

- tcp_ftoa : tcp 헤더 중에 제어 플래그 비트를 플래그 문자열로 변경합니다.

 

- print_ip : ip 구조체의 멤버변수를 표준출력과 파일 포인터로 출력합니다.

 

 

2) 소스 해설

1 : packetCapture함수는 포트번호와 수신한 패킷 데이터를 저장할 파일 포인터를 인자로 받습니다.

19 : 패킷의 Ethernet 헤더부터 수신 하기 위해 socket 함수에 SOCK_PACKET,  ETH_P_ALL옵션을 매개변수로 대입합니다.

25 : 오픈한 소켓을 통하여 데이터를 수신하여 buff에 저장합니다.

30 : Ethernet 헤더 데이터부터 읽기 위해 buff의 선두 주소와 packetPointer 포인터를 일치시킵니다.

32 : 현재 packetPointer 포인터 변수는 Ethernet 헤더 데이터를 가리키고 있기 때문에 ether_header 구조체 포인터로 캐스팅 하여ether_header 구조체 포인터인 eth 포인터 변수에 대입합니다.

33 : Ethernet 헤더 다음에 위치한 ip 헤더 데이터를 가리키도록 하기 위해 ether_header 구조체 크기만큼 packetPointer 포인터를 이동시킵니다.

36 : ethrnet 구조체 포인터인 eth의 타입이 ETHERTYPE_IP(IP타입)인지 확인한다. ip타입 이 외에 arp 타입인 경우도 있습니다.

37 : 현재 packetPointer 포인터 변수는 ip 헤더 데이터를 가리키고 있기 때문에 ip 구조체 포인터로 캐스팅하여 ip 구조체 포인터인 ip포인터 변수에 대입합니다.

39 : ip 헤더 다음에 위치한 tcp 헤더를 가리키도록 하기 위해 ip 헤더 길이만큼 포인터를 이동 시킵니다. Ip 헤더 길이는 ip 구조체의ip_hl 멤버 변수에 값을 4배 한 값입니다.

42 ~ 43 : ip 구조체 포인터인 ip의 프로토콜 타입이 TCP타입(IPPROTO_TCP)일 경우 현재 packetPointer 포인터 변수는 tcp 헤더 데이터를 가리키고 있기 때문에 tcphdr 구조체 포인터로 캐스팅하여 tcphdr 구조체 포인터인 tcp 포인터 변수에 대입합니다.

44 ~ 54 : tcphdr 구조체 포인터의 출발지 포트번호(th_sport)와 목적지 포트번호(th_dport)가 인자로 받은 모니터링 할 포트번호(portnum)와 일치하는지 확인합니다동일 포트번호를 담은 패킷 데이터이면 print_ip함수를 사용하여 ip헤더를 출력하고,print_tcp 함수를 사용하여 tcp헤더를 출력합니다. dump_packet 함수를 사용하여 수신받은 모든 버퍼의 내용을 16진수와 ASCII 값으로 표준출력과 파일 포인터로 출력합니다.

55 ~ 56 : ip 구조체 포인터인 ip의 프로토콜 타입이 UDP타입(IPPROTO_UDP)일 경우 현재 packetPointer 포인터 변수는 udp 헤더 데이터를 가리키고 있기 때문에 udphdr 구조체 포인터로 캐스팅하여 udphdr 구조체 포인터인 udp 포인터 변수에 대입합니다.

58 ~ 67 : udphdr 구조체 포인터의 출발지 포트번호(th_sport)와 목적지 포트번호(th_dport)가 인자로 받은 모니터링 할 포트번호(portnum)와 일치하는지 확인합니다동일 포트번호를 담은 패킷 데이터이면 print_ip함수를 사용하여 ip헤더를 출력하고,print_udp를 사용하여 udp헤더를 출력합니다. dump_packet 함수를 사용하여 수신받은 모든 버퍼의 내용을 16진수와 ASCII 값으로 표준출력과 파일 포인터로 출력합니다.

 

76행 : dump_packet 함수는 패킷 헤더와 데이터의 내용을 가리키고 있는 buff 포인터와 buff의 내용을 저장할 파일 포인터를 인자로 받습니다.

84 ~ 123행 : 16바이트를 간격으로 수신한 데이터 크기만큼 Ethernet 헤더부터 데이터 내용까지 16진수와 ASCII 문자로 표준출력과 인자로 받은 파일 포인터로 출력합니다.

 

128행 : tcp_ftoa 함수는 tcp 헤더의 제어 플래그 비트 값과 제어 플래그 문자열을 저장할 문자열 포인터를 인자로 받습니다.

130 : tcp 제어 플래그인 "URG", "ACK", "PSH", "RST", "SYN", "FIN" 문자열을 f배열에 저장합니다.

132 : Tcp 제어 플래그는 6비트로 표현되기 때문에 6번째 비트를 기준으로 AND 마스크할 변수를 정의합니다.

135 ~ 145행 : flag 변수를 0부터 5까지 왼쪽 쉬프트하여 mask 변수로 AND 마스크하면 어느 비트가 1로 세팅 되었는지 확인할 수 있습니다. 1로 세팅된 제어 플레그를 맵핑된 tcp플래그 문자열로 바꾸어 str 문자열 변수에 복사합니다.

 

154 : print_ip 함수는 ip 구조체 포인터 변수와 ip헤더의 내용을 저장할 파일 포인터 변수를 인자로 받습니다.

163 : ip헤더의 identifier, TTL, Checksum 내용을 ip 구조체의 멤버 변수를 통해 추출합니다각각의 데이터에는 ip구조체의 ip_id, ip_ttl, ip_sum 멤버 변수 값이 대입됩니다.

171 ~ 179행 : ip헤더의 출발지 ip, 목적지 ip 내용을 ip구조체의 멤버 변수를 통해 추출합니다각각의 데이터에는 ip구조체의 ip_src, ip_dst 멤버변수 값이 대입됩니다.

 

 

 

 

3. 맺음말

 

지금까지 /proc 디렉토리에 담긴 정보를 분석이용하여 특정 프로세스가 사용 중인 포트 번호를 추출하는 방법과 socket 시스템 콜을 이용하여 TCP/IP 헤더와 실제 데이터를 분석하는 방법에 대해 공부하고실제 구현하는 방법까지 알아보았습니다본 프로그램은 /proc 디렉토리의 프로세스 정보와 네트워크 정보만을 다루었지만 /proc 디렉토리에는 시스템에 관련된 거의 대부분의 정보를 가지고 있기 때문에 시스템 모니터링 프로그램이나 시스템 성능 분석 프로그램 등을 개발하는데 유용하게 사용될 수 있습니다.

본 문서에서는 이와 유사한 프로그램을 만들기 위한 제작 과정을 소개하기 위한 목적으로 작성되었기 때문에 기능이 미약하고 불안전할 수도 있습니다문서에서 설명한 프로그램에 스니핑 된 패킷들의 데이터를 프로토콜, IP 주소 별로 분류하거나 기타 통계 기능 등을 추가한다면 더욱 유용하게 사용할 수 있을 것으로 생각합니다.

 

 

 

 

----------- 전체 소스코드 -----------

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

#include <errno.h>

#include <ctype.h>

#include <string.h>

#include <netdb.h>

#include <dirent.h>

#include <sys/time.h>

#include <sys/socket.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <net/ethernet.h>

#include <netinet/in_systm.h>

#include <netinet/in.h>

#define  __FAVOR_BSD

#include <netinet/ip.h>

#include <netinet/ip_icmp.h>

#include <netinet/tcp.h>

#include <netinet/udp.h>

#include <netinet/if_ether.h>

#include <arpa/inet.h>

#include <linux/sockios.h>

 

#define MAXSIZE 4096

#define BUFSIZE 128

 

 

void tcp_ftoa(int flag, char *str);

void print_ip(struct ip *ip, FILE *fp);

void print_tcp(struct tcphdr *tcp, FILE *fp);

void print_udp(struct udphdr *udp);

void dump_packet(unsigned char *buff, int len, FILE *fp);

int ProcParser(char *proc_file, char *proc_name);

int IsDigit(char *str);

int HexToDecimal(char *buffer);

int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum);

unsigned short FindPortNum(char* processID);

unsigned short FindProcInfo(char* process);

void packetCapture(unsigned short portnum, FILE *wfp);

void help(char *cmd);

 

int main(int argc, char **argv)

{

             int c;                   

             char data[BUFSIZE];

             unsigned short portnum;

             FILE *wfp;

 

             while ((c = getopt(argc, argv, "i:p:")) != EOF) {

                           switch (c) {

                                        case 'i':

                                                     portnum = FindProcInfo(argv[2]);

                                                     break;

                                        case 'p' :

                                                     portnum = FindProcInfo(argv[2]);

                                                     break;

                                        case 'h':              

                                                     help(argv[0]);

                                        default:

                                                     help(argv[0]);

                                                     exit(1);

                                                     break;

                           }

             }

 

             if(argc < 2) {

                           fprintf(stderr, "parameter errror!\n");

                           help(argv[0]);

                           exit(1);

             }

 

             sprintf(data, "process_%s", argv[2]);

             if((wfp = fopen(data, "wa"))==NULL) {

                           perror("file open error\n");

                           exit(0);

             }

 

             packetCapture(portnum, wfp);

             fclose(wfp);

             return 0;

}

 

void tcp_ftoa(int flag, char *str)

{

             static char f[][3] = {"URG", "ACK", "PSH", "RST", "SYN", "FIN"};

             int length = 0;

             u_int mask = 1 << 5;

             int i;

 

             for(i = 0;i<6;i++) {

                           if (((flag << i) & mask) != 0)

                           {

                                        strncat(str, f[i], 3);

                                        strncat(str, " ", 1);

                           }

             }

 

             length = strlen(str);

             str[length] = '\0';

 

}

 

 

void print_ip(struct ip *ip, FILE *fp)

{

             char buf[BUFSIZE];

             printf("Protocol: IP\n");

             sprintf(buf, "Protocol: IP\n");

             fputs(buf, fp);

printf("+-------------------------+--------+----------------+\n");

sprintf(buf, "+-------------------------+--------+----------------+\n");

             fputs(buf, fp);

             printf("| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

                                        ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

             sprintf(buf, "| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

                                        ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

             fputs(buf, fp);

printf("+------------+------------+-------------------------+\n");

sprintf(buf, "+------------+------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Source IP Address:                 %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

             sprintf(buf, "| Source IP Address:                 %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

             fputs(buf, fp);

printf("+---------------------------------------------------+\n");

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

             printf("| Destination IP Address:            %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

             sprintf(buf, "| Destination IP Address:            %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

             fputs(buf, fp);

printf("+---------------------------------------------------+\n");

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

}

 

void print_tcp(struct tcphdr *tcp, FILE *fp)

{

             char buf[BUFSIZE];

             char str[17];

 

             memset(str, 0, sizeof(str));

 

             printf("protocol: TCP\n");

             sprintf(buf, "protocol: TCP\n");

             fputs(buf, fp);

printf("+-------------------------+-------------------------+\n");

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

 

             printf("| Source Port:       %5u| Destination Port:  %5u|\n",

                                        ntohs(tcp->th_sport), ntohs(tcp->th_dport));

             sprintf(buf, "| Source Port:       %5u| Destination Port:  %5u|\n",

                                        ntohs(tcp->th_sport), ntohs(tcp->th_dport));

             fputs(buf, fp);

            

printf("+-------------------------+-------------------------+\n");

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Sequence Number:                        %10lu|\n",

                                        (u_long)ntohl(tcp->th_seq));

             sprintf(buf, "| Sequence Number:                        %10lu|\n",

                                        (u_long)ntohl(tcp->th_seq));

             fputs(buf, fp);

            

printf("+---------------------------------------------------+\n");

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

             tcp_ftoa(tcp->th_flags, str);

             printf("| Ack Number:   %10lu| Flag:         %10s|\n",

                                        (u_long)ntohl(tcp->th_ack), str);

             sprintf(buf, "| Ack Number:   %10lu| Flag:         %10s|\n",

                                        (u_long)ntohl(tcp->th_ack), str);

             fputs(buf, fp);

 

printf("+-------------------------+-------------------------+\n");

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Checksum:          %5u| Urgent Pointer:    %5u|\n",

                                        ntohs(tcp->th_sum), ntohs(tcp->th_urp));

             sprintf(buf, "| Checksum:          %5u| Urgent Pointer:    %5u|\n",

                                        ntohs(tcp->th_sum), ntohs(tcp->th_urp));

             fputs(buf, fp);

printf("+-------------------------+-------------------------+\n");

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

}

 

 

 

void print_udp(struct udphdr *udp)

{

             printf("Protocol: UDP\n");

printf("+-------------------------+-------------------------+\n");

             printf("|Source Port:        %5u| Dest Port:         %5u|\n",

                                        ntohs(udp->uh_sport), ntohs(udp->uh_dport));

printf("+-------------------------+-------------------------+\n");

             printf("|Length:             %5u| Ckecksum:          %5u|\n",

                                        ntohs(udp->uh_ulen), ntohs(udp->uh_sum));

printf("+-------------------------+-------------------------+\n");

}

 

void dump_packet(unsigned char *buff, int len, FILE *fp)

{

             int i, j; 

             char buf[BUFSIZE];

 

             printf("Packet Dump:\n"); 

             sprintf(buf, "Packet Dump\n");

             fputs(buf, fp);

             for (i = 0; i < len; i += 16) {

                           for (j = i; j < i + 16 && j < len; j++) {

                                        printf("%02x", buff[j]);

                                        sprintf(buf, "%02x", buff[j]);

                                        fputs(buf, fp);

 

                                        if (j % 2 == 1){

                                                     printf(" ");

                                                     sprintf(buf, " ");

                                                     fputs(buf, fp);

                                        }

                           }

 

                           if (j == len && len % 16 != 0)

                                        for (j = 0; j < 40 - (len % 16)*2.5; j++){

                                                     printf(" ");

                                                     sprintf(buf, " ");

                                                     fputs(buf, fp);

                                        }

                           printf(": ");

                           sprintf(buf, ": ");

                           fputs(buf, fp);

 

                           for (j = i; j < i + 16 && j < len; j++) {

                                        if ((buff[j] >= 0x20) && (buff[j] <= 0x7e)){

                                                     putchar(buff[j]);

                                                     sprintf(buf, "%c", buff[j]);

                                                     fputs(buf, fp);

                                        }

                                        else{

                                                     printf(".");

                                                     sprintf(buf, ".");

                                                     fputs(buf, fp);

                                        }

                           }

                           printf("\n");

                           fputs("\n", fp);

             }

}

 

void help(char *cmd)

{

             fprintf(stderr, "usage: %s [-i processid] [-p processname] \n", cmd);

}

 

void packetCapture(unsigned short portnum, FILE *wfp)

{

             struct ether_header *eth;

             struct ether_arp *arp;   

             struct ip *ip;           

             struct icmp *icmp;       

             struct tcphdr *tcp;      

             struct udphdr *udp;      

             int s;                    

             int len;                 

             int c;                   

             char buff[MAXSIZE];      

             char *packetPointer;     

             char *packetFirst;       

             char buf[BUFSIZE];

             int i;

             char data[BUFSIZE];

            

             if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {

                           perror("socket");

                           exit(1);

             }

 

             while (1){

                           if ((len = read(s, buff, MAXSIZE)) < 0) {

                                        perror("read");

                                        exit(1);

                           }

                           packetPointer = packetFirst = buff;

 

                           eth = (struct ether_header *) packetPointer;

                           packetPointer = packetPointer + sizeof (struct ether_header);

                           printf("ether : %d\n", sizeof(struct ether_header));

 

                           if (ntohs(eth->ether_type) == ETHERTYPE_IP) {

                                        ip = (struct ip *) packetPointer;

                                        printf("ip : %d\n", sizeof(struct ip));

                                        packetPointer = packetPointer + ((int)(ip->ip_hl) << 2);

 

                                        switch (ip->ip_p) {

                                                     case IPPROTO_TCP:

                                                                  tcp = (struct tcphdr *) packetPointer;

                                                if((portnum == ntohs(tcp->th_sport))

|| (portnum == ntohs(tcp->th_dport))){

                                                     cketPointer = packetPointer + ((int)(tcp->th_off) << 2);

                                                                                print_ip(ip, wfp);

                                                                                print_tcp(tcp, wfp);

                                                                                dump_packet(packetFirst, len, wfp);

                                                                                printf("\n");

                                                                                sprintf(buf, "\n");

                                                                                fputs(buf, wfp);

                                                                                fflush(stdout);

                                                                  }

                                                                  break;

                                                     case IPPROTO_UDP:

                                                                  udp = (struct udphdr *) packetPointer;

                                                                  if((portnum == ntohs(udp->uh_sport))

|| (portnum == ntohs(udp->uh_dport))){

                                                                                print_ip(ip, wfp);

                                                                                print_udp(udp);

                                                                                dump_packet(packetFirst, len, wfp);

                                                                                printf("\n");

                                                                                sprintf(buf, "\n");

                                                                                fputs(buf, wfp);

                                                                                fflush(stdout);

                                                                  }

                                                                  break;

                                        }

                           }

             }

 

}

 

int ProcParser(char *proc_file, char *proc_name)

{

    FILE *fp;

    char buf[512] = {0x00,};

    int pid;

    char *pname;

 

    fp = fopen(proc_file, "r");

    if (fp == NULL)

    {

        perror("error : ");

        exit(0);

    }

 

    fgets(buf, 511, fp);

    pid = atoi(strtok(buf, " "));

    pname = (char*)strtok(NULL, " ");

 

    if(strncmp(pname, proc_name, strlen(proc_name)))

    {

                 return 0;

    }

    else

    {

                 return 1;

    }

    fclose(fp);

 

int IsDigit(char *str)

{

    int i;

    for (i = 0; i < strlen(str); i++)

    {

        if (isdigit(str[i])==0)

            return 0;

    }

    return 1;

}

 

int HexToDecimal(char *buffer)

{

             int count=0, decimal=0;

 

             for(count =0;count<4;count++)

             {

                           if(buffer[count]>='0' && buffer[count]<='9')

                           {

                                        decimal *= 16;

                                        decimal += buffer[count] - '0';

                           }

                           else if(buffer[count]>='A' && buffer[count]<='F')

                           {

                                        decimal *= 16;

                                        decimal += buffer[count] - 'A' + 10;

                           }

             }

 

             return decimal;

                          

}

 

int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum)

{

             DIR *directory;

             struct dirent *entry = NULL;

             char buffer[256];

             char *parsing;

             char hexPortNum[40];

             int culcount;

             int linecount;

             int find;

             FILE *fp;

 

             culcount = linecount = find = 0;

             fp = fopen(ProcTcp, "r");

             if (fp == NULL)

             {

                           perror("/proc/net/tcp(6) error");

                           exit(0);

             }

            

             linecount = 0;

             while(fgets(buffer,256, fp) != NULL)

             {

                           if(linecount == 0)

                           {

                                        linecount++;

                                        continue;

                           }

                           culcount = 0;

                           parsing = strtok(buffer, ": ");

                           while((parsing = strtok(NULL, ": ")) != NULL)

                           {

                                        if(culcount == 1)

                                        {

                                                     strcpy(hexPortNum, parsing);

                                        }

                                       

                                        if(!strncmp(parsing, sockdevnum, strlen(sockdevnum)))

                                        {

                                                     find = 1;

                                                     break;

                                        }

                                        else

                                        {

                                        }

                                        culcount++;

                           }

                           if(find) break;

             }

 

             if(find){

                           *processPortNum = HexToDecimal(hexPortNum);

                           return 1;

             }

             else

                           return 0;

}

 

unsigned short FindPortNum(char* processID)

{

             DIR *directory;

             struct dirent *entry = NULL;

             char procBuff[40];

             char sockBuff[40];

             char retBuff[40];

             char *sockdev;

             char *sockdevnum;

             char ProcTcp[20];

             int ret;

             unsigned short processPortNum;

 

 

             sprintf(procBuff,"/proc/%s/fd", processID);

 

        if ((directory = opendir(procBuff)) == NULL)

             {

                     perror("/proc opendir error");

                           exit(0);

        }

             while((entry = readdir(directory)) != NULL)

             {

                           if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0

&& strcmp(entry->d_name, "0") != 0 && strcmp(entry->d_name, "1") !=0

&& strcmp(entry->d_name, "2") != 0)

                           {

                                        sprintf(sockBuff,"/proc/%s/fd/%s", processID, entry->d_name);

                                        readlink(sockBuff, retBuff, sizeof(retBuff));

                                        sockdev = strtok(retBuff, ":[");

                                        if(strcmp(sockdev, "socket"))

                                                     continue;

                                        sockdevnum = strtok(NULL, ":[]");

                                        break;

                           }

             }

 

             sprintf(ProcTcp, "/proc/net/tcp");

             ret = SockMapPort(ProcTcp, sockdevnum, &processPortNum);

             if(ret == 0)

             {

                           sprintf(ProcTcp, "/proc/net/tcp6");

                           SockMapPort(ProcTcp, sockdevnum, &processPortNum);

             }

 

             closedir(directory);

             return processPortNum;

}

 

unsigned short FindProcInfo(char* process)

{

    DIR *directory;

    struct dirent *entry = NULL;

    char proc_file[40];

    char proc_name[20];

    int processFlag = 0;

    unsigned short port;

 

    if (IsDigit(process))

    {

                 processFlag = 1;

    }

    else

    {

                 sprintf(proc_name, "(%s)", process);

    }

 

 

    if(processFlag == 0)

    {

                 system(process);

 

                 if ((directory = opendir("/proc")) == NULL)

                 {

                           perror("/proc opendir error");

                           exit(0);

                 }

 

                 while((entry = readdir(directory)) != NULL)

                 {

                           if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0)

                           {

                               sprintf(proc_file,"/proc/%s/stat", entry->d_name);

                               if (access(proc_file, F_OK) != 0)

                               {

                                        continue;

                               }

 

                               if (IsDigit(entry->d_name))

                               {

                                        if(ProcParser(proc_file, proc_name))

                                        {

                                                     port = FindPortNum(entry->d_name);

                                   printf("processName : %s\nport : %d\n", process, port);

                                                     break;

                                        }

                               }

                               else

                               {

                               }

                           }

                 }

 

                 closedir(directory);

    }

    else

    {

                 port = FindPortNum(process);

                 printf("processID : %s\nport : %d\n", process, port);

    }

 

    return port;

}



Posted by k1rha