[Project] C 코드 정리 및 요약

Date:     Updated:

카테고리:

태그:

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

#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
//#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/time.h>
#include <time.h>
#include <math.h>

#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <linux/tcp.h>
#include <netdb.h>

// new
#include <pthread.h> // thread()
#include <unistd.h> // sleep()


// for mariadb .
//#include <mariadb/my_global.h>
#include <mariadb/mysql.h>

#define ETHER_ADDR_LEN	6

/* Ethernet header */
struct sniff_ethernet {
	u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
	u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
	u_short ether_type; /* IP? ARP? RARP? etc */
};

/* IP header */
struct sniff_ip {
	u_char ip_vhl;		/* version << 4 | header length >> 2 */
	u_char ip_tos;		/* type of service */
	u_short ip_len;		/* total length */
	u_short ip_id;		/* identification */
	u_short ip_off;		/* fragment offset field */
#define IP_RF 0x8000		/* reserved fragment flag */
#define IP_DF 0x4000		/* don't fragment flag */
#define IP_MF 0x2000		/* more fragments flag */
#define IP_OFFMASK 0x1fff	/* mask for fragmenting bits */
	u_char ip_ttl;		/* time to live */
	u_char ip_p;		/* protocol */
	u_short ip_sum;		/* checksum */
	struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip)		(((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)		(((ip)->ip_vhl) >> 4)

/* TCP header */
typedef u_int tcp_seq;

struct sniff_tcp {
	u_short th_sport;	/* source port */
	u_short th_dport;	/* destination port */
	tcp_seq th_seq;		/* sequence number */
	tcp_seq th_ack;		/* acknowledgement number */
	u_char th_offx2;	/* data offset, rsvd */
#define TH_OFF(th)	(((th)->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_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
	u_short th_win;		/* window */
	u_short th_sum;		/* checksum */
	u_short th_urp;		/* urgent pointer */
};

/*------------------global variables------------------*/
// socket
#define TO_MS 1000
#define IP_SIZE 16
#define IP_HDR_SIZE 20
#define TCP_HDR_SIZE 20

// sendraw
char bind_device_name[] = "lo" ;
int bind_device_name_len = 2 ;
int sendraw_mode = 1;

// DB
MYSQL *connection = NULL;
MYSQL conn;
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL_RES *res_block;
MYSQL_ROW row_block;
MYSQL_RES *res_check;
MYSQL_ROW row_check;
int cmp_ret = 1; // base: allow
#define DOMAIN_BUF 260
#define REC_DOM_MAX 100
#define REC_DOM_LEN 260
// DB - new
int log_cnt = 0;
MYSQL_RES *res_check;
MYSQL_ROW row_check;
MYSQL_RES *res_cnt;
MYSQL_ROW row_cnt;
char block_domain_arr[REC_DOM_MAX][REC_DOM_LEN] = { 0x00 }; // block_domain_arr array for print block_list
int block_domain_count = 1;

// TCP Header checksum
struct pseudohdr {
        u_int32_t   saddr;
        u_int32_t   daddr;
        u_int8_t    useless;
        u_int8_t    protocol;
        u_int16_t   tcplength;
};

// Protocol Info
char IPbuffer_str[IP_SIZE]; 		// IP_SIZE 16
char IPbuffer2_str[IP_SIZE]; 		// IP_SIZE 16
unsigned short tcp_src_port = 0;
unsigned short tcp_dst_port = 0;

// int gbl_debug = 1; 	// later .
// int g_ret = 0; 		// later .



/*------------------function------------------*/
// got_packet
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void print_info(const struct sniff_ethernet *ethernet, 
				const struct sniff_ip *ip, 
				const struct sniff_tcp *tcp,
				u_char* domain_str);

// DB
MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query);
void mysql_insert(u_char* domain_str);
void mysql_select_log();
void mysql_block_list(u_char* domain_str, const u_char *packet);
// DB - new
int get_mysql_log_cnt();
void select_block_list();
void *update_block_5m_run();


// sendraw
int sendraw( u_char* pre_packet , int mode ) ;
int print_chars(char print_char, int nums);
void print_payload_right(const u_char *payload, int len);
void print_hex_ascii_line_right(const u_char *payload, int len, int offset);
unsigned short in_cksum ( u_short *addr , int len );



///////////////////////////////////////
//                                   //
// begin MAIN FUNCTION !!!    		 //
//                                   //
///////////////////////////////////////
int main(int argc, char *argv[])
{
	pcap_t *handle;					/* Session handle */
	char *dev;						/* The device to sniff on */
	char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
	struct bpf_program fp;			/* The compiled filter */
	char filter_exp[] = "port 80";	/* The filter expression */
	bpf_u_int32 mask;				/* Our netmask */
	bpf_u_int32 net;				/* Our IP */
	struct pcap_pkthdr header;		/* The header that pcap gives us */
	const u_char *packet;			/* The actual packet */
	struct pcap_if *devs;
	int result = 0 ;
	
	/* Define the device */
	pcap_findalldevs(&devs, errbuf);
	printf("INFO: dev name = %s .\n" , (*devs).name );
	dev = (*devs).name ;
	// strcpy(dev, "lo");
	
	
	/* Find the properties for the device */
	if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
		fprintf(stderr, "Couldn't get netmask for device %s: %s  (LINE=%d)\n", dev, errbuf, __LINE__);
		net = 0;
		mask = 0;
	}
	/* Open the session in promiscuous mode */
	handle = pcap_open_live(dev, BUFSIZ, 1, TO_MS, errbuf); 	// TO_MS 1000
	if (handle == NULL) {
		fprintf(stderr, "Couldn't open device %s: %s  (LINE=%d)\n", dev, errbuf, __LINE__);
		return(2);
	}
	/* Compile and apply the filter */
	if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
		fprintf(stderr, "Couldn't parse filter %s: %s  (LINE=%d)\n", filter_exp, pcap_geterr(handle), __LINE__);
		return(2);
	}
	if (pcap_setfilter(handle, &fp) == -1) {
		fprintf(stderr, "Couldn't install filter %s: %s  (LINE=%d)\n", filter_exp, pcap_geterr(handle), __LINE__);
		return(2);
	}
	
	
	
	
	mysql_init(&conn);
	connection = mysql_real_connect(
			&conn,				// mariadb/mysql handler
			"192.168.35.4",		// host address
			"dbuser",				// db id
			"dbuserpass",				// db pass
			"project_db",		// db_name
			3306,				// port
			(char*)NULL,		// unix_socket -> usually NULL
			0					// client_flag -> usually 0
	);
	
	
	if ( connection == NULL ) {
		fprintf ( stderr , "ERROR: mariadb connection error: %s  (LINE=%d)\n", mysql_error(&conn) , __LINE__);
		return 1;
	} else { 
		fprintf ( stdout , "INFO: mariadb connection OK\n" );
	}

	/*-----------------Thread new-----------------*/
	pthread_t update_block_5m;
	int threadErr;
	// thread run 1
	if(threadErr = pthread_create(&update_block_5m,NULL,update_block_5m_run,NULL))
		fprintf(stderr, "ERROR: pthread_create()_5m error !! (LINE=%d) \n",__LINE__);
	
	result = pcap_loop(handle, 0, got_packet, NULL) ;
	if ( result != 0 ) {
		fprintf(stderr, "ERROR: pcap_loop end with error !!!!  (LINE=%d)\n", __LINE__);
	} else {
		fprintf(stdout, "INFO: pcap_loop end without error .\n");
	}
	
	/* And close the session */
	pcap_close(handle);
	return(0);
} // end of main function.

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) 
{
	/*------------------ethernet------------------*/
	#define SIZE_ETHERNET 14 /* ethernet headers are always exactly 14 bytes */
	const struct sniff_ethernet *ethernet; /* The ethernet header */
	ethernet = (struct sniff_ethernet*)(packet); // ethernet header
	
	/*---------------------IP---------------------*/
	u_int size_ip;
	const struct sniff_ip *ip;
	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
	size_ip = IP_HL(ip)*4;
	if (size_ip < IP_HDR_SIZE)	// IP_HDR_SIZE 20
	{											
		// printf("   * Invalid IP header length: %u bytes\n", size_ip);
		return;
	}
		
	/*--------------------PORT--------------------*/
	u_int size_tcp;
	const struct sniff_tcp *tcp;
	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
	{
		// printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
		return;
	}
		
	/*-------------------payload------------------*/
	const char *payload; /* Packet payload */
	unsigned short payload_len = 0; // payload
	payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
	payload_len = ntohs(ip->ip_len) - size_ip - size_tcp;
	// printf("payload_len (pre_packet) %u \n", payload_len);
	
	/*-------------------domain-------------------*/
	u_char* domain = NULL;
	u_char* domain_end = NULL;
	u_char domain_str[DOMAIN_BUF] = {0x00};		// DOMAIN_BUF 260
	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);
		}
	}

	/*-----------------print data-----------------*/
	if(domain_len){
		
		// print ehternet, ip, tcp, domain
		print_info(ethernet, ip, tcp, domain_str);
		
		// block_list : compare(domain_str <-> block_list), block or allow
		mysql_block_list(domain_str, packet);
		
		// INSERT to tb_packet_log
		mysql_insert(domain_str);
		
		// SELECT tb_packet_log
		// mysql_select_log();
		
		// fputc('\n',stdout);	
	}	
	
} // end of got_packet function .

