Вступление
Сканер портов - это софтина, которая проверяет сервер на наличие открытых портов, пытаясь подключиться к серверу через каждый порт по очереди. После программа обычно сообщает, какие порты были открыты, а какие закрыты. Более сложные реализации сканеров портов, такие как Nmap помимо всего могут предоставлять и другую инфу, начиная от версии ПО заканчивая версией браузера. Сканирование портов обычно выполняется системными администраторами для проверки безопасности сети или злоумышленниками (хаЦкерами), которые ищут открытый порт, через который можно поставить под угрозу безопасность сервера, или в народе - просунуть свою жопу, дабы чем поживится. Наш первый скан портов в первородном виде
Повторяясь, скан портов так же просто, как попытка подключения к адресу и порту по средствам сокетов. Если попытка подключения успешна, порт должен быть открыт. В противном случае fail, порт закрыт.
Начнем с функции-чекера, использующей сетевой модуль SFML для проверки открыт ли порт:
Функция port_is_open:
C++:
bool port_is_open(const std::string& address, int port)
{
sf::TcpSocket socket; // через глобал. пилим сокет
bool open = (socket.connect(sf::IpAddress(address), port) == sf::Socket::Done); // проверяем на open
socket.disconnect(); // закрываем
return open;
}
Пояснительная бригада на выезд:
- Сначала мы создаем экземпляр sf :: TcpSocket, который позволяет нам подключаться к удаленному сокету.
- Затем подключаем сокет. Мы преобразуем строку «адрес» в экземпляр sf :: IpAddress, вызывая конструктор для sf :: IpAddress. Если явный вызов конструктора не заюзали, компилятор все равно выполнит его неявно. После попытки подключения мы проверяем, было ли соединение успешным, сравнивая возвращаемое значение функции sf :: TcpSocket :: connect со значением sf :: Socket :: Done. Если они равны, это означает, что соединение установлено и порт открыт. В этом случае для переменной open установлено значение true.
- Далее мы отключаем сокет с помощью функции sf :: TcpSocket :: disconnect. Это будет сделано автоматически в деструкторе, если мы оставим явный вызов.
- Наконец, мы возвращаем значение open вызывающей функции.
Функция FirtsTempMain:
C++:
#include <iostream>
#include <SFML/Network.hpp> // не забудь её скачать и подключить
#include <string>
static bool port_is_open(const std::string& address, int port)
{
return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}
int main()
{
std::cout << "Port 80 : ";
if (port_is_open("localhost", 80))
std::cout << "OPEN" << std::endl;
else
std::cout << "CLOSED" << std::endl;
return 0;
}
Есть пробитие!
Попробуйте скомпилировать и запустить эту программу. Она проверит, открыт ли порт 80 на вашем компьютере. Обратите внимание, что «localhost» означает локальный компьютер; вы также можете использовать IP-адрес 127.0.0.1 или :: 1 (версия IPv6, хотя SFML еще не поддерживает IPv6). Вы можете изменить "localhost" на IP-адрес или веб-адрес другого веб-сайта (не включая "http: //" и любую информацию о пути).
А даватей проапдейтим наш сканер, чтобы он был похож как у настоящих тру-хацкеров в фильмах и боевиках.
Улучшенный сканер портов
Теперь, когда мы успешно разработали программу, которая может сканировать порт по адресу, мы изменим нашу программу, чтобы юзер, то есть вы, могли сами выбирать порты и адреса для скана:
C++:
#include <iostream>
#include <SFML/Network.hpp>
#include <string>
// тут все ясно. чекнули получили валид-сокет идем дальше
static bool port_is_open(const std::string& address, int port)
{
return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}
int main()
{
std::string address; // пилим адресс
int port; // номер апорта
// получаем адресс.
std::cout << "Address: " << std::flush;
std::getline(std::cin, address);
// получае порт.
std::cout << "Port: " << std::flush;
std::cin >> port;
// поехали шерстить
std::cout << "Scanning " << address << "...\n" << "Port " << port << " : ";
if (port_is_open(address, port))
std::cout << "OPEN" << std::endl;
else
std::cout << "CLOSED" << std::endl;
return 0;
}
На этот раз это может занять немного больше времени, потому что вы не сканируете свой комп, на этот раз вы подключаетесь к другому компьютеру по инету
Стек Портов
Скан одного порта душная тема, мы хотим разогнатся на все массив портов. Один из способов сделать это - позволить юзеру вводить столько портов, сколько он хочет, а затем сканировать их все за один раз. Проблема заключается в том, что юзер может захотеть просканировать множество портов, и ему придется вводить каждый из них. Мы также могли бы позволить пользователю указать диапазон портов, скажем, 0–100, но тогда они не могли бы указывать значения за пределами этой ранжи. Нырнем глубже, и заюзаем и то, и другое - укажем диапазоны И отдельные порты в списке: '80, 8080 '; диапазон, например: «20-80»; или список, содержащий диапазоны: «20–80,8080». Этот код становится довольно сложным из-за использования шаблонов, std :: vector, std :: stringstream и цикла for C ++ 11 на основе диапазона.Для начала нам нужна функция для разделения строк:
Функция std::vector<std::string> split:
C++:
// Разбиваем строку на "токены" возле разделителя (пробел),
// опционально пропускаем пустые токены.
static std::vector<std::string> split(const std::string& string,
char delimiter = ' ',
bool allow_empty = false)
{
std::vector<std::string> tokens;
std::stringstream sstream(string);
std::string token;
while (std::getline(sstream, token, delimiter)) {
if (allow_empty || token.size() > 0)
tokens.push_back(token);
}
return tokens;
}
Функция string_to_int:
C++:
static int string_to_int(const std::string& string)
{
std::stringstream sstream(string);
int i;
sstream >> i;
return i;
}
Если у нас есть диапазон портов, нам понадобится функция для генерации всех значений в этом диапазоне:
C++:
// Функция обмена.
template <typename T>
static void swap(T& a, T& b)
{
T c = a;
a = b;
b = c;
}
// Создает вектор, содержащий диапазон значений.
template <typename T>
static std::vector<T> range(T min, T max)
{
if (min > max)
swap(min, max);
if (min == max)
return std::vector<T>(1, min);
std::vector<T> values;
for (; min <= max; ++min)
values.push_back(min);
return values;
}
Наконец, нам нужна функция для анализа списка портов с использованием вышеуказанных функций:
Функция parse_ports_list:
C++:
// Лист для парсинга портов
static std::vector<int> parse_ports_list(const std::string& list)
{
std::vector<int> ports;
// Лист портов.
for (const std::string& token : split(list, ',')) {
// Лист диапазона.
std::vector<std::string> strrange = split(token, '-');
switch (strrange.size()) {
// Только одно знач. (добавьте только в конце 'ports').
case 0: ports.push_back(string_to_int(token)); break;
case 1: ports.push_back(string_to_int(strrange[0])); break;
// Два значения (диапазон - все в этом диапазоне).
case 2:
{
int min = string_to_int(strrange[0]),
max = string_to_int(strrange[1]);
for (int port : range(min, max))
ports.push_back(port);
break;
}
default:
break;
}
}
return ports;
}
Финалочка:
C++:
#include <iostream>
#include <SFML/Network.hpp>
#include <sstream>
#include <string>
#include <vector>
static bool port_is_open(const std::string& address, int port)
{
return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}
static std::vector<std::string> split(const std::string& string,
char delimiter = ' ',
bool allow_empty = false)
{
std::vector<std::string> tokens;
std::stringstream sstream(string);
std::string token;
while (std::getline(sstream, token, delimiter)) {
if (allow_empty || token.size() > 0)
tokens.push_back(token);
}
return tokens;
}
static int string_to_int(const std::string& string)
{
std::stringstream sstream(string);
int i;
sstream >> i;
return i;
}
template <typename T>
static void swap(T& a, T& b)
{
T c = a;
a = b;
b = c;
}
template <typename T>
static std::vector<T> range(T min, T max)
{
if (min > max)
swap(min, max);
if (min == max)
return std::vector<T>(1, min);
std::vector<T> values;
for (; min <= max; ++min)
values.push_back(min);
return values;
}
static std::vector<int> parse_ports_list(const std::string& list)
{
std::vector<int> ports;
for (const std::string& token : split(list, ',')) {
std::vector<std::string> strrange = split(token, '-');
switch (strrange.size()) {
case 0: ports.push_back(string_to_int(token)); break;
case 1: ports.push_back(string_to_int(strrange[0])); break;
case 2:
{
int min = string_to_int(strrange[0]),
max = string_to_int(strrange[1]);
for (int port : range(min, max))
ports.push_back(port);
break;
}
default:
break;
}
}
return ports;
}
int main()
{
std::string address;
std::string port_list;
std::vector<int> ports;
std::cout << "Address: " << std::flush;
std::getline(std::cin, address);
std::cout << "Port: " << std::flush;
std::getline(std::cin, port_list);
ports = parse_ports_list(port_list);
std::cout << "Scanning " << address << "...\n";
for (int port : ports) {
std::cout << "Port " << port << " : ";
if (port_is_open(address, port))
std::cout << "OPEN\n";
else
std::cout << "CLOSED\n";
}
std::cout << std::flush;
return 0;
}
На премию Тьюринга не претендует, но уже есть отправная точка)