/*
============================================================================
Name : pingscan.c
Author : Chebotarev Roman
Version : 0.9
Copyright : All rights reserved
Description : pingscan project
============================================================================
*/
/* Need for compile in Visual Studio
* #define WIN32_LEAN_AND_MEAN
* #define _MT
*/
#include <winsock2.h>
#include <Ipexport.h>
#include <process.h>
#include <stdio.h>
#include <stdint.h>
#include "pingscan.h"
#include "func.h"
#include "raw_ping.h"
uint32_t start_scan_time;
uint32_t end_scan_time;
/* For scan mode */
IcmpSendEcho icmp_echo; /* Pointer to function. See pingscan.h */
IcmpCreateFile icmp_create_file; /* Pointer to function. See pingscan.h */
IcmpCloseHandle icmp_close_file;
uint32_t hosts_count; /* Total hosts responded */
/* For flood mode */
uint8_t flood_mode;
uint32_t total_sended; /* Total number of sended requests */
uint32_t unfinished_echoes_count;/* The number of requests which have not received answers */
int main(int arc, char *arv[])
{
WSADATA wsa_data;
HINSTANCE icmp_lib; /* Handle DLL which contains ICMP functions */
uint32_t threads_count; /* The maximum number of threads created by the program */
HANDLE threads[MAX_THREADS_COUNT]; /* Array of threads for ICMP senders */
DWORD th_id[MAX_THREADS_COUNT]; /* Array of threads identifiers */
uint32_t i = 0;
uint32_t start_address; /* Start of scanned IP addresses range */
uint32_t end_addr; /* End of scanned IP addresses range */
int32_t free_thread_handle_num;
uint32_t addr = 0;
CRITICAL_SECTION host_incr; /* Critical section, used for increment hosts_count
value from different threads */
CRITICAL_SECTION unfin_echoes; /* Critical section, used for increment unfinished_echoes
value from different threads */
struct config config_params; /* Various configuration settings. See pingscan.h */
struct echo_params * ping_args;
ZeroMemory(&config_params, sizeof(config_params));
config_params.netmask_len = DEF_SUBNET_MASK_LEN;
config_params.packets_count = DEF_PACKET_COUNT;
config_params.wait_time = DEF_WAIT_TIME;
config_params.packet_size = DEF_PACKET_SIZE;
if(!parsing_cmd_arguments(arc, arv, &config_params))
usage();
if (WSAStartup(0x0101, &wsa_data) != 0)
{
fprintf(stderr, "WSAStartup failed: %ld\n", GetLastError());
return -1;
}
/* Check WinSock version */
if (0x0101 != wsa_data.wVersion)
{
fprintf(stderr,"\nWinSock version 1.1 not supported\n");
WSACleanup();
return -1;
}
SetConsoleCtrlHandler(keyboard_interrupt_handler, 1);
/* Calculate first IP address of scanning range */
start_address = ntohl(inet_addr(config_params.subnet_ptr)) >> (32 - config_params.netmask_len);
start_address = htonl( (start_address << (32 - config_params.netmask_len)) );
/* Calculate last IP address of scanning range */
if(config_params.netmask_len == 31)
end_addr = start_address + htonl(1);
else if(config_params.netmask_len == 32)
end_addr = start_address;
else
end_addr = htonl( ntohl(start_address) |
((0xFFFFFFFF << config_params.netmask_len) >> config_params.netmask_len)
);
start_scan_time = GetTickCount();
if(config_params.flood)
{ /* Ping-flood mode */
flood_mode = 1;
InitializeCriticalSection(&unfin_echoes);
struct recving_echoes_params thread_recv_params;
thread_recv_params.common_params = &config_params;
thread_recv_params.dst_ip = start_address;
thread_recv_params.critical_section = &unfin_echoes;
thread_recv_params.unfinished_echoes = &unfinished_echoes_count;
/* Start thread which receiving ICMP echoes */
threads[0] = (HANDLE)_beginthreadex(NULL, 0, recving_echoes_threads, (void*) &thread_recv_params,
0, (uint32_t *) th_id);
/* Start sending flood */
printf("Loss: ");
send_echoes(start_address, config_params.packet_size, config_params.packets_count,
&unfin_echoes, &unfinished_echoes_count);
/* Waiting last packets in thread... */
WaitForSingleObject(threads[0], (DWORD) config_params.wait_time * 2);
/* Forcibly termitate recving thread */
TerminateThread(threads[0], 0);
DeleteCriticalSection(&unfin_echoes);
printf(" (%u packets)\n", unfinished_echoes_count);
}
else
{
/* Starting multi-threads ping */
/* Check for availability needed functions.
* Remark from http://msdn.microsoft.com/en-us/library/aa366045(VS.85).aspx:
*
* The IcmpCreateFile function is exported from the Icmp.dll on Windows 2000.
* The IcmpCreateFile function is exported from the Iphlpapi.dll on Windows XP and later.
* OS version checking is not recommended to use this function. Applications requiring
* portability with this function across Windows 2000, Windows XP, Windows Server 2003
* and later Windows versions should not statically link to either the Icmp.lib or the
* Iphlpapi.lib file. Instead, the application should check for the presence of
* IcmpCreateFile in the Iphlpapi.dll with calls to LoadLibrary and GetProcAddress.
* Failing that, the application should check for the presence of IcmpCreateFile in the
* Icmp.dll with calls to LoadLibrary and GetProcAddress.
*/
/* Trying used functions from Iphlpapi.dll */
icmp_lib = LoadLibrary(ICMP_DLL_XP);
if(!icmp_lib)
{
printf("LoadLibrary failed!\n");
return -1;
}
icmp_create_file = (IcmpCreateFile) GetProcAddress(icmp_lib, "IcmpCreateFile");
if(!(DWORD)icmp_create_file)
{
FreeLibrary(icmp_lib);
/* Trying use functions from Iphlpapi.dll */
icmp_lib = LoadLibrary(ICMP_DLL_2K);
icmp_create_file = (IcmpCreateFile) GetProcAddress(icmp_lib, "IcmpCreateFile");
if(!(DWORD)icmp_create_file)
{
printf("Failed get address IcmpCreateFile!\n");
return -1;
}
}
icmp_echo = (IcmpSendEcho) GetProcAddress(icmp_lib, "IcmpSendEcho");
if(!(DWORD)icmp_echo)
{
printf("Failed get address IcmpSendEcho!\n");
return -1;
}
icmp_close_file = (IcmpCloseHandle) GetProcAddress(icmp_lib, "IcmpCloseHandle");
if(!(DWORD)icmp_close_file)
{
printf("Failed get address IcmpCloseFile");
return -1;
}
/* Calculate threads number for running multi-threads pinging */
if(end_addr == start_address)
threads_count = 1;
else
{
if( (ntohl(end_addr) - ntohl(start_address)) <= MAX_THREADS_COUNT)
threads_count = ntohl(end_addr) - ntohl(start_address) + 1;
else threads_count = MAX_THREADS_COUNT;
}
printf("Pingscan version %s started.\n", VERSION);
InitializeCriticalSection(&host_incr);
for(i = 0, addr = start_address; i < threads_count; ++i)
{
ping_args = malloc(sizeof(struct echo_params));
if(!ping_args)
{
fprintf(stderr, "Can't allocate memory for arguments of thread! Exit.\n");
ExitProcess(-1);
}
ping_args -> config_params = &config_params;
ping_args -> dst_ip = addr;
ping_args -> hosts_count = &hosts_count;
ping_args -> host_incr = &host_incr;
ping_args -> release_mem_after_use = 1;
threads[i] = (HANDLE)_beginthreadex(NULL, 0, one_ping, (void*) ping_args, 0,
(uint32_t *) &th_id[i]);
addr += htonl(1);
}
/* Waiting first finishing thread from array of threads and running new thread instead him */
free_thread_handle_num = WaitForMultipleObjects(threads_count, (HANDLE*)&threads,
0, INFINITE) - WAIT_OBJECT_0;
while(ntohl(addr) <= ntohl(end_addr))
{
ping_args = malloc(sizeof(struct echo_params));
if(!ping_args)
{
fprintf(stderr, "Can't allocate memory for arguments of thread! Exit.\n");
ExitProcess(-1);
}
ping_args -> config_params = &config_params;
ping_args -> dst_ip = addr;
ping_args -> hosts_count = &hosts_count;
ping_args -> host_incr = &host_incr;
ping_args -> release_mem_after_use = 1;
threads[free_thread_handle_num]=
(HANDLE)_beginthreadex(NULL, 0, one_ping, (void*) ping_args, 0, (uint32_t *) &th_id[free_thread_handle_num]);
/* Waiting finished next thread from array of threads and running new thread instead him */
free_thread_handle_num = WaitForMultipleObjects(threads_count, (HANDLE*) &threads, 0, INFINITE) - WAIT_OBJECT_0;
addr = htonl(ntohl(addr) + 1);
}
/* Waiting finished all running ping-threads */
WaitForMultipleObjects(threads_count, (HANDLE*) &threads, 1, INFINITE);
DeleteCriticalSection(&host_incr);
if(!FreeLibrary(icmp_lib))
{
printf("FreeLibrary failed!\n");
return -1;
}
}
end_scan_time = GetTickCount();
WSACleanup();
printf("Total hosts scanned: %ld in %g seconds.\n", ntohl(end_addr) - ntohl(start_address) + 1,
(float)(end_scan_time - start_scan_time)/1000);
if(flood_mode)
{
printf("Flood mode statistic: ");
printf("%u packets transmitted, %u received, %.2f%% packets loss.\n",
total_sended, total_sended - unfinished_echoes_count,
((float)unfinished_echoes_count / total_sended) * 100);
printf("Pingscan finished.\n");
}
else
printf("Pingscan finished - %d hosts found.\n", hosts_count);
return 0;
}