unsigned short in_cksum(u_short *addr, int len)
{
        int         sum = 0;
        int         nleft = len;
        u_short     *w = addr;
        u_short     answer = 1;		// return for checksum .
		u_short 	result = 0;		// check for integrity .
		
        while (nleft > 1){
            sum += *w++;
            nleft -= 2;
        }

        if (nleft == 1){
            *( (u_char *)(&answer) ) = *(u_char *)w ;
            sum += answer;
        }
		
        sum = (sum >> 16) + (sum & 0xffff); // hight bit(8 8=16) + low bit(ff ff) .
        sum += (sum >> 16); 				// wrap around -> carry value is too add in sum .
		
        answer = ~sum;

		result = answer + sum  + 1;
		if( result == 0 ) {
			//	fprintf(stdout, "INFO: tcphdr in_cksum() success ! \n");
			return answer;
		} else {
			fprintf(stderr, "ERROR :  tcphdr in_cksum() result is not integrity status !! (LINE=%d) \n",__LINE__);
			return -1;
		}
}
// end in_cksum function .


int sendraw( u_char* pre_packet, int mode)
{
		const struct sniff_ethernet *ethernet;  /* The ethernet header [1] */

		u_char packet[1600];
        int IP_HDRINCL_ON=1, len ; // len Later .
        struct iphdr *iphdr;
        struct tcphdr *tcphdr;
        struct in_addr source_address, dest_address;
        struct pseudohdr *pseudo_header;
        struct in_addr ip;
		struct sockaddr_in address, target_addr; // target_addr later
        int port;
        int pre_payload_size = 0 ;
		u_char *payload = NULL ;
		int size_payload = 0 ;
        int post_payload_size = 0 ;
        int sendto_result = 0 ;
		int setsockopt_result = 0 ;
		int prt_sendto_payload = 1 ;

		int ret = 1 ;							
		int raw_socket, recv_socket;			// recv_socket later .
		
		
		// --------vlan--------
		// int size_vlan = 0 ; 					// excepted because of i think that i don't need this yet .
		// int size_vlan_apply = 0 ; 			// excepted because of i think that i don't need this yet .
		// int vlan_tag_disabled = 0 ;			// excepted because of i think that i don't need this yet .
		
		// --------later--------
		// char recv_packet[100], compare[100]; // later .
        // struct hostent *target; 				// later .
		// int loop1=0; 						// later .
        // int loop2=0; 						// later .
		// int rc = 0 ; 						// later .
		// struct ifreq ifr ; 					// relative ioctl() -> ioctl function is control hardware and analyze hardware status
		// char * if_bind ; 					// later .
		// int if_bind_len = 0 ; 				// later .
		// char* ipaddr_str_ptr ; 				// later .
		
		//	--------nope--------
		//	int warning_page = 1 ;
		

		#ifdef SUPPORT_OUTPUT
			printf("\n");
			print_chars('\t',6);
			printf( "[raw socket sendto]\t[start]\n\n" );

			print_chars('\t',6);
			printf("   PRE_PACKET WHOLE(L2_PACKET_DATA) (%d bytes only):\n", 54);
			print_payload_right(pre_packet, 54);
			printf("\n");
		#endif

        for( port=80; port<81; port++ ) {
			// create raw socket
			raw_socket = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
			if ( raw_socket < 0 ) {
				print_chars('\t',6);
				fprintf(stderr,"Error in socket() creation - %s  (LINE=%d)\n", strerror(errno) , __LINE__);
				fprintf(stderr,"Error in socket() creation - %s  (LINE=%d)\n", strerror(errno) , __LINE__);
				return -2;
			}
		
			// IP_HDRINCL option: include IP_Header .
			setsockopt( raw_socket, IPPROTO_IP, IP_HDRINCL, (char *)&IP_HDRINCL_ON, sizeof(IP_HDRINCL_ON)); 

			if ( bind_device_name != NULL ) {
				// i think that ifreq will be use later ( SO_BINDTODEVICE ) .
				setsockopt_result = setsockopt( raw_socket, SOL_SOCKET, SO_BINDTODEVICE, bind_device_name, bind_device_name_len );

				if( setsockopt_result == -1 ) {
					print_chars('\t',6);
					fprintf(stderr,"ERROR: setsockopt() - %s  (LINE=%d)\n", strerror(errno) , __LINE__);
					return -2;
				}
				#ifdef SUPPORT_OUTPUT
				else {
					print_chars('\t',6);
					fprintf(stdout,"OK: setsockopt(%s)(%d) - %s  (LINE=%d)\n", bind_device_name, setsockopt_result, strerror(errno) , __LINE__);
				}
				#endif
			}
			
			// ethernet setting in pre_packet without vlan
			ethernet = (struct sniff_ethernet*)(pre_packet);
			if (ethernet->ether_type == (unsigned short)*(unsigned short*)&"\x08\x00" ) {
				#ifdef SUPPORT_OUTPUT
				print_chars('\t',6);
				printf("NORMAL PACKET");
				#endif
			} else {
				fprintf(stderr,"NOTICE: ether_type is not IPv4, so you prepare other ether_types .......... \n");
			}

			// TCP, IP reset header without vlan
			iphdr = (struct iphdr *)(packet) ;
			memset( iphdr, 0, 20 );
			tcphdr = (struct tcphdr *)(packet + 20);
			memset( tcphdr, 0, 20 );

			// twist s and d address
			source_address.s_addr = ((struct iphdr *)(pre_packet + 14))->daddr ;
			dest_address.s_addr = ((struct iphdr *)(pre_packet + 14))->saddr ;		// for return response
          
			iphdr->id = ((struct iphdr *)(pre_packet + 14))->id ;// identification field in ip_header
			
			int pre_tcp_header_size = 0;
			// char pre_tcp_header_size_char = 0x0; 	// Later
			pre_tcp_header_size = ((struct tcphdr *)(pre_packet + 14 + 20))->doff ;
			pre_payload_size = ntohs( ((struct iphdr *)(pre_packet + 14))->tot_len ) - ( 20 + pre_tcp_header_size * 4 ) ;

			// TCP header setting
			tcphdr->source = ((struct tcphdr *)(pre_packet + 14 + 20))->dest ;// src_port field in tcp_header
			tcphdr->dest = ((struct tcphdr *)(pre_packet + 14 + 20))->source ;// dst_port field in tcp_header
			tcphdr->seq = ((struct tcphdr *)(pre_packet + 14 + 20))->ack_seq ;// SEQ num field in tcp_header
			tcphdr->ack_seq = ((struct tcphdr *)(pre_packet + 14 + 20))->seq  + htonl(pre_payload_size - 20)  ;// ACK num field in tcp_header
			tcphdr->window = ((struct tcphdr *)(pre_packet + 14 + 20))->window ;// window field in tcp_header
			tcphdr->doff = 5;// offset field in tcp_header
			tcphdr->ack = 1;// tcp_flag field in tcp_header
			tcphdr->psh = 1;// tcp_flag field in tcp_header
			tcphdr->fin = 1;// tcp_flag field in tcp_header
			
			// created pseudo_header for calculate TCP checksum ( total = 12bytes )
			pseudo_header = (struct pseudohdr *)((char*)tcphdr-sizeof(struct pseudohdr));
			pseudo_header->saddr = source_address.s_addr;// TTL,Protocol,Checksum field in ip_header(strange value)
			pseudo_header->daddr = dest_address.s_addr;// src_ip field in ip_header(not change value)
			pseudo_header->useless = (u_int8_t) 0;// reserved field in tcp_header
			pseudo_header->protocol = IPPROTO_TCP;// dst_ip field in ip_header(strange value)
			pseudo_header->tcplength = htons( sizeof(struct tcphdr) + post_payload_size);// dst_ip field in ip_header(strange value)


			char *fake_packet = 
					"HTTP/1.1 200 OK\x0d\x0a"
					"Content-Length: 530\x0d\x0a"
					"Content-Type: text/html"
					"\x0d\x0a\x0d\x0a"
					"<html>\r\n"
					"<head>\r\n"
					"<meta charset=\"UTF-8\">\r\n"
					"<title>\r\n"
					"CroCheck - WARNING - PAGE\r\n"
					"SITE BLOCKED - WARNING - \r\n"
					"</title>\r\n"
					"</head>\r\n"
					"<body>\r\n"
					"<center>\r\n"
					"<img   src=\"http://127.0.0.1/warning2.jpg\" alter=\"*WARNING*\">\r\n"
					"<h1>SITE BLOCKED</h1>\r\n"
					"</center>\r\n"
					"</body>\r\n"
					"</html>\r\n"
					;
			
			post_payload_size = strlen(fake_packet);
			
			
			memcpy ( (char*)packet + 40, fake_packet , post_payload_size ) ;
			
			
			// renewal after post_payload_size for calculate TCP checksum
			pseudo_header->tcplength = htons( sizeof(struct tcphdr) + post_payload_size);

			// calculate TCP header checksum
			tcphdr->check = in_cksum( (u_short *)pseudo_header,
			               sizeof(struct pseudohdr) + sizeof(struct tcphdr) + post_payload_size);// checksum field in tcp_header

			
			// line
			print_chars('\t',6);
			
			// IP header setting
			iphdr->version = 4;// version field in ip_header
			iphdr->ihl = 5;// IHL field in ip_header
			iphdr->protocol = IPPROTO_TCP;// protocol field in ip_header(reset)
			iphdr->tot_len = htons(40 + post_payload_size);// total length field in ip_header
			iphdr->id = ((struct iphdr *)(pre_packet + 14))->id + htons(1);//identification field in ip_header(increase 1)
			
			// 0x40 -> don't use flag
			memset( (char*)iphdr + 6 ,  0x40  , 1 );// IP_flags field in ip_header
			iphdr->ttl = 60;// TTL field in ip_header(reset)
			iphdr->saddr = source_address.s_addr;// src_ip field in ip_header(change value)
			iphdr->daddr = dest_address.s_addr;// dst_ip field in ip_header(change value)
			
			// calculate IP header checksum
			iphdr->check = in_cksum( (u_short *)iphdr, sizeof(struct iphdr));// checksum field in ip_header(reset)
			
			// for sendto
			address.sin_family = AF_INET;
			address.sin_port = tcphdr->dest ;
			address.sin_addr.s_addr = dest_address.s_addr;

			if( prt_sendto_payload == 1 ) {

				#ifdef SUPPORT_OUTPUT
				printf("\n\n");
				print_chars('\t',6);
				printf("----------------sendto Packet data----------------\n");

				print_chars('\t',6);
				printf("    From: %s(%hhu.%hhu.%hhu.%hhu)\n",
								inet_ntoa( source_address ),
								((char*)&source_address.s_addr)[0],
								((char*)&source_address.s_addr)[1],
								((char*)&source_address.s_addr)[2],
								((char*)&source_address.s_addr)[3]
						);
				print_chars('\t',6);
				printf("      To: %s(%hhu.%hhu.%hhu.%hhu)\n",
								inet_ntoa( dest_address ),
								((char*)&dest_address.s_addr)[0],
								((char*)&dest_address.s_addr)[1],
								((char*)&dest_address.s_addr)[2],
								((char*)&dest_address.s_addr)[3]
						);

				switch(iphdr->protocol) {
					case IPPROTO_TCP:
						print_chars('\t',6);
						printf("Protocol: TCP\n");
						break;
					case IPPROTO_UDP:
						print_chars('\t',6);
						printf("Protocol: UDP\n");
						return -1;
					case IPPROTO_ICMP:
						print_chars('\t',6);
						printf("Protocol: ICMP\n");
						return -1;
					case IPPROTO_IP:
						print_chars('\t',6);
						printf("Protocol: IP\n");
						return -1;
					case IPPROTO_IGMP:
						print_chars('\t',6);
						printf("Protocol: IGMP\n");
						return -1;
					default:
						print_chars('\t',6);
						printf("Protocol: unknown\n");
						return -2;
				}

				print_chars('\t',6);
				printf("Src port: %d\n", ntohs(tcphdr->source));
				print_chars('\t',6);
				printf("Dst port: %d\n", ntohs(tcphdr->dest));
				
				#endif

				payload = (u_char *)(packet + sizeof(struct iphdr) + tcphdr->doff * 4 );

				size_payload = ntohs(iphdr->tot_len) - ( sizeof(struct iphdr) + tcphdr->doff * 4 );
				
				#ifdef SUPPORT_OUTPUT
				if (size_payload > 0) {
					printf("\n");
					print_chars('\t',6);
					printf("   PACKET-HEADER(try1) (%d bytes):\n", ntohs(iphdr->tot_len) - size_payload); // 40
					print_payload_right((const u_char*)&packet, ntohs(iphdr->tot_len) - size_payload);
				}

				if (size_payload > 0) {
					printf("\n");
					print_chars('\t',6);
					printf("   Payload (%d bytes):\n", size_payload);
					print_payload_right(payload, size_payload);
				}
				#endif
				
			} // end -- if -- prt_sendto_payload = 1 ;
			
			if ( mode == 1 ) {
				sendto_result = sendto( raw_socket, &packet, ntohs(iphdr->tot_len), 0x0,
										(struct sockaddr *)&address, sizeof(address) ) ;
				if ( sendto_result != ntohs(iphdr->tot_len) ) {
					fprintf ( stderr,"ERROR: sendto() - %s  (LINE=%d)\n", strerror(errno) , __LINE__) ;
					ret = -2;
				} else {
					// fprintf ( stdout,"INFO: sendto() success ! \n");
					ret = 0;
				}
			} // end if(mode)


			if ( (unsigned int)iphdr->daddr == (unsigned int)*(unsigned int*)"\xCB\xF6\x53\x2C" ) {
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf("##########################################################################################################################\n");
				printf( "address1 == %hhu.%hhu.%hhu.%hhu\taddress2 == %X\taddress3 == %X\n",
						*(char*)((char*)&source_address.s_addr + 0),*(char*)((char*)&source_address.s_addr + 1),
						*(char*)((char*)&source_address.s_addr + 2),*(char*)((char*)&source_address.s_addr + 3),
						source_address.s_addr,	(unsigned int)*(unsigned int*)"\xCB\xF6\x53\x2C" );
			}
			
			close( raw_socket );
        } // end for loop
		
		#ifdef SUPPORT_OUTPUT
		printf("\n");
		print_chars('\t',6);
        printf( "[sendraw] end . \n\n" );
		#endif
	
		
		return ret; // 0 -> normal exit
}
// end sendraw function .


