Add raw socket based port scanner 33/205533/4
authorYu <jiung.yu@samsung.com>
Tue, 7 May 2019 08:14:38 +0000 (17:14 +0900)
committerYu <jiung.yu@samsung.com>
Wed, 8 May 2019 06:05:17 +0000 (15:05 +0900)
Change-Id: I92c3a0203eb96d683ba9f3ac10afbb4fedd7a727
Signed-off-by: Yu Jiung <jiung.yu@samsung.com>
src/inm-port-scan.c

index 18341fcd9f8aeb5d5f29b04510b760969e54c44f..98aeea4995d983f7ac832a07b61f86ad9ed438ae 100644 (file)
@@ -326,6 +326,10 @@ static void __port_manager_shutdown_current_sock(port_manager_s *manager)
        port_handle_s *p_port_handle =
                        __port_manager_get_current_port_handle(manager);
 
+       g_free(manager->p_hdr_buf);
+       manager->p_hdr_buf = NULL;
+       manager->packet_len  = 0;
+
        if (!p_port_handle)
                return;
 
@@ -349,6 +353,9 @@ static void __port_manager_initialize_current_sock(port_manager_s *manager)
        p_port_handle->sock = -1;
        p_port_handle->sock_io_channel = NULL;
        p_port_handle->sock_source_id = 0;
+       g_free(manager->p_hdr_buf);
+       manager->p_hdr_buf = NULL;
+       manager->packet_len  = 0;
 }
 
 static void __port_manager_deinitialize(port_manager_s *manager)
@@ -573,6 +580,86 @@ static int __conn_port_scan_start(port_manager_s *p_port_manager)
        return 0;
 }
 
