대문 / 공개프로젝트 / HWPORT stealth portscan

HWPORT stealth portscan

  • 개발자
    조재혁(Mminzkn@minzkn.com)

  • 기록사항
    2010년 8월 18일 : 예전에 작성했던 테스트용 소스 정리해서 공개


개요

이것은 TCP의 연결과정에서 SYN->ACK에 대한 부분만을 구현하여 열려진 port를 확인하는 Stealth port scan util입니다. 막상 테스트용 소스를 정리하고 다듬어보니 기대이상으로 꽤 빠른 scan동작을 하게 되었습니다.

프로젝트 정보

사용법

만약 자신의 IP주소가 192.168.0.100이고 portscan 대상이 google.com이며 port범위는 1~1024인 경우 다음과 같이 실행합니다.
./hwport_portscan 192.168.0.100 google.com 1 1024
중요한것은 자신의 IP를 portscan대상으로부터 SYN/ACK신로를 응답받을 주소로 정확히 사용해야 한다는 점입니다.

완료된 기능

  • 기본적인 TCP stealth port scan 기능 (SYN->ACK)

개발중인 기능


언젠가는 추가하고자 하는 기능


참고기술자료

소스내용

/*
    Copyright (C) HWPORT.COM.
    All rights reserved.
    Author: JAEHYUK CHO <mailto:minzkn@minzkn.com>
*/

#if !defined(_ISOC99_SOURCE)
# define _ISOC99_SOURCE (1L)
#endif

#if !defined(_GNU_SOURCE)
# define _GNU_SOURCE (1L)
#endif

/* ---- */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <memory.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <dirent.h>

#include <netinet/in.h>

#define def_hwport_portscan_timeout (4000)

typedef unsigned long long __hwport_portscan_time_stamp_t;
#define hwport_portscan_time_stamp_t __hwport_portscan_time_stamp_t

typedef struct hwport_portscan_timer_ts {
    /* need shadow */
    long m_clock_tick;
    clock_t m_prev_clock;
    hwport_portscan_time_stamp_t m_time_stamp;

    /* timer stat */
    hwport_portscan_time_stamp_t m_start_time_stamp;
    hwport_portscan_time_stamp_t m_timeout;
    hwport_portscan_time_stamp_t m_duration;
}__hwport_portscan_timer_t;
#define hwport_portscan_timer_t __hwport_portscan_timer_t

typedef struct hwport_portscan_info_ts {
    const char *m_hostname;
    const char *m_peername;
   
    uint8_t m_try_table[ 65536 / 8 ]; 
    uint8_t m_syn_table[ 65536 / 8 ]; 
    uint8_t m_ack_table[ 65536 / 8 ]; 
    uint8_t m_open_table[ 65536 / 8 ]; 

    int m_timeout_msec;
}__hwport_portscan_info_t;
#define hwport_portscan_info_t __hwport_portscan_info_t

typedef struct hwport_portscan_pseudo_header_ts {
    uint32_t m_srcaddr;
    uint32_t m_dstaddr;
    uint8_t m_unused;
    uint8_t m_protocol;
    uint16_t m_length;
}__hwport_portscan_pseudo_header_t;
#define hwport_portscan_pseudo_header_t __hwport_portscan_pseudo_header_t

static void usage(const char *s_name);

static hwport_portscan_time_stamp_t hwport_portscan_time_stamp(hwport_portscan_timer_t *s_timer);
static void hwport_portscan_timer_init(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout);
static void hwport_portscan_timer_set(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout);
#if 0L
static void hwport_portscan_timer_update(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout);
#endif
static int hwport_portscan_timer_check(hwport_portscan_timer_t *s_timer);

static unsigned int hwport_portscan_checksum(const void *s_data, size_t s_size);
static hwport_portscan_info_t *hwport_portscan_info_init(hwport_portscan_info_t *s_info);
static __inline void hwport_portscan_set_mask(void *s_table, int s_port);
static __inline int hwport_portscan_get_mask(const void *s_table, int s_port);
static int hwport_portscan(hwport_portscan_info_t *s_info);

int main(int s_argc, char **s_argv);