int print_chars(char print_char, int nums)
{
	int i = 0;
	for ( i ; i < nums ; i++) {
		printf("%c",print_char);
	}
	return i;
}


void
print_hex_ascii_line_right(const u_char *payload, int len, int offset)
{
	int i;
	int gap;
	const u_char *ch;
	int tabs_cnt = 6 ;  // default at now , afterward receive from function caller

	/* print 10 tabs for output to right area	*/
	for ( i = 0 ; i < tabs_cnt ; i++ ) {
		printf("\t");
	}

	/* offset */
	printf("%05d   ", offset);

	/* hex */
	ch = payload;
	for(i = 0; i < len; i++) {
		printf("%02x ", *ch);
		ch++;
		/* print extra space after 8th byte for visual aid */
		if (i == 7)
			printf(" ");
	}
	/* print space to handle line less than 8 bytes */
	if (len < 8)
		printf(" ");

	/* fill hex gap with spaces if not full line */
	if (len < 16) {
		gap = 16 - len;
		for (i = 0; i < gap; i++) {
			printf("   ");
		}
	}
	printf("   ");

	/* ascii (if printable) */
	ch = payload;
	for(i = 0; i < len; i++) {
		if (isprint(*ch))
			printf("%c", *ch);
		else
			printf(".");
		ch++;
	}

	printf("\n");

	return;
}

