[Project] 프로젝트 C언어를 사용하여 DB와 연동
카테고리: Project
전체 코드
코드
#include <stdio.h>
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <mysql.h>
#include <time.h>
// MySQL
struct connection_details {
char *server;
char *user;
char *password;
char *database;
};
// 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");
}
}
// new -------------------------------------
struct check_domain_struct {
char domain[256];
};
// reset method 3 ( use this )
int check_domain_str_count = 10000;
struct check_domain_struct *check_domain_str = NULL;
// malloc
check_domain_str = malloc ( sizeof(struct check_domain_struct) *
check_domain_str_count
);
if( check_domain_str == NULL ) {
fprintf(stderr, "ERROR: malloc fail !!! (line=%d) \n", __LINE__);
} else {
// fprintf(stdout,"INFO: malloc ok (line=%d) \n", __LINE__);
}
// reset 0
memset( check_domain_str, 0x00, sizeof( struct check_domain_struct ) *
check_domain_str_count
);
// method 3 strcpy & check .
strcpy(check_domain_str[0].domain, "naver.com");
if( strlen(check_domain_str[0].domain) == 0 )
fprintf(stderr, "check_domain_str[0] is NULL !! \n");
strcpy(check_domain_str[1].domain, "kakao.com");
if( strlen(check_domain_str[1].domain) == 0 )
fprintf(stderr, "check_domain_str[1] is NULL !! \n");
strcpy(check_domain_str[2].domain, "mail.naver.com");
if( strlen(check_domain_str[2].domain) == 0 )
fprintf(stderr, "check_domain_str[2] is NULL !! \n");
if( domain_len ) {
int cmp_ret = 1; // for compare result
// 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 ( check_domain_str[i].domain );
int str2_len = strlen ( domain_str );
if( str1_len != str2_len ) {
continue; // move to next array !
}
cmp_ret = strcmp(check_domain_str[i].domain, 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( check_domain_str[i].domain) == 0 ) {
break; // stop for loop 1.
}
} // end for loop 1 .
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);
// new -------------------------
// DB
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL* conn = mysql_init(NULL);
if (conn == NULL) {
printf("MySQL initialization failed");
return;
}
struct connection_details mysqlD;
mysqlD.server = "localhost";
mysqlD.user = "root";
mysqlD.password = "1234";
mysqlD.database = "project";
if (mysql_real_connect(conn, mysqlD.server, mysqlD.user, mysqlD.password, mysqlD.database, 0, NULL, 0) == NULL) {
printf("Unable to connect with MySQL server\n");
mysql_close(conn);
return;
}
char query[1024] = { 0x00};
// 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);
//dd
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");
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 .
if( check_domain_str != NULL ) {
free(check_domain_str);
check_domain_str = NULL;
} else {
fprintf(stderr, "CRIT: check_domain_str was already free status !! (line=%d) \n", __LINE__);
} // end check_domain_str
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);
}
분석
1. 선언과 초기화
MYSQL* conn = mysql_init(NULL);
if (conn == NULL) {
printf("MySQL initialization failed");
return;
}
- MYSQL* conn = mysql_init( NULL ) ;
이 부분은 MYSQL 구조체를 사용하여 conn 이란 변수를 초기화하는데,
mysql의 초기화 함수인 mysql_init()
을 사용했다.
1-1. mysql_init( )
MYSQL * mysql_init(MYSQL * mysql);
mysql - a pointer to MYSQL or NULL.
In case of passing a NULL pointer mysql_init() will allocate memory
and return a pointer to a MYSQL structure.
- 위 문법 설명을 보면 MYSQL의 포인터를 가리키던지 아니면 NULL을 준다고 한다.
- 그리고 NULL을 매개변수로 주었을 때
mysql_init()
은 메모리를 할당할 것이며, MYSQL 구조체를 가르키는 포인터를반환
한다 !
Prepares and initializes a MYSQL structure to be used with mysql_real_connect().
If mysql_thread_init() was not called before,
mysql_init() will also initialize the thread subsystem for the current thread
- 설명부분을 보면
mysql_real_connect()
를 사용하여MYSQL 구조체
를 준비하고 초기화할 때,
만약mysql_thread_init()
를사용하지 않았었다
면,
mysql_real_connect()
는 지금의 스레드를 위해 스레드 서브시스템으로초기화
할 것이다. 라는 뜻이다.
2. 연결 및 데이터 추가
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;
}
-
mysql_real_connect()
함수를 사용하여, conn 이라는 MYSQL 구조체에 server 이름과, user의 이름, password,
database의 이름, 포트번호, unix_socket인데 NULL로 주었고, client_flag의 값을 0으로 준 것이다.
2-1. mysql_real_connect()
MYSQL *
mysql_real_connect(MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long client_flag)
-
중요한 것들만 가져온다면,
const char *db
는 적어놓은 DATABASE의 이름을 connection에서의default Database
로 설정한다.
( 없는 DB이름을 적어도 오류가 나지 않으니 주의할 것 ) - 설명이 굉장히 많으므로, 링크를 남기겠다.
- https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-connect.html
2-2. sprintf()
, mysql_query()
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");
- 먼저 이번에 처음 배우게 된
sprintf()
함수는printf()
와 기능은 비슷하지만, 거기에 문자열에 추가할 수 있는 용도로 쓸 수 있는 함수이다. ( 굉장히 유용하다 )
2-3. mysql_query()
int
mysql_query(MYSQL *mysql,
const char *stmt_str)
- stmt_str에 있는 DB 명령어 문자열들을 매개변수 mysql이 가리킨 MYSQL 구조체에서 실행한다.
성공시:
0
실패시:
ERROR ( multiple )
3. DB안에 있는 내용들 불러오기
MYSQL_RES *res;
MYSQL_ROW row;
res = mysql_perform_query(conn, "SELECT * FROM Recent_list");
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]);
}
// 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);
}
- 자료형:
MYSQL_RES
: SELECT 등 결과를 리턴하는 query의 결과를 나타내는 자료형이다. - 자료형:
MYSQL_ROW
: MYSQL_RES에서 하나의 레코드씩 값을 얻어 올때 쓰이는 자료형이다.
3-1. mysql_use_result()
MYSQL_RES *
mysql_use_result(MYSQL *mysql)
- 쿼리를 실행한 mysql의 결과를 자료형:
MYSQL_RES
형으로 반환하는 함수이다.
즉,return values
를 받기 위해서는MYSQL_RES
형으로 선언한 변수가 필요하다.
3-2. mysql_perform_query()
res = mysql_perform_query(conn, "SELECT * FROM Recent_list");
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);
}
- DB데이터를 불러 올 때 써야했는데, 일단 그 이유는 밑의
mysql_fetch_row()
함수를 설명할 때 얘기하도록 하자. - 먼저
mysql_query()
와 동일한 기능을 하지만, 여기선mysql_use_result()
함수를 반환하고, 그 값을 받기 위해서 사용했다.
3-3. mysql_fetch_row()
MYSQL_ROW
mysql_fetch_row(MYSQL_RES *result)
- MYSQL_RES result 안에 있는 값들을 한 줄씩 불러오기 위해서 사용하며,
NULL
이 나왔을 경우 더 이상의 데이터는 없다는 것을 의미한다.
4. time() , ctime()
// 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);
4-1. time()
time_t time(time_t *pTime)
-
time()
은 1970년 1월 1일 0시(UTC)부터 현재까지 흐른 시간을 time_t 타입(초단위 정수)로 반환을 해준다. - 그래서 변환을 위한
ctime()
함수를 사용하는 것이다.
4-2. ctime()
char* ctime(const time_t* pTime);
-
반환형
: Www Mmm dd hh:mm:ss yyyy - 나중에 이걸 사용하더라도
strstr()
를 사용하면 될 듯 하다.
5. mysql_free_result()
mysql_free_result(res);
mysql_close(conn);
-
mysql_query()
을 사용했다면,mysql_free_result()
를 반드시 마지막에 사용해서 메모리를 해제해줘야한다.
댓글 남기기