[Project] pcap과 mysql함수들을 편하게 사용하기위한 새로운 함수 정의

Date:     Updated:

카테고리:

태그:

코드

코드
#include <stdio.h>
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <mysql.h>
#include <time.h>

// function()
MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query);

// DB
MYSQL_RES *res;
MYSQL_ROW row;

MYSQL_RES *res_block;
MYSQL_ROW row_block;

MYSQL* conn;

// connect DB
char* server = "localhost";
char* user = "root";
char* password = "1234";
char* database = "project";
	
	
	

// PCAP
#define ETHER_ADDR_LEN 6


struct sniff_ethernet {
	u_char ether_dhost[ETHER_ADDR_LEN];
	u_char ether_shost[ETHER_ADDR_LEN];
	u_short ether_type;
};

struct sniff_ip {
	u_char ip_vhl;
	u_char ip_tos;
	u_short ip_len;
	u_short ip_id;
	u_short ip_off;

#define IP_RF 0x8000
#define IP_DF 0x4000
#define IP_MF 0x2000
#define IP_OFFMASK 0x1fff

	u_char ip_ttl;
	u_char ip_p;
	u_short ip_sum;
	
	struct in_addr ip_src, ip_dst;
};
#define IP_HL(ip)	(( (ip)->ip_vhl ) & 0x0f)
#define IP_V(ip)	(( (ip)->ip_vhl ) >> 4)


typedef u_int tcp_seq;
struct sniff_tcp {
	u_short th_dport;
	u_short th_sport;
	tcp_seq th_seq;
	tcp_seq th_ack;

	u_char th_offx2;
#define TH_OFF(tcp)	(( (tcp)->th_offx2 & 0xf0) >> 4 )
	u_char th_flags;

#define TH_FIN 0x01
#define TH_SYN 0x02 
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CRW 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECE|TH_CRW)

	u_short th_win;
	u_short th_sum;
	u_short th_urp;
};

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char* packet);

// new
#define DOMAIN_BUF 256
#define IP_SIZE 16
#define IP_HDR_SIZE 20
#define TCP_HDR_SIZE 20
#define REC_DOM_MAX 20
#define REC_DOM_LEN 100
#define TMP_THUD 1024
#define TO_MS 1000

char* SELECT = "Recent_list";
int MODE = 0;
void print_packet_ethernet(struct sniff_ethernet* ethernet, unsigned short int payload_len, const struct pcap_pkthdr *header);
char* print_packet_ip(struct sniff_ip* ip);
unsigned short int  print_packet_tcp(struct sniff_tcp* tcp);
u_char* print_packet_domain(const char *payload);
void print_block_list(char tmp[REC_DOM_MAX][REC_DOM_LEN]);
char* now_time();
void mysql_insert(char* recv_ip, unsigned short int recv_tcp, u_char* recv_domain);
void mysql_select(char* SELECT_TB);

