Сканер портов
У меня возникла проблема при реализации сканера портов под Линукc:
Программа почему то себя по разному ведет при запуске на разных дистрибутивах Линукса. Пробовал всего на двух: на Red Hat'e и на Ubuntu. При чем на Red Hat'e поведение корректное, а на Ubuntu на все порты выдает "open"
ПС Так же хотелось бы чтобы знающие люди оценили программу и по возможности что нибудь подсказали, как ее можно улучшить
Задание на программу:
Сканер открытых TCP портов.
Сканирует порты в заданном диапазоне, пытаясь установить соединение с каждым из них.
Ответ ожидается в течение заданного интервала, чтобы исключить резкое замедление сканирования из-за возможного блокирования.
В результате для каждого сканированного порта должен быть выведен один из трех возможных результатов: open, closed, blocked.
Использовать перевод сокета в неблокирующий режим и функцию select() для ожидания готовности сокета или ошибки в течение заданного интервала времени.
Пример вызова программы:
./scan_ports 127.0.0.1 20 25 0.8
20: closed
21: closed
22: open
23: closed
24: closed
25: blocked
done
Сканирует порты в заданном диапазоне, пытаясь установить соединение с каждым из них.
Ответ ожидается в течение заданного интервала, чтобы исключить резкое замедление сканирования из-за возможного блокирования.
В результате для каждого сканированного порта должен быть выведен один из трех возможных результатов: open, closed, blocked.
Использовать перевод сокета в неблокирующий режим и функцию select() для ожидания готовности сокета или ошибки в течение заданного интервала времени.
Пример вызова программы:
./scan_ports 127.0.0.1 20 25 0.8
20: closed
21: closed
22: open
23: closed
24: closed
25: blocked
done
Собственно код программы:
Код:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <algorithm>
#include <set>
#include <map>
#include <iostream>
#include <errno.h>
#include <arpa/inet.h>
#include <string>
#include <sstream>
#include <math.h>
using namespace std;
typedef map<unsigned int, unsigned int> portmap;
//List must be: <ip_addr> <from_port> <to_port> <max_delay>
// Example: 127.0.0.1 20 50 3.9
int main(int argc, char* argv[])
{
char* ip_addr;
int port_from;
int port_to;
float max_delay;
cout << "Settings:" << endl;
if ( argc == 5 )
{
ip_addr = argv[1];
cout << "\tIP address for scan:\t" << ip_addr << endl;
string tempstr;
stringstream convert1(tempstr.assign(argv[2],sizeof(argv[2])));
if ( ! (convert1 >> port_from))
{
cerr << "Error: Format of <port_from> isnt correct\n";
exit(1);
}
cout << "\tFrom port:\t\t" << port_from << endl;
stringstream convert2(tempstr.assign(argv[3],sizeof(argv[3])));
if ( ! (convert2 >> port_to))
{
cerr << "Error: Format of <port_to> isnt correct\n";
exit(1);
}
cout << "\tTill port:\t\t" << port_to << endl;
stringstream convert3(tempstr.assign(argv[4],sizeof(argv[4])));
if ( ! (convert3 >> max_delay) || max_delay < 0)
{
cerr << "Error: Format of <max_delay> isnt correct\n";
exit(1);
}
cout << "\tTill port:\t\t" << max_delay << endl;
}
else
{
cerr << "List of argument isnt correct. List must be: <ip_addr> <from_port> <to_port> <max_delay>";
exit(1);
}
int sock;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip_addr);
portmap port_status;
port_status.clear();
portmap connections;
connections.clear();
for (int cur_port=port_from; cur_port < port_to; cur_port++)
{
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) //turn on nonblock mode
{
perror("fcntl");
exit(2);
}
addr.sin_port = htons(cur_port);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0 && errno != EINPROGRESS)
{
perror("connect");
exit(3);
}
connections[sock]=cur_port;
port_status[cur_port]=0;
}
// set value of timeout
timeval timeout;
double b;
timeout.tv_usec=(int)(modf(max_delay,&b)*10);
timeout.tv_sec=(int)(max_delay-modf(max_delay,&b));
fd_set wset;
int mx;
bool istimeout=false;
while(!connections.empty())
{
// fill in array of sockets
FD_ZERO(&wset);
for(portmap::iterator it = connections.begin(); it != connections.end(); it++)
FD_SET((*it).first, &wset);
// waiting events
mx = max_element(connections.begin(), connections.end())->first;
if(int err=select(mx+1, NULL, &wset, NULL, &timeout) <= 0)
{
if (err == -1)
{
perror("select");
exit(4);
}
else
istimeout = true; //timeout
}
for(portmap::iterator it = connections.begin(); it != connections.end(); it++)
{
if(FD_ISSET((*it).first, &wset))
{
int error;
socklen_t err_len = sizeof(error);
if( getsockopt((*it).first, SOL_SOCKET, SO_ERROR, &error, &err_len) < 0 || error != 0)
{
switch (errno)
{
case EINPROGRESS:
break;
case EISCONN:
case EALREADY:
port_status[(*it).second]=3; //blocked
close((*it).first);
connections.erase(it);
break;
case ETIMEDOUT:
case ECONNREFUSED:
port_status[(*it).second]=2; //closed
close((*it).first);
connections.erase(it);
break;
case EPERM:
case EACCES:
case EAFNOSUPPORT:
cout << "Address isn't correct" << endl;
exit(1); //
break;
case ENETUNREACH:
cout << "The network is unreachable" << endl;
break;
default:
cout << "Unknown error" << endl;
break;
}
}
else
{
port_status[(*it).second]=1; //open
close((*it).first);
connections.erase(it);
}
}
if (istimeout)
{
port_status[(*it).second]=2; //closed
close((*it).first);
connections.erase(it);
}
}
}
//output results
cout << "\nResults:" << endl;
for(portmap::iterator it = port_status.begin(); it != port_status.end(); it++)
{
cout << (*it).first << ": ";
switch((*it).second)
{
case 1:
cout << "open" << endl;
break;
case 2:
cout << "closed" << endl;
break;
case 3:
cout << "blocked" << endl;
break;
}
}
return 0;
}
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <algorithm>
#include <set>
#include <map>
#include <iostream>
#include <errno.h>
#include <arpa/inet.h>
#include <string>
#include <sstream>
#include <math.h>
using namespace std;
typedef map<unsigned int, unsigned int> portmap;
//List must be: <ip_addr> <from_port> <to_port> <max_delay>
// Example: 127.0.0.1 20 50 3.9
int main(int argc, char* argv[])
{
char* ip_addr;
int port_from;
int port_to;
float max_delay;
cout << "Settings:" << endl;
if ( argc == 5 )
{
ip_addr = argv[1];
cout << "\tIP address for scan:\t" << ip_addr << endl;
string tempstr;
stringstream convert1(tempstr.assign(argv[2],sizeof(argv[2])));
if ( ! (convert1 >> port_from))
{
cerr << "Error: Format of <port_from> isnt correct\n";
exit(1);
}
cout << "\tFrom port:\t\t" << port_from << endl;
stringstream convert2(tempstr.assign(argv[3],sizeof(argv[3])));
if ( ! (convert2 >> port_to))
{
cerr << "Error: Format of <port_to> isnt correct\n";
exit(1);
}
cout << "\tTill port:\t\t" << port_to << endl;
stringstream convert3(tempstr.assign(argv[4],sizeof(argv[4])));
if ( ! (convert3 >> max_delay) || max_delay < 0)
{
cerr << "Error: Format of <max_delay> isnt correct\n";
exit(1);
}
cout << "\tTill port:\t\t" << max_delay << endl;
}
else
{
cerr << "List of argument isnt correct. List must be: <ip_addr> <from_port> <to_port> <max_delay>";
exit(1);
}
int sock;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip_addr);
portmap port_status;
port_status.clear();
portmap connections;
connections.clear();
for (int cur_port=port_from; cur_port < port_to; cur_port++)
{
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) //turn on nonblock mode
{
perror("fcntl");
exit(2);
}
addr.sin_port = htons(cur_port);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0 && errno != EINPROGRESS)
{
perror("connect");
exit(3);
}
connections[sock]=cur_port;
port_status[cur_port]=0;
}
// set value of timeout
timeval timeout;
double b;
timeout.tv_usec=(int)(modf(max_delay,&b)*10);
timeout.tv_sec=(int)(max_delay-modf(max_delay,&b));
fd_set wset;
int mx;
bool istimeout=false;
while(!connections.empty())
{
// fill in array of sockets
FD_ZERO(&wset);
for(portmap::iterator it = connections.begin(); it != connections.end(); it++)
FD_SET((*it).first, &wset);
// waiting events
mx = max_element(connections.begin(), connections.end())->first;
if(int err=select(mx+1, NULL, &wset, NULL, &timeout) <= 0)
{
if (err == -1)
{
perror("select");
exit(4);
}
else
istimeout = true; //timeout
}
for(portmap::iterator it = connections.begin(); it != connections.end(); it++)
{
if(FD_ISSET((*it).first, &wset))
{
int error;
socklen_t err_len = sizeof(error);
if( getsockopt((*it).first, SOL_SOCKET, SO_ERROR, &error, &err_len) < 0 || error != 0)
{
switch (errno)
{
case EINPROGRESS:
break;
case EISCONN:
case EALREADY:
port_status[(*it).second]=3; //blocked
close((*it).first);
connections.erase(it);
break;
case ETIMEDOUT:
case ECONNREFUSED:
port_status[(*it).second]=2; //closed
close((*it).first);
connections.erase(it);
break;
case EPERM:
case EACCES:
case EAFNOSUPPORT:
cout << "Address isn't correct" << endl;
exit(1); //
break;
case ENETUNREACH:
cout << "The network is unreachable" << endl;
break;
default:
cout << "Unknown error" << endl;
break;
}
}
else
{
port_status[(*it).second]=1; //open
close((*it).first);
connections.erase(it);
}
}
if (istimeout)
{
port_status[(*it).second]=2; //closed
close((*it).first);
connections.erase(it);
}
}
}
//output results
cout << "\nResults:" << endl;
for(portmap::iterator it = port_status.begin(); it != port_status.end(); it++)
{
cout << (*it).first << ": ";
switch((*it).second)
{
case 1:
cout << "open" << endl;
break;
case 2:
cout << "closed" << endl;
break;
case 3:
cout << "blocked" << endl;
break;
}
}
return 0;
}
Прогнал у себя в Kubuntu. Тот-же результат - все порты открыты. У вас есть опечатка -- cout << "\tTill port:\t\t" << max_delay << endl;