static void usage(const char *s_name)
{
    (void)fprintf(stdout, "usage: %s <hostname> <peername> [<start port> [<end port>]]\n", s_name);
}

static hwport_portscan_time_stamp_t hwport_portscan_time_stamp(hwport_portscan_timer_t *s_timer)
{
    clock_t s_clock;

#if defined(__linux__)
    /* get linux kernel's jiffes (tick counter) */
    s_clock = times((struct tms *)0);
#else
    do {
        struct tms s_tms;
        s_clock = times((struct tms *)(&s_tms));
    }while(0);
#endif    
    
    if(s_clock == ((clock_t)(-1))) {
        /* overflow clock timing */
        return(s_timer->m_time_stamp);
    }

    if(s_timer->m_clock_tick <= 0l) {
        /* get ticks per second */ 
        s_timer->m_clock_tick = sysconf(_SC_CLK_TCK);
        if(s_timer->m_clock_tick <= 0l) {
            /* invalid clock tick */
            return(s_timer->m_time_stamp);
        }
        
        s_timer->m_prev_clock = s_clock;
    }

    /* update time stamp (clock to upscale) */
    s_timer->m_time_stamp += (((hwport_portscan_time_stamp_t)(s_clock - s_timer->m_prev_clock)) * ((hwport_portscan_time_stamp_t)1000u)) / ((hwport_portscan_time_stamp_t)s_timer->m_clock_tick);
    s_timer->m_prev_clock = s_clock;

    return(s_timer->m_time_stamp);
}

static void hwport_portscan_timer_init(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout)
{
    /* shadow part */
    s_timer->m_clock_tick = 0l;
    s_timer->m_prev_clock = (clock_t)0;
    s_timer->m_time_stamp = (hwport_portscan_time_stamp_t)1000u;

    /* timer stat part */
    hwport_portscan_timer_set(s_timer, s_timeout); 
}

static void hwport_portscan_timer_set(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout)
{
    s_timer->m_start_time_stamp = hwport_portscan_time_stamp(s_timer);
    s_timer->m_timeout = s_timeout;
    s_timer->m_duration = (hwport_portscan_time_stamp_t)0u;
}

#if 0L
static void hwport_portscan_timer_update(hwport_portscan_timer_t *s_timer, hwport_portscan_time_stamp_t s_timeout)
{
    /* increment timeout */
    s_timer->m_timeout += s_timeout;
}
#endif

static int hwport_portscan_timer_check(hwport_portscan_timer_t *s_timer)
{
    s_timer->m_duration = hwport_portscan_time_stamp(s_timer) - s_timer->m_start_time_stamp; 

    return((s_timer->m_duration >= s_timer->m_timeout) ? 1 : 0);
}

static unsigned int hwport_portscan_checksum(const void *s_data, size_t s_size)
{
    register unsigned int s_result = 0u;

    while(s_size > ((size_t)1)) {
        s_result += (unsigned int)(*((const unsigned short int *)s_data));
        s_data = ((const unsigned short int *)s_data) + ((size_t)1);
        s_size -= (size_t)2;
    }
   
    if(s_size > ((size_t)0)) {
        s_result += (unsigned int)(*((const unsigned char *)s_data));
    }

    s_result = (s_result >> 16) + (s_result & 0xffffu);
    s_result += s_result >> 16;

    return((~s_result) & 0xffffu);
}

static hwport_portscan_info_t *hwport_portscan_info_init(hwport_portscan_info_t *s_info)
{
    s_info->m_hostname = (const char *)0;
    s_info->m_peername = (const char *)0;

    s_info->m_timeout_msec = def_hwport_portscan_timeout;

    (void)memset((void *)(&s_info->m_try_table[0]), 0, sizeof(s_info->m_try_table));
    (void)memset((void *)(&s_info->m_syn_table[0]), 0, sizeof(s_info->m_syn_table));
    (void)memset((void *)(&s_info->m_ack_table[0]), 0, sizeof(s_info->m_ack_table));
    (void)memset((void *)(&s_info->m_open_table[0]), 0, sizeof(s_info->m_open_table));

    return(s_info);
}