/*
 * print packet payload data (avoid printing binary data)
 */
void
print_payload_right(const u_char *payload, int len)
{

	int len_rem = len;
	int line_width = 16;			/* number of bytes per line */
	int line_len;
	int offset = 0;					/* zero-based offset counter */
	const u_char *ch = payload;


	if (len <= 0)
		return;

	/* data fits on one line */
	if (len <= line_width) {
		print_hex_ascii_line_right(ch, len, offset);
		return;
	}

	/* data spans multiple lines */
	for ( ;; ) {
		/* compute current line length */
		line_len = line_width % len_rem;
		/* print line */
		print_hex_ascii_line_right(ch, line_len, offset);
		/* compute total remaining */
		len_rem = len_rem - line_len;
		/* shift pointer to remaining bytes to print */
		ch = ch + line_len;
		/* add offset */
		offset = offset + line_width;
		/* check if we have line width chars or less */
		if (len_rem <= line_width) {
			/* print last line and get out */
			print_hex_ascii_line_right(ch, len_rem, offset);
			break;
		}
		//m-debug
		if ( offset > 600 ) {
			print_chars('\t',6);
			printf("INFO: ..........    payload too long (print_payload_right func) \n");
			break;
		}
	}
    return;
}


void mysql_block_list(u_char* domain_str, const u_char *packet) {
		
		// printf("block list start\n");
		cmp_ret = 1; // reset ( for delete block_list ) .
		// compare---------------------------------
		for(int i = 0; i < block_domain_count; i++ ) {

			// if you knew str_len, you choice method like this
			int str1_len = strlen( &block_domain_arr[i][0] ); // block list
			int str2_len = strlen( domain_str );		// domain_string
			// printf("domain domain :  %s \n", domain_str);
			// printf("block domain :  %s \n", &block_domain_arr[i][0]);
			// printf("block : %s \n",&block_domain_arr[i][0]);
			// break different value each other and
			if( str1_len != str2_len && str1_len != 0 ) {
				continue; // move to next array .
			}
			// printf("block -> %s \n", &block_domain_arr[i][0]);
			cmp_ret = strcmp( &block_domain_arr[i][0], domain_str );

			if( cmp_ret == 0 )
				break;
		} 

		// block or allow
		if( cmp_ret == 0 ) {
			// printf("DEBUG: domain blocked . \n");
			int sendraw_ret = sendraw(packet , sendraw_mode);
			if ( sendraw_ret != 0 ) {
				fprintf(stderr, "ERROR: emerge in sendraw() !!! (LINE=%d) \n",__LINE__);
			}
		} else {
			// printf("DEBUG: domain allowed . \n");
			cmp_ret = 1; // new show allow 
		} // end if emp_ret .
} // end of mysql_block_list() .

MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query) {
 
	sleep(3); // delay for error
    if(mysql_query(connection, sql_query)) {
        printf("MYSQL query error : %s (LINE=%d) \n",mysql_error(connection), __LINE__);
        exit(1);
    }
    return mysql_use_result(connection);
} // end of mysql_perform_query() .

void mysql_insert(u_char* domain_str)
{
	// INSERT
	char query[DOMAIN_BUF] = { 0x00}; // DOMAIN_BUF 260
	
	// analyze log_cnt value
	if( get_mysql_log_cnt() >= 100 ) {
		mysql_query(connection, "DELETE FROM tb_packet_log ORDER BY created_at ASC LIMIT 1");
	} 
	

	if (  !strcmp(IPbuffer2_str,"192.168.111.150") ) {
		// query setting
		sprintf(query,"INSERT INTO tb_packet_log ( src_ip , src_port , dst_ip , dst_port , domain , result )"
				  "VALUES('%s', '%u', '%s' , '%u' , '%s' , '%d')",
				  IPbuffer_str , 
				  tcp_src_port , 
				  IPbuffer2_str , 
				  tcp_dst_port ,  
				  domain_str , 
				  cmp_ret
				  );

		if( mysql_query(connection, query) != 0 ) {
		fprintf(stderr, "ERROR : mysql_query() is failed !!!  (LINE=%d)\n", __LINE__);
		} else {
			// printf("mysql_query() success :D \n");
		}
	} else {
		printf("connect another server ! ");
	}
} // end of mysql_insert() .