int main( int argc, char *argv[])
{

	char *dev, errbuf[PCAP_ERRBUF_SIZE];

	pcap_t *handle;

	bpf_u_int32 net;
	bpf_u_int32 mask;

	struct bpf_program fp;
	char filter_exp[] = "port 80";

	struct pcap_pkthdr header;
	const u_char *packet;


	dev = pcap_lookupdev(errbuf);
	if( dev == NULL ) {
		fprintf(stderr, "could not find default device %s \n", errbuf);
		return 2;
	}

	if( pcap_lookupnet(dev, &net, &mask, errbuf) == -1 ) {
		fprintf(stderr, "could not get netmask for device %s : %s \n", dev, errbuf);
		net = 0;
		mask = 0;
	}

	handle = pcap_open_live(dev, BUFSIZ, 1, TO_MS, errbuf); // TO_MS 1000
	if( handle == NULL ) {
		fprintf(stderr, "could not open device %s : %s \n", dev, errbuf);
		return 2;
	}

	if( pcap_compile(handle, &fp, filter_exp, 0, net) == -1 ) {
		fprintf(stderr, "could not parse filter %s : %s \n", filter_exp, pcap_geterr(handle));
		return 2;
	}

	if( pcap_setfilter(handle, &fp) == -1 ) {
		fprintf(stderr, "could not install filter %s : %s \n", filter_exp, pcap_geterr(handle));
		return 2;
	}

	// DB Connection
	
	conn = mysql_init(NULL);
	if (conn == NULL) {
		fprintf(stderr,"MySQL initialization failed");
		return 2;
	}
	if (mysql_real_connect(conn, server, user, password, database, 0, NULL, 0) == NULL) {
		fprintf(stderr,"mysql_real_connect() Unable to connect with MySQL server !");
		mysql_close(conn);
		return 2;
	}


	int result = 0;
	result = pcap_loop(handle, 0, got_packet, NULL);
	if( result != 0 ) {
		fprintf(stderr,"ERROR : pcap_loop() end with error !!! \n");
	} else {
		fprintf(stdout,"INFO : pcap_loop() end without error \n");
	}

	pcap_close(handle);
	mysql_close(conn);

	return 0;
} // end of main() .

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char* packet)
{
	#define SIZE_ETHERNET 14

	struct sniff_ethernet *ethernet;
	struct sniff_ip *ip;
	struct sniff_tcp *tcp;
	char *payload;
	
	char* recv_ip;
    unsigned short int recv_tcp;
    u_char* recv_domain;
	
	u_int size_ip;
	u_int size_tcp;

	ethernet = (struct sniff_ethernet*)(packet);
	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
	size_ip = IP_HL(ip) * 4;
	if( size_ip < IP_HDR_SIZE ) { // IP_HDR_SIZE == 20
		fprintf(stderr, " * Invalid IP Header Length %u bytes \n", size_ip);
	}

	tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
	size_tcp = TH_OFF(tcp) * 4;
	if( size_tcp < TCP_HDR_SIZE ) { // TCP_HDR_SIZE == 20
		fprintf(stderr, " * Invalid TCP Header Length %u bytes \n", size_tcp);
	}

	payload = (u_char*)(packet + SIZE_ETHERNET + size_ip + size_tcp);

	unsigned short int payload_len = 0;
	payload_len = ntohs(ip->ip_len) - size_ip - size_tcp;
	
	
	// print domain
	// if blocked domain, don't print ip, port ->> define
	recv_domain = print_packet_domain(payload);
	// print ethernet
	print_packet_ethernet(ethernet, payload_len, header);
	// print ip
	recv_ip = print_packet_ip(ip);
	
	// print port
	recv_tcp = print_packet_tcp(tcp);

	
	if(recv_domain && recv_ip && recv_tcp) {
		// query insert in Recent_list
		mysql_insert(recv_ip, recv_tcp, recv_domain);
		
		// select * from recent_list
		mysql_select(SELECT);
	}
} // end of got_packet()

// query function() for print of DB contents
MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query) {
 
    if(mysql_query(connection, sql_query)) {
        printf("MYSQL query error : %s\n", mysql_error(connection));
        exit(1);
    }
    return mysql_use_result(connection);
}

void print_packet_ethernet(struct sniff_ethernet* ethernet, unsigned short int payload_len, const struct pcap_pkthdr *header) {
	
	if( MODE == 1 ) {
		printf("DATA: payload_len %u \n", payload_len);
		
		printf("Jacked a packet with Length of [%d] \n", header->len);
		
		printf("DATA: dest MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
				ethernet->ether_dhost[0],
				ethernet->ether_dhost[1],
				ethernet->ether_dhost[2],
				ethernet->ether_dhost[3],
				ethernet->ether_dhost[4],
				ethernet->ether_dhost[5]
				);
		
		printf("DATA: src MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
				ethernet->ether_shost[0],
				ethernet->ether_shost[1],
				ethernet->ether_shost[2],
				ethernet->ether_shost[3],
				ethernet->ether_shost[4],
				ethernet->ether_shost[5]
				);
	}
}