static __inline void hwport_portscan_set_mask(void *s_table, int s_port)
{
    uint8_t *s_table8 = (uint8_t *)s_table;

    s_table8[s_port >> 3] |= (uint8_t)(1u << (s_port & 0x07));
}

static __inline int hwport_portscan_get_mask(const void *s_table, int s_port)
{
    const uint8_t *s_table8 = (const uint8_t *)s_table;

    return(((s_table8[s_port >> 3] & ((uint8_t)(1u << (s_port & 0x07)))) == ((uint8_t)0)) ? 0 : 1);
}

static int hwport_portscan(hwport_portscan_info_t *s_info)
{
    int s_result = (-1);
    
    struct hostent *s_hostent;
    struct in_addr s_hostaddr;
    struct in_addr s_peeraddr;

    int s_socket, s_tcp_socket;
    static int s_on = 1;
    int s_bind_port;

    struct iphdr s_ip_header;
    hwport_portscan_pseudo_header_t s_pseudo_header;
    struct tcphdr s_tcp_header;

    int s_current_port;

    size_t s_buffer_size;
    uint8_t *s_buffer;
    struct iphdr *s_ip_header_ptr;
    hwport_portscan_pseudo_header_t *s_pseudo_header_ptr;
    struct tcphdr *s_tcp_header_ptr;

    struct sockaddr_in s_sockaddr_in;
    socklen_t s_socklen;
    ssize_t s_send_bytes;

    hwport_portscan_timer_t s_timer;

    struct timeval s_timeval;
    fd_set s_fd_set_rx;
    fd_set s_fd_set_tx;
    int s_select_check;
    int s_need_more_rx_check; /* socket buffer to prevention overflowing */
            
    ssize_t s_recv_bytes;

    /* resolv host */
    s_hostent = gethostbyname(s_info->m_hostname);
    if(s_hostent == ((struct hostent *)0)) {
        return(-1);
    }
    s_hostaddr = *((struct in_addr *)(s_hostent->h_addr));
    
    /* resolv peer */
    s_hostent = gethostbyname(s_info->m_peername);
    if(s_hostent == ((struct hostent *)0)) {
        goto l_return;
    }
    s_peeraddr = *((struct in_addr *)(s_hostent->h_addr));

    /* open raw socket */
    s_socket = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s_socket == (-1)) {
        perror("socket");
        goto l_return;
    }
  
    /* open tcp socket for bind port */
    s_tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(s_tcp_socket == (-1)) {
        perror("tcp socket");
        goto l_close_with_return;
    }

    /* include IP header to recv packet */
    if(setsockopt(s_socket, IPPROTO_IP, IP_HDRINCL, &s_on, sizeof(s_on)) == (-1)) {
        perror("setsockopt");
        goto l_close_with_return;
    }

    /* bind tcp socket */
    (void)memset((void *)(&s_sockaddr_in), 0, sizeof(s_sockaddr_in));
    s_sockaddr_in.sin_family = AF_INET;
    s_sockaddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
    s_sockaddr_in.sin_port = htons(0);
    s_socklen = (socklen_t)sizeof(s_sockaddr_in);
    if(bind(s_tcp_socket, (struct sockaddr *)(&s_sockaddr_in), s_socklen) == (-1)) {
        perror("bind");
        goto l_close_with_return;
    }
    if(getsockname(s_tcp_socket, (struct sockaddr *)(&s_sockaddr_in), (socklen_t *)(&s_socklen)) == (-1)) {
        perror("getsockname");
        goto l_close_with_return;
    }
    s_bind_port = (int)ntohs(s_sockaddr_in.sin_port);

    /* build default header */
    (void)memset((void *)(&s_ip_header), 0, sizeof(s_ip_header));
    (void)memset((void *)(&s_pseudo_header), 0, sizeof(s_pseudo_header));
    (void)memset((void *)(&s_tcp_header), 0, sizeof(s_tcp_header));
   
    s_ip_header.ihl = sizeof(s_ip_header) >> 2;
    s_ip_header.version = 4;
    s_ip_header.tos = 0;
    s_ip_header.tot_len = htons(sizeof(s_ip_header) + sizeof(s_tcp_header));
    s_ip_header.id = htons(0);
    s_ip_header.frag_off = 0;
    s_ip_header.ttl = IPDEFTTL;
    s_ip_header.protocol = IPPROTO_TCP;
    s_ip_header.check = hwport_portscan_checksum((void *)(&s_ip_header), sizeof(s_ip_header));
    s_ip_header.saddr = s_hostaddr.s_addr;
    s_ip_header.daddr = s_peeraddr.s_addr;
   
    s_pseudo_header.m_srcaddr = s_ip_header.saddr;
    s_pseudo_header.m_dstaddr = s_ip_header.daddr;
    s_pseudo_header.m_unused = 0;
    s_pseudo_header.m_protocol = s_ip_header.protocol;
    s_pseudo_header.m_length = htons(sizeof(s_tcp_header));

    s_tcp_header.source = htons(s_bind_port);
    s_tcp_header.dest = htons(0);
    s_tcp_header.seq = htonl(random());
    s_tcp_header.ack_seq = htonl(0);
    s_tcp_header.doff = 5;
    s_tcp_header.res1 = 0;
    s_tcp_header.fin = 0;
    s_tcp_header.syn = 1;
    s_tcp_header.rst = 0;
    s_tcp_header.psh = 0;
    s_tcp_header.ack = 0;
    s_tcp_header.urg = 0;
    s_tcp_header.window = htons(65535);
    s_tcp_header.check = htons(0);

    /* build for sendto sockaddr_in */
    (void)memset((void *)(&s_sockaddr_in), 0, sizeof(s_sockaddr_in));
    s_sockaddr_in.sin_family = AF_INET;
    s_sockaddr_in.sin_addr = s_peeraddr;
    s_sockaddr_in.sin_port = htons(0);
    s_socklen = (socklen_t)sizeof(s_sockaddr_in);

    s_buffer_size = (size_t)(4 << 10);
    s_buffer = (uint8_t *)malloc(s_buffer_size);
    if(s_buffer == ((uint8_t *)0)) {
        goto l_close_with_return;
    }

    s_need_more_rx_check = 0;
    s_current_port = 0;
    FD_ZERO(&s_fd_set_rx);
    FD_ZERO(&s_fd_set_tx);
    hwport_portscan_timer_init((hwport_portscan_timer_t *)(&s_timer), (hwport_portscan_time_stamp_t)s_info->m_timeout_msec);
    do {
	if(s_current_port != (-1)) {
            while(s_current_port <= ((int)(sizeof(s_info->m_try_table) * 8))) {
                if(hwport_portscan_get_mask((const void *)(&s_info->m_try_table[0]), s_current_port) != 0) {
                    break;
                }
        	++s_current_port;
            }
            if(s_current_port >= ((int)(sizeof(s_info->m_try_table) * 8))) {
        	s_current_port = (-1);
            }
	}
        
	if((s_current_port == (-1)) && (memcmp((const void *)(&s_info->m_syn_table[0]), (const void *)(&s_info->m_ack_table[0]), sizeof(s_info->m_try_table)) == 0)) {
            /* all checked & all try port opened */
            break;
        }
        
	if((s_need_more_rx_check == 0) && (s_timer.m_duration <= ((hwport_portscan_time_stamp_t)s_info->m_timeout_msec))) {
            hwport_portscan_time_stamp_t s_timeout_msec;
            
            s_timeout_msec = ((hwport_portscan_time_stamp_t)s_info->m_timeout_msec) - s_timer.m_duration;
            s_timeval.tv_sec = s_timeout_msec / 1000;
            s_timeval.tv_usec = (s_timeout_msec % 1000) * 1000;
        }
        else {
            s_timeval.tv_sec = 0;
            s_timeval.tv_usec = 0;
        }

        FD_SET(s_socket, &s_fd_set_rx);
        if((s_need_more_rx_check == 0) && (s_current_port != (-1))) {
            FD_SET(s_socket, &s_fd_set_tx);
        }
	s_need_more_rx_check = 0;
	
	s_select_check = select(s_socket + 1, (fd_set *)(&s_fd_set_rx), (fd_set *)(&s_fd_set_tx), (fd_set *)0, (struct timeval *)(&s_timeval));
        if(s_select_check == (-1)) {
            perror("select");
            break;
        }

        if(s_select_check == 0) { /* timeout */
            continue;
        }

        if((s_select_check > 0) && (FD_ISSET(s_socket, &s_fd_set_tx) != 0)) {
	    --s_select_check;
            FD_CLR(s_socket, &s_fd_set_tx);
        
            /* make packet */
            s_pseudo_header_ptr = (hwport_portscan_pseudo_header_t *)memcpy((void *)(&s_buffer[sizeof(s_ip_header) - sizeof(hwport_portscan_pseudo_header_t)]), (const void *)(&s_pseudo_header), sizeof(s_pseudo_header));
            s_tcp_header_ptr = (struct tcphdr *)memcpy((void *)(&s_buffer[sizeof(s_ip_header)]), (const void *)(&s_tcp_header), sizeof(s_tcp_header));

            s_tcp_header_ptr->dest = htons(s_current_port);
            s_tcp_header_ptr->check = hwport_portscan_checksum((void *)s_pseudo_header_ptr, sizeof(s_pseudo_header) + sizeof(s_tcp_header));
        
            s_ip_header_ptr = (struct iphdr *)memcpy((void *)(&s_buffer[0]), (const void *)(&s_ip_header), sizeof(s_ip_header));

            s_sockaddr_in.sin_port = s_tcp_header_ptr->dest;
            s_send_bytes = sendto(s_socket, (const void *)(&s_buffer[0]), sizeof(s_ip_header) + sizeof(s_tcp_header), MSG_NOSIGNAL, (struct sockaddr *)(&s_sockaddr_in), s_socklen);
            if(s_send_bytes > ((ssize_t)0)) {
                hwport_portscan_set_mask((void *)(&s_info->m_syn_table[0]), s_current_port);
	    }

	    ++s_current_port;
    
            /* reset timer */
            hwport_portscan_timer_set((hwport_portscan_timer_t *)(&s_timer), (hwport_portscan_time_stamp_t)s_info->m_timeout_msec);
	}

        if((s_select_check > 0) && (FD_ISSET(s_socket, &s_fd_set_rx) != 0)) {
            --s_select_check;
            FD_CLR(s_socket, &s_fd_set_rx);

	    s_socklen = (socklen_t)sizeof(s_sockaddr_in);
            s_recv_bytes = recvfrom(s_socket, (void *)(&s_buffer[0]), s_buffer_size, MSG_NOSIGNAL, (struct sockaddr *)(&s_sockaddr_in), (socklen_t *)(&s_socklen));
            if(s_recv_bytes > ((ssize_t)0)) {
                int s_this_port;

                if(((size_t)s_recv_bytes) < s_buffer_size) {
                    (void)memset((void *)(&s_buffer[s_recv_bytes]), 0, s_buffer_size - ((size_t)s_recv_bytes));
                }

                s_ip_header_ptr = (struct iphdr *)(&s_buffer[0]);
                s_tcp_header_ptr = (struct tcphdr *)(&s_buffer[s_ip_header_ptr->ihl << 2]);

                s_this_port = (int)ntohs(s_tcp_header_ptr->source);
	    
                if((s_ip_header_ptr->saddr == s_peeraddr.s_addr) &&
                   (s_ip_header_ptr->daddr == s_hostaddr.s_addr) &&
                   (s_bind_port == ((int)ntohs(s_tcp_header_ptr->dest))) &&
                   (hwport_portscan_get_mask((const void *)(&s_info->m_syn_table[0]), s_this_port) != 0)
                ) { /* filtering my event only */
                    hwport_portscan_set_mask((void *)(&s_info->m_ack_table[0]), s_this_port);
                    if((s_tcp_header_ptr->syn != 0) && (s_tcp_header_ptr->ack != 0)) {
                        hwport_portscan_set_mask((void *)(&s_info->m_open_table[0]), s_this_port);
                    }
                    else if(s_tcp_header_ptr->rst != 0) {
                        /* closed */
                    }
                }
                s_need_more_rx_check = 1;
	    }
	}
    }while(hwport_portscan_timer_check((hwport_portscan_timer_t *)(&s_timer)) == 0);
	                
    s_result = 0;

    free((void *)s_buffer);