void mysql_select_log()
{
	char query[DOMAIN_BUF] = { 0x00 }; // DOMAIN_BUF 260
	sprintf(query, "SELECT * FROM tb_packet_log");
	
	res = mysql_perform_query(connection, query);

	printf("\n");
	int cnt = 1;
	
	while( (row_check = mysql_fetch_row(res) ) != NULL){
		printf("Mysql contents in tb_packet_log [ row : %d | ID : %s ] \n", cnt++, row[0]);
		printf(" src_ip: %20s | ", row[1]); 
		printf(" src_port: %5s | \n", row[2]);
		printf(" dst_ip: %20s | ", row[3]);
		printf(" dst_port: %5s | \n", row[4]);
		printf(" Domain: %20s | ", row[5]);
		printf(" result: %7s | ", row[6]);
		printf(" created at: %s . \n\n\n", row[7]);
	}
	printf("\n");
	mysql_free_result(res);
} // end of mysql_select_log() .


void print_info(const struct sniff_ethernet *ethernet, 
				const struct sniff_ip *ip, 
				const struct sniff_tcp *tcp,
				u_char* domain_str)
{

	#ifdef SUPPORT_OUTPUT
	// print ethernet
	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]
	);
	#endif

	// print ip
	char *IPbuffer, *IPbuffer2;

	IPbuffer = inet_ntoa(ip->ip_src);
	strcpy(IPbuffer_str, IPbuffer);
	IPbuffer2 = inet_ntoa(ip->ip_dst);
	strcpy(IPbuffer2_str, IPbuffer2);
	
	#ifdef SUPPORT_OUTPUT
	printf("DATA: IP src : %s\n",IPbuffer_str);
	printf("DATA: IP dst : %s\n",IPbuffer2_str);
	#endif
	
	// print port
	tcp_src_port = ntohs(tcp->th_sport);
	tcp_dst_port = ntohs(tcp->th_dport);
	
	#ifdef SUPPORT_OUTPUT
	printf("DATA: src Port : %u\n", tcp_src_port);
	printf("DATA: dst Port : %u\n", tcp_dst_port);	
	
	
	// print domain
	printf("INFO: Domain = %s\n", domain_str);
	#endif
}