char* print_packet_ip(struct sniff_ip* ip) {
	
	// IP
	char *IPbuffer, *IPbuffer2;
	char IPbuffer_str[IP_SIZE]; 		// IP_SIZE 16
	static char IPbuffer2_str[IP_SIZE];	// IP_SIZE 16

	IPbuffer = inet_ntoa(ip->ip_src);
	strcpy(IPbuffer_str, IPbuffer);

	IPbuffer2 = inet_ntoa(ip->ip_dst);
	strcpy(IPbuffer2_str, IPbuffer2);
	
	if ( MODE == 1 ) {
		printf("DATA: IP src : %s \n", IPbuffer_str);
		printf("DATA: IP dst : %s \n", IPbuffer2_str);
	}
	return IPbuffer2_str;
}   

unsigned short print_packet_tcp(struct sniff_tcp* tcp) {
	// port
	unsigned short tcp_src_port = 0;
	unsigned short tcp_dst_port = 0;

	tcp_src_port = ntohs(tcp->th_sport);
	tcp_dst_port = ntohs(tcp->th_dport);
	
	if ( MODE == 1 ) {
		printf("DATA : src Port %u \n", tcp_src_port);
		printf("DATA : dst Port %u \n", tcp_dst_port);
	}
	
	return tcp_dst_port;
}

u_char* print_packet_domain(const char *payload) {
	
	// domain
	u_char *domain = NULL;
	u_char *domain_end = NULL;
	static u_char domain_str[DOMAIN_BUF] = { 0x00}; // DOMAIN_BUF 256

	int domain_len = 0;

	domain = strstr(payload, "Host: ");
	if( domain != NULL ) {
		domain_end = strstr(domain, "\x0d\x0a");
		if( domain_end != NULL ) {
			domain_len = domain_end - domain - 6;
			strncpy(domain_str, domain + 6, domain_len );
//			printf("INFO: Domain : %s \n", domain_str);
		} else {
//			printf("INFO: Host string not found \n");
		}
	}


	// New DB FOR compare with domain
	
	if( domain_len ) {
		int cmp_ret = 1; // for compare result

		char tmp[REC_DOM_MAX][REC_DOM_LEN] = {0x00};
		// print block_list
		print_block_list(tmp);
		
		// start for loop 1 .
		for(int i = 0; i < 100; i++ ) {

		// if you knew str_len, you choice method like this
		int str1_len = strlen( &tmp[i][0] );
		int str2_len = strlen( domain_str );
		
		// printf("why? %s . \n", &tmp[i][0] ); 
		// printf("str1_len : %d \n", str1_len);
		// printf("domain : %s \n", domain_str);
		// printf("str2_len : %d \n", str2_len);

		if( str1_len != str2_len ) {
			continue; // move to next array !
		}
		
		
		// printf("compare start \n");
		cmp_ret = strcmp( &tmp[i][0], domain_str );
		// if each other string is same length but not same string, so break
		if( cmp_ret < 0 ) break; 
		printf("DEBUG: domain name check result : %d \n", cmp_ret);

		if( cmp_ret == 0 )
			break; // stop for loop 1 .
		
		// break if meet NULL data in array .
		if( strlen( &tmp[0][i] ) == 0 ) 
			break; // stop for loop 1.

		} // end for loop .

		// domain
		printf("INFO: Domain : %s . \n", domain_str);
		
		if( cmp_ret == 0 ) {
			printf("DEBUG: main blocked . \n");
		// sendraw(); // here is block packet function location later
		} else {
			printf("DEBUG: domain allowed . \n");
		} // end if emp_ret .
		
		MODE = 1;
		return domain_str;
	} else {
		MODE = 0;
	}
	
	
}