l_close_with_return:;
    if(s_tcp_socket != (-1)) {
        while((close(s_tcp_socket) == (-1)) && (errno == EINTR));
    }

    /* close socket */
    while((close(s_socket) == (-1)) && (errno == EINTR));

l_return:;
    return(s_result);
}

int main(int s_argc, char **s_argv)
{
    static hwport_portscan_info_t s_info_local;

    hwport_portscan_info_t *s_info = &s_info_local;
    int s_start_port = 1, s_end_port = 65535, s_current_port;
    struct servent *s_servent;
    
    (void)fprintf(stdout, "HWPORT STELTH PORTSCAN - Copyright (c) HWPORT.COM. All rights reserved.\n");	

    s_info = hwport_portscan_info_init((hwport_portscan_info_t *)(&s_info_local));

    if(s_argc <= 2) {
        usage((const char *)s_argv[0]);
        return(EXIT_FAILURE);
    }

    s_info->m_hostname = (const char *)(s_argv[1]);
    s_info->m_peername = (const char *)(s_argv[2]);

    if(s_argc >= 4) {
        if((sscanf(s_argv[3], "%i", &s_start_port) != 1) || (s_start_port < 1) || (s_start_port > 65535)) {
            usage((const char *)s_argv[0]);
            (void)fprintf(stderr, "incorrect start_port !\n");
            return(EXIT_FAILURE);
        }
        s_end_port = s_start_port;

        if(s_argc >= 5) {
            if((sscanf(s_argv[4], "%i", &s_end_port) != 1) || (s_end_port < s_start_port) || (s_end_port > 65535)) {
                usage((const char *)s_argv[0]);
                (void)fprintf(stderr, "incorrect end_port !\n");
                return(EXIT_FAILURE);
            }
        }
    }
    
    (void)fprintf(stdout, "(host=\"%s\", peer=\"%s\", port=%d-%d, timeout=%dmsec)\n\n",
        s_info->m_hostname, s_info->m_peername, s_start_port, s_end_port, s_info->m_timeout_msec);

    /* set mask */
    for(s_current_port = s_start_port;s_current_port <= s_end_port;s_current_port++) {
        hwport_portscan_set_mask((void *)(&s_info->m_try_table[0]), s_current_port);
    }
    
    if(hwport_portscan(s_info) == (-1)) {
        return(EXIT_FAILURE);
    }

    setservent(1);
    for(s_current_port = 0;s_current_port < ((int)(sizeof(s_info->m_try_table) * 8));s_current_port++) {
        if(hwport_portscan_get_mask((const void *)(&s_info->m_try_table[0]), s_current_port) == 0) {
            continue;
        }
       
        if(hwport_portscan_get_mask((const void *)(&s_info->m_open_table[0]), s_current_port) != 0) {
            s_servent = getservbyport(htons(s_current_port), "tcp");
            (void)fprintf(stdout, "%d/tcp %s %s\n", s_current_port, "open", (s_servent == ((struct servent *)0)) ? "unknown" : s_servent->s_name);
        }
        else if((s_end_port - s_start_port) < 25) {
            s_servent = getservbyport(htons(s_current_port), "tcp");
            if(hwport_portscan_get_mask((const void *)(&s_info->m_ack_table[0]), s_current_port) != 0) {
                (void)fprintf(stdout, "%d/tcp %s %s\n", s_current_port, "closed", (s_servent == ((struct servent *)0)) ? "unknown" : s_servent->s_name);
            }
            else {
                (void)fprintf(stdout, "%d/tcp %s %s\n", s_current_port, "filtered", (s_servent == ((struct servent *)0)) ? "unknown" : s_servent->s_name);
            }
        }
    }
    endservent();

    return(EXIT_SUCCESS);
}

/* vim: set expandtab: */
/* End of source */

/*
End of page
(RemoteIP=38.107.179.243:53381)
Copyright © HWPORT.COM
All Rights Reserved.
*/