int get_mysql_log_cnt()
{
	char query[DOMAIN_BUF] = { 0x00 }; // DOMAIN_BUF 260
	log_cnt = 0;
	sprintf(query, "SELECT * FROM tb_packet_log");	
	res_cnt = mysql_perform_query(connection, query);
	while( (row_cnt = mysql_fetch_row(res_cnt) ) != NULL) {
		log_cnt++;
	}
	mysql_free_result(res_cnt);
	return log_cnt;
} // end of mysql_select_log() .


void *update_block_5m_run()
{
    while(1)
    {
		select_block_list();
        sleep(300); // per seconds ( test 3seconds 	)
	}
} // end of update_block_5m_run() .

void select_block_list() {
	// printf("select block list start\n");
	// Receive tb_packet_block---------------------------------
	res_block = mysql_perform_query(connection, "SELECT * FROM tb_packet_block");

	block_domain_count = 0;
	// printf(test++);
	while( (row_block = mysql_fetch_row(res_block) ) != NULL){
			// printf("Mysql block_list in tb_packet_block [ row : %d | ID : %s ] \n", block_domain_count, row_block[0]);
			// printf("src_ip: %20s | ", row_block[1]); 			
			// printf("src_port: %5s | \n", row_block[2]);
			// printf("dst_ip: %20s | ", row_block[3]);
			// printf("dst_port: %5s | \n", row_block[4]);
			// printf("Domain: %20s | ", row_block[5]);
			// printf("created at: %s . \n\n\n", row_block[6]); 	// doesn't exist result in block_list
			strcpy( &block_domain_arr[block_domain_count++][0], row_block[5]);	// string copy for compare
		}
}

지난 코드와의 변경점

  1. 불필요한 변수 정리
  2. 함수 간략화 select_block_list() 함수가 포함된 Thread 1번 ( update_block_5m_run() )을
    임시 테스트때문에 여러 테이블로 했었었는데 테이블을 1개로 바꾸면서
    일정 시간마다 select_block_list() 만 사용하게 바꾸었다.

구현하면서 생겼던 트러블 슈팅

  1. Multi Thread의 반복 생성
    • 처음엔 스레드의 호출위치는 242번째 라인 이 아닌, 312번째 라인 이였다.
      그래서 패킷이 캡쳐될 때마다 스레드를 만들어냈으며 그것이 비정상적인 select_block_list() 호출을 야기했었다.
      개선: main함수 안에서 한 번 호출 후에 일정 간격으로 유해사이트의 리스트를 업데이트하는 것으로 해결하였다.

  2. html 크롤링시 한글이 깨짐
    • utf-8을 적용시키지 못하여 index.jsp 파일안에
      <%@
      page language="java"
      contentType="text/html;charset=UTF-8"
      pageEncoding="UTF-8"
      %>
      

      이 부분을 추가하여 page를 utf-8로 인코딩하여 해결했다.

  3. DB 관련 DB RSA Encrytion 오류
    • DB 관리용 서버를 새로 만들면서 계정을 만들었는데
      ERROR 2061 (HY000): RSA Encryption not supported - caching_sha2_password plugin was built with GnuTLS support
      RSA 오류가 발생하였다.
      패스워드의 버전이 지원되지 않는다는 원인을 발견하여, 현재 계정의 패스워드를
      ALTER USER ‘username’@’%’ IDENTIFIED WITH mysql_native_password BY ‘password’;.
      ALTER 명령어로 패스워드의 버전을 바꿔주면서 해결했다.

  4. Node js 에서 page수를 css파일 까지 모두 읽어버리는 오류 (미해결)
