Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a4f103d0c8 | |||
| bb99d8d812 | |||
| 1e6fecb7bd | |||
| 88520915dc |
@@ -2,4 +2,3 @@
|
|||||||
.xmake
|
.xmake
|
||||||
build
|
build
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
ignore
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
#include "portscan_cli.hpp"
|
|
||||||
#include <boost/program_options/value_semantic.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
PortScanCli::PortScanCli()
|
|
||||||
: CliBase("Port Scanner Options")
|
|
||||||
, ip_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanCli::setupOptions()
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
desc_.add_options()
|
|
||||||
("help,h", "Show help")
|
|
||||||
("ip,H", withDefault(ip_, "<IP>"), "Local IPv4 to scan");
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PortScanCli::getIp() const
|
|
||||||
{
|
|
||||||
if (vm_["ip"].empty() == 0) {
|
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
|
||||||
return vm_.at("ip").as<std::string>();
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "cli_base.hpp"
|
|
||||||
#include "option_utils.hpp"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class PortScanCli : public CliBase, protected OptionUtils
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PortScanCli();
|
|
||||||
|
|
||||||
std::string getIp() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setupOptions() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string ip_;
|
|
||||||
};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <boost/asio/ip/address.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
|
|
||||||
// --- Error handling ---
|
|
||||||
using ErrorCode = boost::system::error_code;
|
|
||||||
|
|
||||||
// --- Asio types ---
|
|
||||||
using IoContext = boost::asio::io_context;
|
|
||||||
using SteadyTimer = boost::asio::steady_timer;
|
|
||||||
|
|
||||||
// --- Ip types ---
|
|
||||||
using IpAddress = boost::asio::ip::address;
|
|
||||||
|
|
||||||
// --- TCP types ---
|
|
||||||
using TcpSocket = boost::asio::ip::tcp::socket;
|
|
||||||
using TcpAcceptor = boost::asio::ip::tcp::acceptor;
|
|
||||||
using TcpEndpoint = boost::asio::ip::tcp::endpoint;
|
|
||||||
|
|
||||||
// --- UDP types ---
|
|
||||||
using UdpSocket = boost::asio::ip::udp::socket;
|
|
||||||
using UdpEndpoint = boost::asio::ip::udp::endpoint;
|
|
||||||
|
|
||||||
// --- Program options ---
|
|
||||||
using OptionsDescription = boost::program_options::options_description;
|
|
||||||
using VariablesMap = boost::program_options::variables_map;
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
|
||||||
|
// IO Contextct
|
||||||
|
using IoContext = boost::asio::io_context;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
|
||||||
|
// TCP
|
||||||
|
using TcpSocket = boost::asio::ip::tcp::socket;
|
||||||
|
using TcpAcceptor = boost::asio::ip::tcp::acceptor;
|
||||||
|
using TcpEndpoint = boost::asio::ip::tcp::endpoint;
|
||||||
|
using TcpResolver = boost::asio::ip::tcp::resolver;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
|
||||||
|
// Timers
|
||||||
|
using SteadyTimer = boost::asio::steady_timer;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
using ErrorCode = boost::system::error_code;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// Fixed-width unsigned integers
|
||||||
|
using u8 = std::uint8_t;
|
||||||
|
using u32 = std::uint32_t;
|
||||||
|
using u64 = std::uint64_t;
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#include "cli_base.hpp"
|
|
||||||
#include <boost/program_options/parsers.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
CliBase::CliBase(const std::string &title)
|
|
||||||
: desc_(title)
|
|
||||||
, help_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CliBase::parse(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
using namespace boost::program_options;
|
|
||||||
|
|
||||||
setupOptions(); // must be first
|
|
||||||
|
|
||||||
parsed_options parsed = parse_command_line(argc, argv, desc_);
|
|
||||||
store(parsed, vm_);
|
|
||||||
notify(vm_);
|
|
||||||
|
|
||||||
if (vm_.count("help")) {
|
|
||||||
help_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CliBase::isHelp() const
|
|
||||||
{
|
|
||||||
return help_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CliBase::printHelp() const
|
|
||||||
{
|
|
||||||
std::cout << desc_ << "\n";
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <boost/program_options/options_description.hpp>
|
|
||||||
#include <boost/program_options/variables_map.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class CliBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CliBase(const std::string &title);
|
|
||||||
|
|
||||||
virtual ~CliBase() = default;
|
|
||||||
|
|
||||||
// parse argc/argv
|
|
||||||
void parse(int argc, char *argv[]);
|
|
||||||
|
|
||||||
bool isHelp() const;
|
|
||||||
void printHelp() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// children add their specific options here
|
|
||||||
virtual void setupOptions() = 0;
|
|
||||||
|
|
||||||
boost::program_options::options_description desc_;
|
|
||||||
boost::program_options::variables_map vm_;
|
|
||||||
bool help_;
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
|
|
||||||
class OptionUtils
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template <typename T>
|
|
||||||
using OptionValue = boost::program_options::typed_value<T> *;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static OptionValue<T>
|
|
||||||
withDefault(const T &value, const char *name = nullptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
OptionUtils() = default;
|
|
||||||
~OptionUtils() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "option_utils.tpp"
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "option_utils.hpp"
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
OptionUtils::OptionValue<T>
|
|
||||||
OptionUtils::withDefault(const T &value, const char *name)
|
|
||||||
{
|
|
||||||
auto v = boost::program_options::value<T>()->default_value(value);
|
|
||||||
if (name) {
|
|
||||||
v->value_name(name); // Optional
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
#include "port_scanner.hpp"
|
|
||||||
#include "logger.hpp"
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
PortScanner::PortScanner(
|
|
||||||
const std::string &ip, const std::vector<uint16_t> &ports
|
|
||||||
)
|
|
||||||
: ports_(ports)
|
|
||||||
{
|
|
||||||
ErrorCode ec;
|
|
||||||
addr_ = boost::asio::ip::make_address(ip, ec);
|
|
||||||
ip_ok_ = !ec;
|
|
||||||
|
|
||||||
if (!ip_ok_) {
|
|
||||||
Logger::error(std::string("PortScanner: invalid IP: ") + ip);
|
|
||||||
} else {
|
|
||||||
Logger::debug(std::string("PortScanner: using IP: ") + ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::setTimeoutMs(int ms)
|
|
||||||
{
|
|
||||||
if (ms > 0) {
|
|
||||||
timeout_ms_ = ms;
|
|
||||||
Logger::debug(
|
|
||||||
std::string("PortScanner: timeout set to ")
|
|
||||||
+ std::to_string(timeout_ms_) + " ms"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::run()
|
|
||||||
{
|
|
||||||
if (!ip_ok_) {
|
|
||||||
Logger::error("PortScanner::run - aborting: ip not ok");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (uint16_t p : ports_) {
|
|
||||||
if (probe(p)) {
|
|
||||||
Logger::info(std::to_string(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PortScanner::probe(uint16_t port)
|
|
||||||
{
|
|
||||||
TcpSocket s(io_);
|
|
||||||
SteadyTimer t(io_);
|
|
||||||
auto ep = endpoint(port);
|
|
||||||
|
|
||||||
Logger::debug(
|
|
||||||
std::string("PortScanner::probe - probing port ") + std::to_string(port)
|
|
||||||
);
|
|
||||||
|
|
||||||
armTimer(t, s);
|
|
||||||
armConnect(s, ep);
|
|
||||||
runUntilDone();
|
|
||||||
cancelTimer(t);
|
|
||||||
drainLeftovers();
|
|
||||||
close(s);
|
|
||||||
|
|
||||||
if (ok_) {
|
|
||||||
Logger::debug(std::string("Port ") + std::to_string(port) + " is OPEN");
|
|
||||||
} else {
|
|
||||||
Logger::debug(
|
|
||||||
std::string("Port ") + std::to_string(port) + " is CLOSED/FILTERED"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok_;
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpEndpoint PortScanner::endpoint(uint16_t port) const
|
|
||||||
{
|
|
||||||
return TcpEndpoint(addr_, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::armTimer(SteadyTimer &t, TcpSocket &s)
|
|
||||||
{
|
|
||||||
t.expires_after(std::chrono::milliseconds(timeout_ms_));
|
|
||||||
|
|
||||||
auto onTimeout = [&s](const ErrorCode &ec) {
|
|
||||||
if (!ec) {
|
|
||||||
Logger::debug("Timer expired -> cancelling socket");
|
|
||||||
s.cancel();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
t.async_wait(onTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::armConnect(TcpSocket &s, const TcpEndpoint &ep)
|
|
||||||
{
|
|
||||||
ok_ = false;
|
|
||||||
done_ = false;
|
|
||||||
|
|
||||||
auto onConnect = [this](const ErrorCode &ec) {
|
|
||||||
if (!ec) {
|
|
||||||
ok_ = true;
|
|
||||||
Logger::debug("async_connect succeeded");
|
|
||||||
} else {
|
|
||||||
ok_ = false;
|
|
||||||
Logger::debug(std::string("async_connect failed: ") + ec.message());
|
|
||||||
}
|
|
||||||
done_ = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
s.async_connect(ep, onConnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::runUntilDone()
|
|
||||||
{
|
|
||||||
io_.restart();
|
|
||||||
while (!done_ && io_.run_one()) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::cancelTimer(SteadyTimer &t)
|
|
||||||
{
|
|
||||||
ErrorCode ec;
|
|
||||||
t.cancel();
|
|
||||||
if (ec) {
|
|
||||||
Logger::warn(std::string("cancelTimer: ") + ec.message());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::drainLeftovers()
|
|
||||||
{
|
|
||||||
io_.restart();
|
|
||||||
while (io_.run_one()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::close(TcpSocket &s)
|
|
||||||
{
|
|
||||||
ErrorCode ig;
|
|
||||||
if (s.close(ig)) {
|
|
||||||
Logger::warn(std::string("close socket failed: ") + ig.message());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "aliases.hpp"
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class PortScanner
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PortScanner(const std::string &ip, const std::vector<uint16_t> &ports);
|
|
||||||
|
|
||||||
void setTimeoutMs(int ms);
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool probe(uint16_t port);
|
|
||||||
TcpEndpoint endpoint(uint16_t port) const;
|
|
||||||
|
|
||||||
void armTimer(SteadyTimer &t, TcpSocket &s);
|
|
||||||
void armConnect(TcpSocket &s, const TcpEndpoint &ep);
|
|
||||||
void runUntilDone();
|
|
||||||
void cancelTimer(SteadyTimer &t);
|
|
||||||
void drainLeftovers();
|
|
||||||
void close(TcpSocket &s);
|
|
||||||
|
|
||||||
private:
|
|
||||||
IoContext io_;
|
|
||||||
IpAddress addr_;
|
|
||||||
std::vector<uint16_t> ports_;
|
|
||||||
|
|
||||||
int timeout_ms_{300};
|
|
||||||
bool ip_ok_{false};
|
|
||||||
bool ok_{false};
|
|
||||||
bool done_{false};
|
|
||||||
};
|
|
||||||
+10
-32
@@ -1,38 +1,16 @@
|
|||||||
#include "cli_base.hpp"
|
#include <boost/asio.hpp>
|
||||||
#include "logger.hpp"
|
#include <iostream>
|
||||||
#include "port_scanner.hpp"
|
|
||||||
#include "portscan_cli.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
int main()
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
static std::vector<uint16_t> allPorts()
|
|
||||||
{
|
{
|
||||||
std::vector<uint16_t> v;
|
std::cout << "Hello, Boost + C++23 + xmake!\n";
|
||||||
v.reserve(65535);
|
|
||||||
for (uint32_t p = 1; p <= 65535; ++p) {
|
|
||||||
v.push_back(static_cast<uint16_t>(p));
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
boost::asio::io_context io;
|
||||||
{
|
boost::asio::steady_timer timer(io, std::chrono::seconds(1));
|
||||||
Logger::init(true);
|
timer.async_wait([](const boost::system::error_code &) {
|
||||||
|
std::cout << "Timer fired after 1 second!\n";
|
||||||
|
});
|
||||||
|
|
||||||
PortScanCli cli;
|
io.run();
|
||||||
cli.parse(argc, argv);
|
|
||||||
if (cli.isHelp()) {
|
|
||||||
cli.printHelp();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string ip = cli.getIp();
|
|
||||||
auto ports = allPorts();
|
|
||||||
|
|
||||||
Logger::info("Starting full port scan (1..65535)...");
|
|
||||||
PortScanner scanner(ip, ports);
|
|
||||||
scanner.run();
|
|
||||||
Logger::info("Scan completed.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
|
||||||
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
||||||
|
|
||||||
void Logger::init(bool toConsole, const std::string_view filePath)
|
void Logger::init(bool toConsole, const std::string_view filePath)
|
||||||
@@ -2,18 +2,16 @@ set_languages "c++23"
|
|||||||
|
|
||||||
add_rules("plugin.compile_commands.autoupdate", { outputdir = "." })
|
add_rules("plugin.compile_commands.autoupdate", { outputdir = "." })
|
||||||
|
|
||||||
add_requires("cmake::Boost", {
|
add_requires("boost", {
|
||||||
alias = "boost",
|
system = true, -- sudo pacman -S boost
|
||||||
system = true,
|
|
||||||
configs = {
|
configs = {
|
||||||
components = { "program_options", "log" },
|
all = false,
|
||||||
|
system = true, -- asio
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
target "port_scanner"
|
target "app"
|
||||||
do
|
set_kind "binary"
|
||||||
set_kind "binary"
|
add_files "src/*.cpp"
|
||||||
add_files("src/main.cpp", "src/cli/*.cpp", "src/common/*.cpp", "src/core/*.cpp")
|
add_links "boost_system"
|
||||||
add_includedirs("src", "src/cli", "src/common", "src/core", { public = true })
|
|
||||||
add_packages "boost"
|
|
||||||
end
|
|
||||||
|
|||||||
Reference in New Issue
Block a user