void print_block_list(char tmp[REC_DOM_MAX][REC_DOM_LEN]) {
		// Receive Block_list
		res_block = mysql_perform_query(conn, "SELECT * FROM Block_list");
		
		printf("\n");
		printf("Mysql Block_list \n");
		int i = 0, j = 0;
		
		while( (row_block = mysql_fetch_row(res_block) ) != NULL) {
			printf("Domain: %20s | ", row_block[0]);
			printf(" IP: %15s | ", row_block[1]);
			printf(" Port: %7s | \n", row_block[2]);
			strcpy( &tmp[j++][0], row_block[0]);
			// printf("&tmp[j++][0] = %s", &tmp[j++][0]); // j++ coredump warning !!!
			// printf(" tmp : %d \n", strlen(&tmp[j++][0]));  // j++ coredump warning !!!
		}
		printf("\n");
		
		mysql_free_result(res_block);
}

char* now_time(){
	// for time check
	time_t t1;
	time(&t1);
	
	char* time_buf = ctime(&t1);
	time_buf[strlen(time_buf)-1] = '\0';
	// printf("ctime의 결과 : %s\n", time_buf);
	
	return time_buf;
}


void mysql_insert(char* recv_ip, unsigned short int recv_tcp, u_char* recv_domain)
{
	// print time
	char* time_buf = now_time();
	// printf("ctime의 결과 : %s\n", time_buf);
	
	// INSERT
	char query[TMP_THUD] = { 0x00};
	// query setting
	sprintf(query, "INSERT INTO Recent_list VALUES('%s', '%s', '%d', '%s')", recv_domain, recv_ip, recv_tcp, time_buf);
	
	if( mysql_query(conn, query) )
		printf("mysql_query Sucess \n");
}


void mysql_select(char* SELECT)
{
	char query[TMP_THUD] = { 0x00 } ;
	sprintf(query, "SELECT * FROM %s", SELECT);
	
	res = mysql_perform_query(conn, query);

	printf("\n");
	printf("Mysql contents in mysql %s \n", SELECT);
	while( (row = mysql_fetch_row(res) ) != NULL){
		printf("Domain: %20s | ", row[0]);
		printf(" IP: %15s | ", row[1]);
		printf(" Port: %7s | ", row[2]);
		printf(" Time: %s . \n", row[3]);
	}
	printf("\n");
	mysql_free_result(res);
	
}









코드 분석

  • 새로 추가된 부분 요약
#define DOMAIN_BUF 256
#define IP_SIZE 16
#define IP_HDR_SIZE 20
#define TCP_HDR_SIZE 20
#define REC_DOM_MAX 20
#define REC_DOM_LEN 100
#define TMP_THUD 1024
#define TO_MS 1000

char* SELECT = "Recent_list";
int MODE = 0;
void print_packet_ethernet(struct sniff_ethernet* ethernet, unsigned short int payload_len, const struct pcap_pkthdr *header);
char* print_packet_ip(struct sniff_ip* ip);
unsigned short int  print_packet_tcp(struct sniff_tcp* tcp);
u_char* print_packet_domain(const char *payload);
void print_block_list(char tmp[REC_DOM_MAX][REC_DOM_LEN]);
char* now_time();
void mysql_insert(char* recv_ip, unsigned short int recv_tcp, u_char* recv_domain);
void mysql_select(char* SELECT_TB);

1. void print_packet_ethernet(struct sniff_ethernet* ethernet, unsigned short int payload_len, const struct pcap_pkthdr *header);

void print_packet_ethernet(struct sniff_ethernet* ethernet, unsigned short int payload_len, const struct pcap_pkthdr *header) {
	
	if( MODE == 1 ) {
		printf("DATA: payload_len %u \n", payload_len);
		
		printf("Jacked a packet with Length of [%d] \n", header->len);
		
		printf("DATA: dest MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
				ethernet->ether_dhost[0],
				ethernet->ether_dhost[1],
				ethernet->ether_dhost[2],
				ethernet->ether_dhost[3],
				ethernet->ether_dhost[4],
				ethernet->ether_dhost[5]
				);
		
		printf("DATA: src MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
				ethernet->ether_shost[0],
				ethernet->ether_shost[1],
				ethernet->ether_shost[2],
				ethernet->ether_shost[3],
				ethernet->ether_shost[4],
				ethernet->ether_shost[5]
				);
	}
}
  • 특이사항은 MODE 라는 define 으로 정의된 변수가 1일 때만 출력을 한다는 것이다.
  • MODE 가 1이면 Payload 에서 Domain_len 가 존재한다는 뜻이다.

  • 밑의 2개의 새로 정의된 함수도 특이사항이 MODE 뿐이다.
    1. char* print_packet_ip( struct sniff_ip* ip ) ; -> 피드백 1개 존재 !!
    2. unsigned short int print_packet_tcp( struct sniff_tcp* tcp ) ;

