#include "PortScanner.hpp" const std::unordered_map PortScanner::basicPorts{ {21, "FTP"}, {22, "SSH"}, {23, "TelNet"}, {25, "SMTP"}, {53, "DNS"}, {67, "DHCP server"}, {68, "DHCP client"}, {80, "HTTP"}, {110, "POP3"}, {143, "IMAP"}, {161, "SNMP"}, {443, "HTTPS"}, {445, "SMB"}, {465, "SMTPS"}, {993, "IMAPS"}, {1080, "SOCKS"}, {1521, "ORACLE DB"}, {3306, "MySQL"}, {3389, "RDP"}, {5432, "PostgreSQL"}, {6379, "Redis"}, }; void PortScanner::parse_port(std::string& port) { auto t = std::find(port.begin(), port.end(), '-'); if (t == port.end()) { startPort = 1; endPort = std::stoi(port); return; } auto it = port.begin(); std::string s = "", e = ""; while (it != port.end()) { if (*it == '-') { break; } s += *it; ++it; } ++it; while (it != port.end()) { e += *it; ++it; } int start_port = std::stoi(s); int end_port = std::stoi(e); if (start_port == 0 || end_port > MAX_PORT || start_port > end_port) { startPort = 1; endPort = MAX_PORT; } else { startPort = static_cast(start_port); endPort = static_cast(end_port); } } PortScanner::PortScanner(std::string& domainName, std::string& port, int max_threads, std::uint8_t expiry_time) { this->domainName = std::move(domainName); this->MAX_THREADS = max_threads; this->expiry_time = expiry_time; parse_port(port); auto result = resolver.resolve(this->domainName, ""); endpoint = *result.begin(); setup_queue(); } void PortScanner::setup_queue() { q = std::queue(); for (int i = startPort; i <= endPort; i++) { q.push(i); } } void PortScanner::set_options(std::string& domainName, std::string& port, int max_threads, std::uint8_t expiry_time) { this->domainName = std::move(domainName); this->MAX_THREADS = max_threads; this->expiry_time = expiry_time; parse_port(port); auto result = resolver.resolve(this->domainName, ""); endpoint = *result.begin(); } void PortScanner::set_max_port(std::uint16_t port) { endPort = port; } void PortScanner::set_max_threads(int value) { MAX_THREADS = value; } void PortScanner::set_ip_address(std::string ip) { domainName = std::move(ip); } void PortScanner::set_expiry_time(std::uint8_t value) { expiry_time = value; } void PortScanner::start() { setup_queue(); for (int i = 0; i < MAX_THREADS; i++) { boost::asio::post(strand, [this]() { scan(); }); } } void PortScanner::run() { printf("PORT\tSTATE\tSERVICE\tBANNER\n"); io.run(); printf("\nResult:\n"); printf(" Open ports: %d\n", open_ports); printf(" Closed ports: %d\n", closed_ports); printf(" Filtered ports: %d\n", filtered_ports); } void PortScanner::scan() { if (q.empty() || cnt >= MAX_THREADS) return; uint16_t port = q.front(); q.pop(); ++cnt; auto socket = std::make_shared(io); auto timer = std::make_shared(io); auto complete = std::make_shared(false); tcp::endpoint target_endpoint(this->endpoint.address(), port); timer->expires_after(std::chrono::seconds(expiry_time)); timer->async_wait(boost::asio::bind_executor( strand, [this, complete, socket, port](boost::system::error_code ec) { if (!ec && !*complete) { *complete = true; socket->close(); printf("%i\t%s\t%s\t%s\n", port, "FILTERED", "NULL", "NULL"); ++filtered_ports; --cnt; scan(); } })); socket->async_connect(target_endpoint, boost::asio::bind_executor(strand, [this, socket, timer, port, complete]( boost::system::error_code ec) { if (*complete) return; *complete = true; timer->cancel(); std::string service = "---"; auto banner = std::make_shared("---"); auto it = basicPorts.find(port); if (it != basicPorts.end()) { service = it->second; } if (!ec) { auto buf = std::make_shared>(); socket->async_read_some( boost::asio::buffer(*buf), boost::asio::bind_executor( strand, [this, port, buf, banner, service]( boost::system::error_code ec, std::size_t n) { if (!ec && n > 0) { banner->assign(buf->data(), n); } printf("%i\t%sOPEN%s\t%s\t%s\n", port, GREEN, RESET, service.c_str(), banner->c_str()); ++open_ports; --cnt; scan(); })); } else { printf("%i\t%sCLOSED%s\t%s\t%s\n", port, RED, RESET, service.c_str(), banner->c_str()); ++closed_ports; --cnt; scan(); } })); }