javascript 코드
// board pasing
router.get("/pasing/:cur", function (req, res) {

    if (!authCheck.isOwner(req, res)) {  // 로그인 안되어있으면 로그인 페이지로 이동시킴
        res.redirect('/auth/login');
        return false;
      }

    
    
    var page_size = 10; // 페이지 장수
    var page_list_size = 10; // 리스트 개수
    var no = ""; // LIMIT variable
    var totalPageCount = 0;

    var queryString = 'SELECT count(*) AS cnt FROM tb_packet_block'
    db.query(queryString, function (error2, data) {
        if (error2) {
            console.log(error2 + "mysql_error() main page");
            return
        }
        
        totalPageCount = data[0].cnt
 
        // console.log(req.params);
        var curPage = req.params.cur;

        // console.log("현재 페이지 : " + curPage, "전체 페이지 : " + totalPageCount);

        if (totalPageCount < 0) {
            totalPageCount = 0
        }

        var totalPage = Math.ceil(totalPageCount / page_size);
        var totalSet = Math.ceil(totalPage / page_list_size);        
        var curSet = Math.ceil(curPage / page_list_size) 
        var startPage = ((curSet - 1) * 10) + 1 
        var endPage = (startPage + page_list_size) - 1; 

        if (curPage < 0) {
            no = 0
        } else {
            //0보다 크면 limit 함수에 들어갈 첫번째 인자 값 구하기
            no = (curPage - 1) * 10
        }

        

        console.log('[0] curPage : ' + curPage + 
                    ' | [1] page_list_size : ' + page_list_size + 
                    ' | [2] page_size : ' + page_size + 
                    ' | [3] totalPage : ' + totalPage + 
                    ' | [4] totalSet : ' + totalSet + 
                    ' | [5] curSet : ' + curSet + 
                    ' | [6] startPage : ' + startPage + 
                    ' | [7] endPage : ' + endPage
                    )

        var result2 = {
            "curPage": curPage,
            "page_list_size": page_list_size,
            "page_size": page_size,
            "totalPage": totalPage,
            "totalSet": totalSet,
            "curSet": curSet,
            "startPage": startPage,
            "endPage": endPage
        };


        fs.readFile('crud/list_test.html', 'utf-8', function (error, data) {

            if (error) {
                console.log("ejs오류" + error);
                return
            }
            // console.log("몇번부터 몇번까지냐~~~~~~~" + no)

            var queryString = "SELECT *, DATE_FORMAT(created_at,'%Y년-%m월-%d일-%H시-%i분') created_at FROM tb_packet_block ORDER BY created_at DESC LIMIT ?,?";
            
            db.query(queryString, [no, page_size], function (error, result) {
                if (error) {
                    console.log("페이징 에러" + error);
                    return
                }
                    
                res.send(ejs.render(data, {
                    data: result,
                    pasing: result2
                }));
            });
        }); 
    })
})
  • page수를 포함하여 block_list 를 구현하려고 했던 부분이다.
    여기서 css 파일 을 따로 빼서 정리를 하려고 했었는데
    css파일 을 따로 떼어보니 page 수가 css파일 까지 읽어버리는 바람에 페이지 수를 NaN 로 읽어버렸고,
    그로 인해 현재로 html파일 안에 head -> style 안에 css파일 을 빼지못한 문장들이 280줄 남아있다..
    이 문제는 성장하면서 해결해보도록 하자 !!

개선사항

  1. 백앤드 개발자가 되고 싶지만 Node js 부분도 기본적으로 다룰 줄 알아야한다고 생각한다.
    위의 트러블슈팅 4번 문제를 꼭 해결해보도록하자 !

  2. 멀티스레드를 활용하였지만 동기화문제를 해결할 mutex lock을 사용하지 못 했다.
    공부하여 mutex lock 구현과 안산 한직교 내(정지환)가 올린 게시글을 참고하여
    손기조 전문가 선생님의 자세한 답변을 꼭 구현해내보자 !!!!!

프로젝트를 끝마치고 취업을 준비하는 이 시점까지 느낀 점

처음엔 마냥 쉬웠다.
지금 돌이켜보니 쉬운 것만 배워서 쉽다고 느꼈던 것이다.
파보면 파볼 수록 어려웠고, 모르는 것들, 한 번에 이해되지 않는 것들도 있었다.
하지만 그 순간을 극복하기위해 투자했던 시간들, 투자하고 나서 이해되는 시점들이
지금 내가 개발자가 되고 싶다는 동기부여에 가장 큰 역할을 하고 있는 것 같다.
난 지금도 오류들을 찾아 분석하고, 해결하며 남들에게 도움을 주고 싶고,
편리한 프로그램을 만들거나, 효율적인 백앤드 시스템을 구축해보고싶다.
어렵고 힘든 길일 것이다.
쉬운 건 세상에 존재하지 않으니까.
그럼에도 꺾이지 않고 계속 나아갈 것이다.
느리더라도 전진할 것이다.
중요한 건 꺾이지 않는 마음 이니까

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

댓글 남기기