2. u_char* print_packet_domain(const char *payload);

u_char* print_packet_domain(const char *payload) {
	
	// domain
	u_char *domain = NULL;
	u_char *domain_end = NULL;
	static u_char domain_str[DOMAIN_BUF] = { 0x00}; // DOMAIN_BUF 256

	int domain_len = 0;

	domain = strstr(payload, "Host: ");
	if( domain != NULL ) {
		domain_end = strstr(domain, "\x0d\x0a");
		if( domain_end != NULL ) {
			domain_len = domain_end - domain - 6;
			strncpy(domain_str, domain + 6, domain_len );
//			printf("INFO: Domain : %s \n", domain_str);
		} else {
//			printf("INFO: Host string not found \n");
		}
	}


	// New DB FOR compare with domain
	
	if( domain_len ) {
		int cmp_ret = 1; // for compare result

		char tmp[REC_DOM_MAX][REC_DOM_LEN] = {0x00};
		// print block_list
		print_block_list(tmp);
		
		// start for loop 1 .
		for(int i = 0; i < 100; i++ ) {

		// if you knew str_len, you choice method like this
		int str1_len = strlen( &tmp[i][0] );
		int str2_len = strlen( domain_str );
		
		// printf("why? %s . \n", &tmp[i][0] ); 
		// printf("str1_len : %d \n", str1_len);
		// printf("domain : %s \n", domain_str);
		// printf("str2_len : %d \n", str2_len);

		if( str1_len != str2_len ) {
			continue; // move to next array !
		}
		
		
		// printf("compare start \n");
		cmp_ret = strcmp( &tmp[i][0], domain_str );
		// if each other string is same length but not same string, so break
		if( cmp_ret < 0 ) break; 
		printf("DEBUG: domain name check result : %d \n", cmp_ret);

		if( cmp_ret == 0 )
			break; // stop for loop 1 .
		
		// break if meet NULL data in array .
		if( strlen( &tmp[0][i] ) == 0 ) 
			break; // stop for loop 1.

		} // end for loop .

		// domain
		printf("INFO: Domain : %s . \n", domain_str);
		
		if( cmp_ret == 0 ) {
			printf("DEBUG: main blocked . \n");
		// sendraw(); // here is block packet function location later
		} else {
			printf("DEBUG: domain allowed . \n");
		} // end if emp_ret .
		
		MODE = 1;
		return domain_str;
	} else {
		MODE = 0;
	}
	
} // end of print_packet_domain
  • print_packet_domain() 의 특징도 MODE domain_len 의 값이 존재할 때 1 아닐 때 0으로 해준다는 것이 특징이다.
  • 피드백 2개 존재 !!

3. void print_block_list(char tmp[REC_DOM_MAX][REC_DOM_LEN]);

void print_block_list(char tmp[REC_DOM_MAX][REC_DOM_LEN]) {
		// Receive Block_list
		res_block = mysql_perform_query(conn, "SELECT * FROM Block_list");
		
		printf("\n");
		printf("Mysql Block_list \n");
		int i = 0, j = 0;
		
		while( (row_block = mysql_fetch_row(res_block) ) != NULL) {
			printf("Domain: %20s | ", row_block[0]);
			printf(" IP: %15s | ", row_block[1]);
			printf(" Port: %7s | \n", row_block[2]);
			strcpy( &tmp[j++][0], row_block[0]);
			// printf("&tmp[j++][0] = %s", &tmp[j++][0]); // j++ coredump warning !!!
			// printf(" tmp : %d \n", strlen(&tmp[j++][0]));  // j++ coredump warning !!!
		}
		printf("\n");
		
		mysql_free_result(res_block);
} // end of print_block_list() .
  • 기존과 다른 점은 매개변수를 2차원 배열인 tmp로 받고 call by reference 형태로 사용한다는 것 뿐이다 !