+
+static gint __create_raw_sock()
+{
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0,};
+       int on = 1;
+       gint sock = -1;
+
+       sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
+       if (sock < 0) {
+               INM_LOGW("socket Failed");
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INM_LOGE("Could not send with %s", error_buf);
+               close(sock);
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (setsockopt(sock, SOL_IP, IP_RECVERR, (char*)&on, sizeof(on)) < 0) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INM_LOGE("setsock ERCVERR errno[%d]: %s", errno, error_buf);
+               close(sock);
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       return sock;
+}
+
+static int __create_raw_port_handle(port_manager_s *p_port_manager)
+{
+       port_handle_s *p_port_handle = NULL;
+       gint sock = -1;
+       int ret;
+
+       __INM_FUNC_ENTER__;
+
+       p_port_handle = __port_manager_get_current_port_handle(p_port_manager);
+       if (!p_port_handle) {
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       sock = __create_raw_sock();
+       if (sock < 0) {
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       ret = inm_util_create_gio_channel(sock, &p_port_handle->sock_io_channel);
+       if (ret != 0) {
+               INM_LOGI("Failed to create gio channel");
+               close(sock);
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       p_port_handle->sock = sock;
+
+       __INM_FUNC_EXIT__;
+       return 0;
+}
+
+int __raw_sock_port_scan_start(port_manager_s *p_port_manager)
+{
+       if (!p_port_manager)
+               return -1;
+
+       __port_manager_initialize_current_sock(p_port_manager);
+
+       if (__create_raw_port_handle(p_port_manager) < 0)
+               return -1;
+
+       return 0;
+}
+
 static inline int __get_target_port(target_manager_s *p_target_manager, port_manager_s *p_port_manager)
 {
        if (!p_target_manager || !p_port_manager)
@@ -652,6 +739,242 @@ static int __conn_port_scan_send(target_manager_s *p_target_manager,
        return 0;
 }
 
+static unsigned short __checksum(unsigned short *buf, int len)
+{
+       int sum = 0;
+       int left = len;
+       u_short  *word = buf;
+       u_short rest = 0;
+       while (left > 1) {
+               sum += *word++;
+               left -= 2;
+       }
+       if (left) {
+               *(u_char *)(&rest) = *(u_char *)word;
+               sum += rest;
+       }
+
+       sum = (sum >> 16) + (sum & 0xffff);
+       sum += (sum >> 16);
+
+       return (unsigned short)(~sum);
+}
+
+static void __set_default_hdr(unsigned char flags,
+               target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager,
+               unsigned char *buf)
+{
+       struct ip *p_ip_hdr;
+       struct tcphdr *p_tcp_hdr;
+       pseudo_hdr_s *p_pseudo_hdr;
+       char dst_ip_addr_str[INET_ADDRSTRLEN] = {0,};
+       struct sockaddr_in *sin;
+
+       __INM_FUNC_ENTER__;
+       if (!buf) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       sin = (struct sockaddr_in *)p_target_manager->p_addr_info_current->ai_addr;
+       inet_ntop(p_target_manager->p_addr_info_current->ai_family,
+                       &sin->sin_addr,
+                       dst_ip_addr_str,
+                       sizeof(dst_ip_addr_str));
+
+       p_ip_hdr = (struct ip*)buf;
+       p_tcp_hdr = (struct tcphdr *)(buf + sizeof(struct ip));
+       p_pseudo_hdr = (pseudo_hdr_s *)((char *)p_tcp_hdr - sizeof(pseudo_hdr_s));
+       p_pseudo_hdr->saddr = inet_addr(p_target_manager->src_addr);
+       p_pseudo_hdr->daddr = inet_addr(dst_ip_addr_str);
+       p_pseudo_hdr->protocol = IPPROTO_TCP;
+       p_pseudo_hdr->tcplength = htons(sizeof(struct tcphdr));
+       memset((char *)p_tcp_hdr, 0, sizeof(struct tcphdr));
+       p_tcp_hdr->th_sport = htons(DEFAULT_SRC_PORT);
+       p_tcp_hdr->th_dport = htons(__get_target_port(p_target_manager, p_port_manager));
+       p_tcp_hdr->th_seq = htons(DEFAULT_SEQ);
+       p_tcp_hdr->th_ack = htons(DEFAULT_ACK_SEQ);
+       p_tcp_hdr->th_off = 5;
+       p_tcp_hdr->th_flags = flags;
+       p_tcp_hdr->window = htons(512);
+       p_tcp_hdr->check = __checksum((unsigned short *)p_pseudo_hdr,
+                       sizeof(pseudo_hdr_s) + sizeof(struct tcphdr));
+       memset((char *)p_ip_hdr, 0, sizeof(struct ip));
+       p_ip_hdr->ip_v = 4;
+       p_ip_hdr->ip_hl = 5;
+       p_ip_hdr->ip_p = IPPROTO_TCP;
+       p_ip_hdr->ip_len = 40;
+       p_ip_hdr->ip_id = htons(777);
+       p_ip_hdr->ip_ttl = 60;
+       inet_aton(p_target_manager->src_addr, &(p_ip_hdr->ip_src));
+       inet_aton(dst_ip_addr_str, &(p_ip_hdr->ip_dst));
+       p_ip_hdr->ip_sum = __checksum((unsigned short *)p_ip_hdr, sizeof(struct ip));
+       __INM_FUNC_EXIT__;
+       return;
+}
+
+static int __create_raw_tcp_pkt(unsigned char flags,
+               target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       unsigned char *buf = NULL;
+       int packet_len;
+
+       __INM_FUNC_ENTER__;
+       if (!p_target_manager || !p_port_manager) {
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       packet_len = sizeof(struct ip) + sizeof(struct tcphdr);
+       buf = g_try_malloc0(packet_len);
+       if (!buf) {
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       __set_default_hdr(flags, p_target_manager, p_port_manager, buf);
+
+       g_free(p_port_manager->p_hdr_buf);
+       p_port_manager->p_hdr_buf = buf;
+       p_port_manager->packet_len = packet_len;
+
+       __INM_FUNC_EXIT__;
+       return 0;
+}
+
+static int __send_raw_tcp_pkt(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       port_handle_s *p_port_handle = NULL;
+       struct sockaddr_in address;
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0,};
+       char dst_ip_addr_str[INET_ADDRSTRLEN] = {0,};
+       struct sockaddr_in *sin;
+       ssize_t nsend;
+
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       p_port_handle = __port_manager_get_current_port_handle(p_port_manager);
+       if (!p_port_handle)
+               return -1;
+
+       sin = (struct sockaddr_in *)p_target_manager->p_addr_info_current->ai_addr;
+       inet_ntop(p_target_manager->p_addr_info_current->ai_family,
+                       &sin->sin_addr,
+                       dst_ip_addr_str,
+                       sizeof(dst_ip_addr_str));
+
+       address.sin_family = AF_INET;
+       address.sin_port = htons(__get_target_port(p_target_manager, p_port_manager));
+       address.sin_addr.s_addr = inet_addr(dst_ip_addr_str);
+
+       nsend = sendto(p_port_handle->sock,
+                       p_port_manager->p_hdr_buf,
+                       p_port_manager->packet_len,
+                       0x0,
+                       (struct sockaddr *)&address,
+                       sizeof(address));
+       if (nsend < 0) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INM_LOGE("Could not send with %s", error_buf);
+       } else
+               INM_LOGI("%zd sent", nsend);
+
+       return 0;
+}
+
+static int __handle_raw_tcp_packet(unsigned char flags,
+               target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       int ret = 0;
+
+       if (!p_port_manager->p_hdr_buf)
+               ret = __create_raw_tcp_pkt(flags, p_target_manager, p_port_manager);
+       if (ret != 0)
+               return -1;
+
+       if (__send_raw_tcp_pkt(p_target_manager, p_port_manager) < 0)
+               return -1;
+
+       return 0;
+}
+
+int __syn_port_scan_send(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       if (__handle_raw_tcp_packet(TH_SYN, p_target_manager, p_port_manager) < 0) {
+               __port_manager_shutdown_current_sock(p_port_manager);
+               return -1;
+       }
+
+       return 0;
+}
+
+int __ack_port_scan_send(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       if (__handle_raw_tcp_packet(TH_ACK, p_target_manager, p_port_manager) < 0) {
+               __port_manager_shutdown_current_sock(p_port_manager);
+               return -1;
+       }
+
+       return 0;
+}
+
+int __fin_port_scan_send(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       if (__handle_raw_tcp_packet(TH_FIN, p_target_manager, p_port_manager) < 0) {
+               __port_manager_shutdown_current_sock(p_port_manager);
+               return -1;
+       }
+
+       return 0;
+}
+
+int __xmas_port_scan_send(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       if (__handle_raw_tcp_packet(TH_FIN | TH_PUSH | TH_URG,
+                       p_target_manager,
+                       p_port_manager) < 0) {
+               __port_manager_shutdown_current_sock(p_port_manager);
+               return -1;
+       }
+
+       return 0;
+}
+
+int __null_port_scan_send(target_manager_s *p_target_manager,
+               port_manager_s *p_port_manager)
+{
+       if (!p_target_manager || !p_port_manager)
+               return -1;
+
+       if (__handle_raw_tcp_packet(0, p_target_manager, p_port_manager) < 0) {
+               __port_manager_shutdown_current_sock(p_port_manager);
+               return -1;
+       }
+
+       return 0;
+}
+
 static void __handle_sock_nval_hup(port_manager_s *p_port_manager, result_manager_s *p_result_manager)
 {
        if (!p_port_manager || !p_result_manager)
@@ -703,6 +1026,87 @@ static void __conn_port_scan_recv(port_scan_received_result *result,
        return;
 }
 
+static void __handle_pkt(port_scan_received_result *result,
+               port_manager_s *p_port_manager,
+               result_manager_s *p_result_manager)
+{
+       if (!p_port_manager || !p_result_manager)
+               return;
+
+       if ((result->tcp_flag & TH_SYN) && (result->tcp_flag & TH_ACK))
+               __result_manager_set_result(p_port_manager->current_port_handle_index,
+                               INM_PORT_SCAN_STATE_OPEN,
+                               p_result_manager);
+       else if (result->tcp_flag & TH_RST)
+               __result_manager_set_result(p_port_manager->current_port_handle_index,
+                               INM_PORT_SCAN_STATE_CLOSE,
+                               p_result_manager);
+
+       return;
+}
+
+static void __handle_local_err(port_manager_s *p_port_manager, result_manager_s *p_result_manager)
+{
+       if (!p_port_manager || !p_result_manager)
+               return;
+
+       __result_manager_set_result(p_port_manager->current_port_handle_index,
+                       INM_PORT_SCAN_STATE_NO_RESPONSE,
+                       p_result_manager);
+
+       return;
+}
+
+static void __handle_icmp_err(port_manager_s *p_port_manager, result_manager_s *p_result_manager)
+{
+       if (!p_port_manager || !p_result_manager)
+               return;
+
+       __result_manager_set_result(p_port_manager->current_port_handle_index,
+                       INM_PORT_SCAN_STATE_NO_RESPONSE,
+                       p_result_manager);
+
+       return;
+}
+
+static void __handle_max_retries(port_manager_s *p_port_manager, result_manager_s *p_result_manager)
+{
+       if (!p_port_manager || !p_result_manager)
+               return;
+
+       __result_manager_set_result(p_port_manager->current_port_handle_index,
+                       INM_PORT_SCAN_STATE_NO_RESPONSE,
+                       p_result_manager);
+
+       return;
+}
+
+static void __port_scan_raw_sock_recv(port_scan_received_result *result,
+               port_manager_s *p_port_manager,
+               result_manager_s *p_result_manager)
+{
+       __INM_FUNC_ENTER__;
+
+       if (!result || !p_port_manager || !p_result_manager) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       if (result->type == PORT_SCAN_RECEIVE_TYPE_PKT)
+               __handle_pkt(result, p_port_manager, p_result_manager);
+       else if (result->type == PORT_SCAN_RECEIVE_TYPE_LOCAL_ERROR)
+               __handle_local_err(p_port_manager, p_result_manager);
+       else if (result->type == PORT_SCAN_RECEIVE_TYPE_ICMP_ERROR)
+               __handle_icmp_err(p_port_manager, p_result_manager);
+       else if (result->type == PORT_SCAN_RECEIVE_TYPE_SOCK_HUP_NVAL)
+               __handle_sock_nval_hup(p_port_manager, p_result_manager);
+       else if (result->type == PORT_SCAN_RECEIVE_TYPE_MAX_RETRIES)
+               __handle_max_retries(p_port_manager, p_result_manager);
+
+       __INM_FUNC_EXIT__;
+       return;
+}
+
 static int __port_scan_stop(port_manager_s *p_port_manager)
 {
        if (!p_port_manager)
@@ -715,21 +1119,61 @@ static int __port_scan_stop(port_manager_s *p_port_manager)
 static port_scan_start scan_start_funcs[] = {
                [INM_PORT_SCAN_TYPE_CONN]
                 = __conn_port_scan_start,
+               [INM_PORT_SCAN_TYPE_SYN]
+                = __raw_sock_port_scan_start,
+               [INM_PORT_SCAN_TYPE_ACK]
+                = __raw_sock_port_scan_start,
+               [INM_PORT_SCAN_TYPE_FIN]
+                = __raw_sock_port_scan_start,
+               [INM_PORT_SCAN_TYPE_XMAS]
+                = __raw_sock_port_scan_start,
+               [INM_PORT_SCAN_TYPE_NULL]
+                = __raw_sock_port_scan_start,
 };
 
 static port_scan_send scan_send_funcs[] = {
                [INM_PORT_SCAN_TYPE_CONN]
                 = __conn_port_scan_send,
+               [INM_PORT_SCAN_TYPE_SYN]
+                = __syn_port_scan_send,
+               [INM_PORT_SCAN_TYPE_ACK]
+                = __ack_port_scan_send,
+               [INM_PORT_SCAN_TYPE_FIN]
+                = __fin_port_scan_send,
+               [INM_PORT_SCAN_TYPE_XMAS]
+                = __xmas_port_scan_send,
+               [INM_PORT_SCAN_TYPE_NULL]
+                = __null_port_scan_send,
 };
 
 static port_scan_recv scan_recv_funcs[] = {
                [INM_PORT_SCAN_TYPE_CONN]
                 = __conn_port_scan_recv,
+               [INM_PORT_SCAN_TYPE_SYN]
+                = __port_scan_raw_sock_recv,
+               [INM_PORT_SCAN_TYPE_ACK]
+                = __port_scan_raw_sock_recv,
+               [INM_PORT_SCAN_TYPE_FIN]
+                = __port_scan_raw_sock_recv,
+               [INM_PORT_SCAN_TYPE_XMAS]
+                = __port_scan_raw_sock_recv,
+               [INM_PORT_SCAN_TYPE_NULL]
+                = __port_scan_raw_sock_recv,
 };
 
 static port_scan_stop scan_stop_funcs[] = {
                [INM_PORT_SCAN_TYPE_CONN]
                 = __port_scan_stop,
+               [INM_PORT_SCAN_TYPE_SYN]
+                = __port_scan_stop,
+               [INM_PORT_SCAN_TYPE_ACK]
+                = __port_scan_stop,
+               [INM_PORT_SCAN_TYPE_FIN]
+                = __port_scan_stop,
+               [INM_PORT_SCAN_TYPE_XMAS]
+                = __port_scan_stop,
+               [INM_PORT_SCAN_TYPE_NULL]
+                = __port_scan_stop,
 };
 
 static char *__print_port_state(inm_port_scan_state_e state)
@@ -963,6 +1407,261 @@ gboolean __scanner_receive_event_from_tcp_sock(GIOChannel *source,
        return FALSE;
 }
 
+static void __debug_received_tcp_packet(struct tcphdr *p_tcp_header)
+{
+       INM_LOGI("Window Size : %d", p_tcp_header->window);
+       INM_LOGI("Flags : ");
+       if (p_tcp_header->th_flags & TH_FIN)
+               INM_LOGI("[FIN]");
+       if (p_tcp_header->th_flags & TH_SYN)
+               INM_LOGI("[SYN]");
+       if (p_tcp_header->th_flags & TH_RST)
+               INM_LOGI("[RST]");
+       if (p_tcp_header->th_flags & TH_PUSH)
+               INM_LOGI("[PSH]");
+       if (p_tcp_header->th_flags & TH_ACK)
+               INM_LOGI("[ACK]");
+       if (p_tcp_header->th_flags & TH_URG)
+               INM_LOGI("[URG]");
+}
+
+static int __read_channel(GIOChannel *source, unsigned char *tcp_flags)
+{
+       gchar buf[4096] = {0, };
+       gsize bytes_read = 0;
+       GError *error = NULL;
+
+       INM_LOGI("Read channel");
+       if (g_io_channel_read_chars(source, buf, sizeof(buf),
+                               &bytes_read, &error) != G_IO_STATUS_NORMAL) {
+               INM_LOGE("Failure received tcp packet[%d]:[%s]",
+                               error->code, error->message);
+               g_error_free(error);
+               return -1;
+       }
+
+       /* handle received packet for proper type */
+       INM_LOGI("%" G_GSIZE_FORMAT " bytes read", bytes_read);
+       struct ip *p_ip_hdr = (struct ip *)buf;
+       if (p_ip_hdr->ip_p != IPPROTO_TCP) {
+               INM_LOGI("Protocol type is not TCP %d", p_ip_hdr->ip_p);
+               return -1;
+       }
+       INM_LOGI("IP Version : %d", p_ip_hdr->ip_v);
+       INM_LOGI("Time To Live : %d", p_ip_hdr->ip_ttl);
+
+       struct tcphdr *p_tcp_header = (struct tcphdr *)(buf + sizeof(struct ip));
+       __debug_received_tcp_packet(p_tcp_header);
+       *tcp_flags = p_tcp_header->th_flags;
+
+       return 0;
+}
+
+static void __scanner_raw_sock_io_in(GIOChannel *source, port_scan_data_s *p_port_scan)
+{
+       port_scan_received_result result = {0, };
+       unsigned char tcp_flags = 0;
+       __INM_FUNC_ENTER__;
+
+       if (!p_port_scan) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       if (__read_channel(source, &tcp_flags) != 0) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       result.type = PORT_SCAN_RECEIVE_TYPE_PKT;
+       result.tcp_flag = tcp_flags;
+       scan_recv_funcs[p_port_scan->type](&result,
+                       &(p_port_scan->port_manager),
+                       &(p_port_scan->result_manager));
+
+       return;
+}
+
+static void __handle_icmp_cmsg(struct sock_extended_err *sock_err,
+               port_scan_received_result *result)
+{
+       if (!sock_err || !result)
+               return;
+
+       INM_LOGI("We got ICMP message %d", sock_err->ee_errno);
+       INM_LOGI("We got ICMP type %d", sock_err->ee_type);
+       INM_LOGI("We got ICMP code %d", sock_err->ee_code);
+       result->type = PORT_SCAN_RECEIVE_TYPE_ICMP_ERROR;
+       result->icmp_type = sock_err->ee_type;
+       result->icmp_code = sock_err->ee_code;
+}
+
+static inline void __handle_local_cmsg(struct sock_extended_err *sock_err,
+               port_scan_received_result *result)
+{
+       if (!sock_err || !result)
+               return;
+
+       INM_LOGI("We got local message %d", sock_err->ee_errno);
+       /* Handle MTU error only */
+       if (sock_err->ee_errno == EMSGSIZE)
+               INM_LOGI("mtu %d", sock_err->ee_info);
+
+       result->type = PORT_SCAN_RECEIVE_TYPE_LOCAL_ERROR;
+       result->local_error = sock_err->ee_errno;
+}
+
+static int __handle_ip_recv_err(struct cmsghdr *cmsg,
+               struct sockaddr_in *p_remote_addr,
+               port_scan_received_result *result)
+{
+       struct sock_extended_err *sock_err;
+       struct sockaddr_in *addr_in;
+       struct sockaddr *addr;
+
+       if (!cmsg || !p_remote_addr || !result)
+               return -1;
+
+       INM_LOGI("We got IP_RECVERR message");
+
+       sock_err = (struct sock_extended_err*)CMSG_DATA(cmsg);
+       if (!sock_err)
+               return -1;
+
+       addr = SO_EE_OFFENDER(sock_err);
+       addr_in = (struct sockaddr_in *)addr;
+       if (addr->sa_family == AF_INET)
+               INM_LOGI("received from %s %d", inet_ntoa(addr_in->sin_addr), p_remote_addr->sin_port);
+       if (sock_err->ee_origin == SO_EE_ORIGIN_ICMP)
+               __handle_icmp_cmsg(sock_err, result);
+       else if (sock_err->ee_origin == SO_EE_ORIGIN_LOCAL)
+               __handle_local_cmsg(sock_err, result);
+
+       return 0;
+}
+
+static int __handle_cmsg(struct msghdr *msg,
+               struct sockaddr_in *p_remote_addr,
+               port_scan_received_result *result)
+{
+       struct cmsghdr *cmsg;
+
+       if (!msg)
+               return -1;
+
+       for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               /* Received IP layer error */
+               if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVERR)
+                       return __handle_ip_recv_err(cmsg, p_remote_addr, result);
+       }
+
+       return -1;
+}
+
+static int __recv_sock_msg_err_queue(int sock, port_scan_received_result *result)
+{
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0,};
+       char buffer[1500];
+       struct icmphdr icmph;
+       struct sockaddr_in remote;
+       struct iovec  iov;
+       struct msghdr msg;
+       int res = 0;
+
+       if (sock <= 0 || !result)
+               return -1;
+
+       iov.iov_base = &icmph;
+       iov.iov_len = sizeof(icmph);
+       msg.msg_name = (void *)&remote;
+       msg.msg_namelen = sizeof(remote);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_flags = 0;
+       msg.msg_control = buffer;
+       msg.msg_controllen = sizeof(buffer);
+
+       res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+       INM_LOGI("%d recvmsg received", res);
+       if (res < 0) {
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+               INM_LOGE("recvmsg errno[%d]: %s", errno, error_buf);
+               __INM_FUNC_EXIT__;
+               return -1;
+       }
+
+       return __handle_cmsg(&msg, &remote, result);
+}
+
+static void __scanner_raw_sock_io_err(port_scan_data_s *p_port_scan)
+{
+       port_handle_s *p_port_handle = NULL;
+       port_scan_received_result result = {0, };
+
+       __INM_FUNC_ENTER__;
+       if (!p_port_scan) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       p_port_handle = __port_manager_get_current_port_handle(&(p_port_scan->port_manager));
+       if (!p_port_handle) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       if (__recv_sock_msg_err_queue(p_port_handle->sock, &result) != 0) {
+               __INM_FUNC_EXIT__;
+               return;
+       }
+
+       scan_recv_funcs[p_port_scan->type](&result,
+                       &(p_port_scan->port_manager),
+                       &(p_port_scan->result_manager));
+
+       __INM_FUNC_EXIT__;
+       return;
+}
+static inline void __scanner_raw_sock_hup_nval(port_scan_data_s *p_port_scan)
+{
+       port_scan_received_result result = {0, };
+       if (!p_port_scan)
+               return;
+
+       INM_LOGE("sock HUP or NVAL");
+       result.type = PORT_SCAN_RECEIVE_TYPE_SOCK_HUP_NVAL;
+       scan_recv_funcs[g_port_scan->type](&result,
+                       &(p_port_scan->port_manager),
+                       &(p_port_scan->result_manager));
+}
+
+gboolean __scanner_receive_event_from_raw_sock(GIOChannel *source,
+                 GIOCondition condition,
+                 gpointer data)
+{
+       port_scan_data_s *p_port_scan_data = NULL;
+       __INM_FUNC_ENTER__;
+
+       p_port_scan_data = data;
+       if (!p_port_scan_data) {
+               INM_LOGI("Invalid data");
+               return FALSE;
+       }
+
+       if (condition == G_IO_IN)
+               __scanner_raw_sock_io_in(source, p_port_scan_data);
+       else if (condition & G_IO_ERR)
+               __scanner_raw_sock_io_err(p_port_scan_data);
+       else if (condition & (G_IO_HUP | G_IO_NVAL))
+               __scanner_raw_sock_hup_nval(p_port_scan_data);
+       else
+               INM_LOGE("unrecognized condition %d", condition);
+
+       __scanner_next_port(p_port_scan_data);
+       __INM_FUNC_EXIT__;
+       return FALSE;
+}
+
 static void __scanner_attach_source(port_scan_data_s *p_port_scan)
 {
        port_manager_s *p_port_manager = NULL;
@@ -973,19 +1672,78 @@ static void __scanner_attach_source(port_scan_data_s *p_port_scan)
        if (!p_port_handle)
                return;
 
-       p_port_handle->sock_source_id =
-                       g_io_add_watch(p_port_handle->sock_io_channel,
-                                       G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                       __scanner_receive_event_from_tcp_sock,
-                                       p_port_scan);
+
+       if (p_port_scan->type == INM_PORT_SCAN_TYPE_CONN)
+               p_port_handle->sock_source_id =
+                               g_io_add_watch(p_port_handle->sock_io_channel,
+                                               G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                               __scanner_receive_event_from_tcp_sock,
+                                               p_port_scan);
+       else
+               p_port_handle->sock_source_id =
+                               g_io_add_watch(p_port_handle->sock_io_channel,
+                                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                               __scanner_receive_event_from_raw_sock,
+                                               p_port_scan);
 
        INM_LOGI("socket %d source_id %d", p_port_handle->sock, p_port_handle->sock_source_id);
+}
+
+static void __reach_max_retries(port_scan_data_s *p_port_scan)
+{
+       port_scan_received_result result = {0, };
+       if (!p_port_scan)
+               return;
+
+       INM_LOGI("Max retries");
+       result.type = PORT_SCAN_RECEIVE_TYPE_MAX_RETRIES;
+       scan_recv_funcs[p_port_scan->type](&result,
+                       &(p_port_scan->port_manager),
+                       &(p_port_scan->result_manager));
 
+       return;
+}
+
+static void __retry_port_scan(port_scan_data_s *p_port_scan)
+{
+       if (!p_port_scan)
+               return;
+
+       scan_send_funcs[p_port_scan->type](
+                       &(p_port_scan->target_manager),
+                       &(p_port_scan->port_manager));
+       return;
+}
+
+static gboolean __scanner_retry_port_scan(gpointer user_data)
+{
+       port_scan_data_s *p_port_scan;
+       port_handle_s *p_port_handle = NULL;
+
+       p_port_scan = (port_scan_data_s *)user_data;
+       if (!p_port_scan)
+               return FALSE;
+
+       p_port_handle = __port_manager_get_current_port_handle(&(p_port_scan->port_manager));
+       if (!p_port_handle)
+               return FALSE;
+
+       p_port_handle->retries++;
+       if (p_port_handle->retries >= DEFAULT_MAX_RETRIES) {
+               __reach_max_retries(p_port_scan);
+               __scanner_next_port(p_port_scan);
+               return FALSE;
+       } else {
+               __retry_port_scan(p_port_scan);
+       }
+
+       return TRUE;
 }
 
 static int __scanner_scan_start(port_scan_data_s *p_port_scan)
 {
        port_manager_s *p_port_manager = NULL;
+       port_handle_s *p_port_handle = NULL;
 
        if (!p_port_scan)
                return -1;
@@ -1003,6 +1761,14 @@ static int __scanner_scan_start(port_scan_data_s *p_port_scan)
                return -1;
        }
 
+       if (p_port_scan->type != INM_PORT_SCAN_TYPE_CONN) {
+               p_port_handle = __port_manager_get_current_port_handle(p_port_manager);
+               p_port_handle->retry_timer_source_id =
+                               g_timeout_add(DEFAULT_RETRY_TIMEOUT_MS,
+                                               __scanner_retry_port_scan,
+                                               p_port_scan);
+       }
+
        return 0;
 }