[Project] 프로젝트 DB 테이블안의 내용들을 출력하여 비교하기
카테고리: Project
코드
코드
#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);
// 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);
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, 1000, errbuf);
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;
}
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);
return 0;
} // end of main() .
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char* packet)
{
#define SIZE_ETHERNET 14
const struct sniff_ethernet *ethernet;
const struct sniff_ip *ip;
const struct sniff_tcp *tcp;
const char *payload;
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 < 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 < 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;
// IP
char *IPbuffer, *IPbuffer2;
char IPbuffer_str[16];
char IPbuffer2_str[16];
IPbuffer = inet_ntoa(ip->ip_src);
strcpy(IPbuffer_str, IPbuffer);
IPbuffer2 = inet_ntoa(ip->ip_dst);
strcpy(IPbuffer2_str, IPbuffer2);
// 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);
// domain
u_char *domain = NULL;
u_char *domain_end = NULL;
u_char domain_str[256] = { 0x00};
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");
}
}
// DB
MYSQL_RES *res;
MYSQL_ROW row;
// New DB FOR compare with domain
MYSQL_RES *res_block;
MYSQL_ROW row_block;
MYSQL* conn = mysql_init(NULL);
if (conn == NULL) {
printf("MySQL initialization failed");
return;
}
// connect DB
char* server = "localhost";
char* user = "root";
char* password = "1234";
char* database = "project";
if (mysql_real_connect(conn, server, user, password, database, 0, NULL, 0) == NULL) {
printf("Unable to connect with MySQL server\n");
mysql_close(conn);
return;
}
if( domain_len ) {
int cmp_ret = 1; // for compare result
// NEW - 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;
char tmp[20][100] = {0x00};
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 : %d \n", strlen(&tmp[j++][0])); // j++ coredump warning !!!
}
printf("\n");
// 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] );
// printf("why? %s . \n", &tmp[i][0] );
// printf("str1_len : %d \n", str1_len);
int str2_len = strlen( domain_str );
// 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 );
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 1 .
// port
printf("DATA: IP src : %s \n", IPbuffer_str);
printf("DATA: IP dst : %s \n", IPbuffer2_str);
printf("DATA : src Port %u \n", tcp_src_port);
printf("DATA : dst Port %u \n", tcp_dst_port);
// domain
printf("INFO: Domain : %s . \n", domain_str);
// 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);
char query[1024] = { 0x00};
// query setting
sprintf(query, "INSERT INTO Recent_list VALUES('%s', '%s', '%d', '%s')", domain_str, IPbuffer2_str, tcp_dst_port, time_buf);
// mysql_perform_query(conn, query);
if( mysql_query(conn, query) )
printf("mysql_query Sucess \n");
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 .
res = mysql_perform_query(conn, "SELECT * FROM Recent_list");
printf("\n");
printf("Mysql contents in mysql Recent_list \n");
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);
mysql_close(conn);
} // end if domain_len
} // 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);
}
코드 분석
// NEW - 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;
char tmp[20][100] = {0x00};
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 : %d \n", strlen(&tmp[j++][0])); // j++ coredump warning !!!
}
printf("\n");
- mysql_perform_query() 로 쿼리 실행한 결과를 받아온다.
return 값은 mysql_use_result() 함수를 사용하여 받아오게 된다.
그 값을 MYSQL_RES *res_block 으로 반환시킨다.
그렇게 반환 된 값들을 한 줄씩 불러오기 위해 mysql_fetch_row() 함수를 사용하였고 row_block 변수에 저장된 값들을 tmp라는 2차원 배열에 저장하여 비교하는데 사용했다.
트러블 슈팅 및 피드백
1. 가장 난관이였던 row_block[0] 의 값을 새로운 변수에 담아서 비교하는데 사용하려고 했던 것
첫번째 시도
- row_block[0]의 값을 비교를 위해 쓰일 문자열에 넣어서 출력 먼저 해보기
char *temp = { 0x00};
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(temp, row_block[0]);
printf("temp: %s \n", temp);
}
- 결과: temp에 도메인의 값이 저장이 잘 되어서
printf()
로 출력이 가능했었다.
두번째 시도 ( 실패 )
- 다음 도메인의 값도 저장해야하니 배열에 저장해보기
char *temp[50] = { 0x00};
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(temp[i], row_block[0]);
printf("temp: %s \n", temp[i++]);
}
- 결과: Segmentation error ( core dump )
- 원인: 서로의 자료형이 맞지 않는걸까?
-
피드백: row_block[0]의 값들을 인지 하지 못하여 MYSQL_ROW의 구조체를 찾아봐야했다.
- MYSQL_ROW 구조체
typedef char** MYSQL_ROW
- 더블 포인터를 사용하고 있었다는 걸 찾았다.
세번째 시도 ( 실패 )
- 주소형태로 비교하는 것이 되지만 인덱스를 붙여 참조로 하는 것은 되지 않는 더블포인터형이라면 주소형태로 strcpy()를 실행해보자.
char *temp[50] = { 0x00};
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(&temp[i], row_block[0]);
printf("temp: %s \n", &temp[i++]);
}
-
결과: 오류가 뜨지는 않았지만, Warning 이 뜨기 시작헀다.
- Warning 내용
- 이것을 보고 자료형을 (char*)으로 모두 캐스팅 해주었고, 해결된 것 같았지만 비교할 때 문제가 생기기 시작했다.
-
문제는 strlen() 함수의 값이 도메인의 문자열과 맞지 않는다는 것인데 이게 비교를 하는 cmp_ret 변수의 값을 제대로 받아올 수 없음을 초래했다.
- 원인: 애초에 오류가 안 났을 뿐이지 제대로 값을 가져오지 못한 듯 했다. 왜냐하면 temp라는 배열의 값을 하나하나 찍었을 때 도메인 여러 개가 아니라 한 개의 도메인을 한 글자씩 바라보고 있었기 떄문이었다.
- 피드백: 포인터 배열이 아닌, 2차원 배열을 사용하여 주소값들을 저장해보기로 했다.
네번째 시도 ( 성공 )
printf("\n");
printf("Mysql Block_list \n");
int i = 0, j = 0;
char tmp[20][100] = {0x00};
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 : %d \n", strlen(&tmp[j++][0])); // j++ coredump warning !!!
}
printf("\n");
- 결과: 성공 !!
- 원인: 주소값들을 2차원 배열의 각각 시작 주소에 저장함으로써 도메인의 주소값들을 저장 & 사용할 수 있었다 !
- 피드백: 주소값들을 사용하기 위한 포인터 배열은 왜 안 됐었던건지 이유를 찾아야한다.
2. mysql_send_query() 사용방법 ( 내 트러블슈팅은 아니지만 같은 조원의 트러블 슈팅 중 하나 )
- 공식 문서 내용을 잘 읽어보자.
어떻게 사용하는지, 누구와 사용해야하는지, 매개변수는 어떤 것을 넣어줘야하는지
- 아래는 공식 문서의 내용이다.
mysql_send_query() executes a SQL statement without waiting for the result.
The main purpose of this function is to perform batch execution
of DML statements.
Each successful call to mysql_send_query()
must be followed by a call to mysql_read_query_result().
Multiple calls to mysql_send_query() can be made before the calls
to mysql_read_query_result() are done.
- 이것을 보면 mysql_send_qeury() 는 mysql_read_query_result() 와 함께 사용함을 찾을 수 있다.
- 공식문서 에 답이 없다고 생각하기전에 답부터 찾아보는 습관 을 들여야겠다.
댓글 남기기