4. void mysql_insert(char* recv_ip, unsigned short int recv_tcp, u_char* recv_domain);

void mysql_insert(char* recv_ip, unsigned short int recv_tcp, u_char* recv_domain)
{
	// print time
	char* time_buf = now_time();
	// printf("ctime의 결과 : %s\n", time_buf);
	
	// INSERT
	char query[TMP_THUD] = { 0x00};
	// query setting
	sprintf(query, "INSERT INTO Recent_list VALUES('%s', '%s', '%d', '%s')", recv_domain, recv_ip, recv_tcp, time_buf);
	
	if( mysql_query(conn, query) )
		printf("mysql_query Sucess \n");
} // end of mysql_insert() .
  • 특이점은 안에서 now_time() 를 사용한다는 것외에는 전과 동일하게 사용한다. ( 여기 이외에 곳에서는 필요가 없다. )

5. void mysql_select(char* SELECT);

void mysql_select(char* SELECT)
{
	char query[TMP_THUD] = { 0x00 } ;
	sprintf(query, "SELECT * FROM %s", SELECT);
	
	res = mysql_perform_query(conn, query);

	printf("\n");
	printf("Mysql contents in mysql %s \n", SELECT);
	while( (row = mysql_fetch_row(res) ) != NULL){
		printf("Domain: %20s | ", row[0]);
		printf(" IP: %15s | ", row[1]);
		printf(" Port: %7s | ", row[2]);
		printf(" Time: %s . \n", row[3]);
	}
	printf("\n");
	mysql_free_result(res);
} // end of mysql_select() .
  • 전과 다른 점은 SELECT 라는 전역변수로 DB안의 테이블을 보다 편하게 바꿀 수 있다는 점이다.

트러블 슈팅 및 피드백

1. 어떤 링크를 넣던간에 main_block을 하게 됨

도메인을 비교하고 있는데 갑자기 tmp 배열에 입력한 도메인의 값이 들어가서 block_list와 비교하는 cmp_ret의 값이 결국 같다고 나오게 되어,

첫번째 시도 ( 실패 )

  • 원인을 str_cpy() 에 있다고 생각했는데 함수를 사용하는 block_list 에는 naver.com 링크가 없다..

두번째 시도 ( 성공 )

printf("why? %s . \n", &tmp[i][0] ); 
printf("str1_len : %d \n", str1_len);
printf("domain : %s \n", domain_str);
printf("str2_len : %d \n", str2_len);
  • 원인을 알아보기 위해 위의 코드를 사용하여 어디가 문제인지 확인해봤다.
  • 결과: naver.com 도메인과 kakao.com 라는 도메인처럼 서로의 길이가 같을 때 오류가 나는 것을 확인할 수 있었다.
  • 피드백: strcmp() 함수는 반환값이 성공했을 때 0이고, 실패했을 때는 0이 아닌 값이 나오는데
    실패를 하고 나서 계속 값을 비교하기 때문에 strcmp() 함수의 반환값을 저장하는
    cmp_ret 변수의 값이 0이 아닐 때 break; 해주어서 해결했다 !

2. 문자열의 return

문자열을 줘야하는데 return 으로 주는게 안돼서.. 사진처럼 나왔다.

  • pj_db_6_feedback_1

첫번째 시도 ( 성공 )

  • 원인: return 에 문자열. 즉, 문자열의 첫번째를 가리키는 주소값을 주었을 때 함수가 끝나면 return 이 가리키던 주소값의 값들도 모두 사라졌다.

  • 피드백: 함수가 끝이나도 값이 사라지지 않게 하기위해 static 을 붙여주었다 !

Project 카테고리 내 다른 글 보러가기

댓글 남기기