Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7efd5cbce5 | |||
| 0e8d77971d | |||
| 025f49a5fd | |||
| 902959f658 | |||
| fcbf6c740c |
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
PortScanCli::PortScanCli()
|
PortScanCli::PortScanCli()
|
||||||
: CliBase("Port Scanner Options")
|
: CliBase("Port Scanner Options")
|
||||||
, ip_("")
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,14 +12,17 @@ void PortScanCli::setupOptions()
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
desc_.add_options()
|
desc_.add_options()
|
||||||
("help,h", "Show help")
|
("help,h", "Show help")
|
||||||
("ip,H", withDefault(ip_, "<IP>"), "Local IPv4 to scan");
|
("ip,H", withDefault(ip_, "<IPv4>"), "Base IPv4 inside your LAN (e.g. 10.0.1.42)")
|
||||||
|
("prefix,p", withDefault(prefix_, "<0..32>"), "CIDR prefix length (e.g. 24)");
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PortScanCli::getIp() const
|
int PortScanCli::getPrefix() const
|
||||||
{
|
{
|
||||||
if (vm_["ip"].empty() == 0) {
|
return vm_.at("prefix").as<int>();
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string PortScanCli::getBaseIp() const
|
||||||
|
{
|
||||||
return vm_.at("ip").as<std::string>();
|
return vm_.at("ip").as<std::string>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ class PortScanCli : public CliBase, protected OptionUtils
|
|||||||
public:
|
public:
|
||||||
PortScanCli();
|
PortScanCli();
|
||||||
|
|
||||||
std::string getIp() const;
|
int getPrefix() const;
|
||||||
|
std::string getBaseIp() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setupOptions() override;
|
void setupOptions() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ip_;
|
int prefix_{24};
|
||||||
|
std::string ip_{"10.0.1.0"};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#include "local_ping_scanner.hpp"
|
||||||
|
#include "logger.hpp"
|
||||||
|
#include <Poco/Net/ICMPClient.h>
|
||||||
|
#include <boost/asio/ip/address_v4.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
LocalPingScanner::LocalPingScanner(
|
||||||
|
const std::string &baseIp, int prefixLen, int timeoutMs
|
||||||
|
)
|
||||||
|
: baseIp_(baseIp)
|
||||||
|
, prefixLen_(prefixLen)
|
||||||
|
, timeoutMs_(timeoutMs)
|
||||||
|
{
|
||||||
|
if (prefixLen_ < 0 || prefixLen_ > 32) {
|
||||||
|
Logger::error("Invalid prefix length in LocalPingScanner constructor");
|
||||||
|
throw std::runtime_error("Bad prefix length");
|
||||||
|
}
|
||||||
|
if (timeoutMs_ <= 0) {
|
||||||
|
timeoutMs_ = 2000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> &LocalPingScanner::alive() const
|
||||||
|
{
|
||||||
|
return alive_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t LocalPingScanner::ipToU32(const std::string &ip)
|
||||||
|
{
|
||||||
|
using namespace boost::asio::ip;
|
||||||
|
return static_cast<uint32_t>(make_address_v4(ip).to_uint());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LocalPingScanner::u32ToIp(uint32_t v)
|
||||||
|
{
|
||||||
|
using namespace boost::asio::ip;
|
||||||
|
return address_v4(v).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalPingScanner::pingHost(const std::string &ip) const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return Poco::Net::ICMPClient::pingIPv4(
|
||||||
|
ip,
|
||||||
|
/*repeat=*/1,
|
||||||
|
/*dataSize=*/48,
|
||||||
|
/*ttl=*/64,
|
||||||
|
/*timeout=*/timeoutMs_
|
||||||
|
)
|
||||||
|
> 0;
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
Logger::error(
|
||||||
|
std::string("Ping failed for host ") + ip + ": " + ex.what()
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
Logger::fatal(std::string("Unknown error pinging host ") + ip);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalPingScanner::runImpl()
|
||||||
|
{
|
||||||
|
alive_.clear();
|
||||||
|
|
||||||
|
const uint32_t base = ipToU32(baseIp_);
|
||||||
|
const uint32_t mask =
|
||||||
|
(prefixLen_ == 0) ? 0u : (0xFFFFFFFFu << (32 - prefixLen_));
|
||||||
|
const uint32_t network = base & mask;
|
||||||
|
const uint32_t broadcast = network | (~mask);
|
||||||
|
|
||||||
|
// No hosts when prefix is too tight (e.g., /32).
|
||||||
|
if (broadcast - network <= 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string selfIp = u32ToIp(base);
|
||||||
|
|
||||||
|
for (uint32_t v = network + 1; v < broadcast; ++v) {
|
||||||
|
const std::string ipStr = u32ToIp(v);
|
||||||
|
|
||||||
|
if (ipStr == selfIp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pingHost(ipStr)) {
|
||||||
|
alive_.push_back(ipStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalPingScanner::run()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
runImpl();
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
Logger::error(
|
||||||
|
std::string("Exception in LocalPingScanner::run: ") + ex.what()
|
||||||
|
);
|
||||||
|
} catch (...) {
|
||||||
|
Logger::fatal("Unknown exception in LocalPingScanner::run");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class LocalPingScanner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocalPingScanner(
|
||||||
|
const std::string &baseIp, int prefixLen, int timeoutMs = 2000
|
||||||
|
);
|
||||||
|
|
||||||
|
void run(); // blocking scan over subnet
|
||||||
|
const std::vector<std::string> &alive() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string u32ToIp(uint32_t v);
|
||||||
|
static uint32_t ipToU32(const std::string &ip);
|
||||||
|
bool pingHost(const std::string &ip) const;
|
||||||
|
void runImpl();
|
||||||
|
|
||||||
|
std::string baseIp_;
|
||||||
|
int prefixLen_;
|
||||||
|
int timeoutMs_;
|
||||||
|
std::vector<std::string> alive_;
|
||||||
|
};
|
||||||
+86
-102
@@ -1,142 +1,126 @@
|
|||||||
#include "port_scanner.hpp"
|
#include "port_scanner.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include <boost/asio.hpp>
|
#include <algorithm>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
PortScanner::PortScanner(
|
PortScanner::PortScanner(std::string ip, int timeoutMs)
|
||||||
const std::string &ip, const std::vector<uint16_t> &ports
|
: ip_(std::move(ip))
|
||||||
)
|
, timeoutMs_(timeoutMs)
|
||||||
: ports_(ports)
|
|
||||||
{
|
{
|
||||||
ErrorCode ec;
|
if (timeoutMs_ <= 0) {
|
||||||
addr_ = boost::asio::ip::make_address(ip, ec);
|
timeoutMs_ = 250;
|
||||||
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)
|
PortScanner::Probe::Probe(IoContext &io, uint16_t p)
|
||||||
|
: port(p)
|
||||||
|
, socket(io)
|
||||||
|
, timer(io)
|
||||||
{
|
{
|
||||||
if (ms > 0) {
|
|
||||||
timeout_ms_ = ms;
|
|
||||||
Logger::debug(
|
|
||||||
std::string("PortScanner: timeout set to ")
|
|
||||||
+ std::to_string(timeout_ms_) + " ms"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<uint16_t> &PortScanner::openPorts() const
|
||||||
|
{
|
||||||
|
return openPorts_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortScanner::run()
|
void PortScanner::run()
|
||||||
{
|
{
|
||||||
if (!ip_ok_) {
|
openPorts_.clear();
|
||||||
Logger::error("PortScanner::run - aborting: ip not ok");
|
nextPort_ = kFirstPort;
|
||||||
|
outstanding_ = 0;
|
||||||
|
active_.clear();
|
||||||
|
|
||||||
|
while (outstanding_ < kMaxConcurrency && nextPort_ <= kLastPort) {
|
||||||
|
startNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
io_.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortScanner::startNext()
|
||||||
|
{
|
||||||
|
if (nextPort_ > kLastPort) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (uint16_t p : ports_) {
|
|
||||||
if (probe(p)) {
|
const uint16_t port = static_cast<uint16_t>(nextPort_);
|
||||||
Logger::info(std::to_string(p));
|
nextPort_ += 1;
|
||||||
}
|
|
||||||
}
|
startProbe(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PortScanner::probe(uint16_t port)
|
void PortScanner::startProbe(uint16_t port)
|
||||||
{
|
{
|
||||||
TcpSocket s(io_);
|
// Lifetime of Probe is managed in 'active_' until probe finishes.
|
||||||
SteadyTimer t(io_);
|
auto prPtr = std::make_unique<Probe>(io_, port);
|
||||||
auto ep = endpoint(port);
|
Probe *pr = prPtr.get();
|
||||||
|
active_.push_back(std::move(prPtr));
|
||||||
|
|
||||||
Logger::debug(
|
outstanding_ += 1;
|
||||||
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);
|
using namespace boost::asio::ip;
|
||||||
}
|
|
||||||
|
|
||||||
void PortScanner::armTimer(SteadyTimer &t, TcpSocket &s)
|
TcpEndpoint ep(make_address_v4(ip_), port);
|
||||||
{
|
|
||||||
t.expires_after(std::chrono::milliseconds(timeout_ms_));
|
|
||||||
|
|
||||||
auto onTimeout = [&s](const ErrorCode &ec) {
|
pr->timer.expires_after(std::chrono::milliseconds(timeoutMs_));
|
||||||
|
|
||||||
|
auto onTimer = [pr](const ErrorCode &ec) {
|
||||||
|
// Cancel socket on timeout; completion will run onConnect with
|
||||||
|
// ec=operation_aborted.
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
Logger::debug("Timer expired -> cancelling socket");
|
pr->socket.cancel();
|
||||||
s.cancel();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
t.async_wait(onTimeout);
|
auto onAsyncConnect = [this, pr](const ErrorCode &ec) {
|
||||||
}
|
onConnect(pr, ec);
|
||||||
|
|
||||||
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);
|
pr->timer.async_wait(onTimer);
|
||||||
}
|
pr->socket.async_connect(ep, onAsyncConnect);
|
||||||
|
|
||||||
void PortScanner::runUntilDone()
|
|
||||||
{
|
|
||||||
io_.restart();
|
|
||||||
while (!done_ && io_.run_one()) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortScanner::cancelTimer(SteadyTimer &t)
|
void PortScanner::onConnect(Probe *pr, const ErrorCode &ec)
|
||||||
{
|
{
|
||||||
ErrorCode ec;
|
pr->timer.cancel();
|
||||||
t.cancel();
|
|
||||||
if (ec) {
|
// Open if connect succeeded; REFUSED means closed but host is alive.
|
||||||
Logger::warn(std::string("cancelTimer: ") + ec.message());
|
if (!ec) {
|
||||||
}
|
openPorts_.push_back(pr->port);
|
||||||
|
Logger::info(std::string("Open port: ") + std::to_string(pr->port));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortScanner::drainLeftovers()
|
ErrorCode ignored;
|
||||||
{
|
pr->socket.close(ignored);
|
||||||
io_.restart();
|
|
||||||
while (io_.run_one()) {
|
finishProbe(pr);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortScanner::close(TcpSocket &s)
|
void PortScanner::finishProbe(Probe *pr)
|
||||||
{
|
{
|
||||||
ErrorCode ig;
|
if (outstanding_ > 0) {
|
||||||
if (s.close(ig)) {
|
outstanding_ -= 1;
|
||||||
Logger::warn(std::string("close socket failed: ") + ig.message());
|
}
|
||||||
|
|
||||||
|
// Remove 'pr' from active_ (active_ size <= kMaxConcurrency, linear
|
||||||
|
// erase is fine).
|
||||||
|
auto it = std::find_if(
|
||||||
|
active_.begin(), active_.end(), [pr](const std::unique_ptr<Probe> &u) {
|
||||||
|
return u.get() == pr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (it != active_.end()) {
|
||||||
|
active_.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextPort_ <= kLastPort) {
|
||||||
|
startNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outstanding_ == 0 && nextPort_ > kLastPort) {
|
||||||
|
io_.stop();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-23
@@ -1,37 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "aliases.hpp"
|
#include "aliases.hpp"
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class PortScanner
|
class PortScanner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PortScanner(const std::string &ip, const std::vector<uint16_t> &ports);
|
explicit PortScanner(std::string ip, int timeoutMs = 250);
|
||||||
|
|
||||||
void setTimeoutMs(int ms);
|
void run(); // blocking scan
|
||||||
|
const std::vector<uint16_t> &openPorts() const;
|
||||||
void run();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool probe(uint16_t port);
|
struct Probe {
|
||||||
TcpEndpoint endpoint(uint16_t port) const;
|
uint16_t port{0};
|
||||||
|
TcpSocket socket;
|
||||||
|
SteadyTimer timer;
|
||||||
|
|
||||||
void armTimer(SteadyTimer &t, TcpSocket &s);
|
Probe(IoContext &io, uint16_t p);
|
||||||
void armConnect(TcpSocket &s, const TcpEndpoint &ep);
|
};
|
||||||
void runUntilDone();
|
|
||||||
void cancelTimer(SteadyTimer &t);
|
void startNext();
|
||||||
void drainLeftovers();
|
void startProbe(uint16_t port);
|
||||||
void close(TcpSocket &s);
|
void onConnect(Probe *pr, const ErrorCode &ec);
|
||||||
|
void finishProbe(Probe *pr);
|
||||||
private:
|
|
||||||
IoContext io_;
|
// Fixed settings
|
||||||
IpAddress addr_;
|
static constexpr uint16_t kFirstPort = 1;
|
||||||
std::vector<uint16_t> ports_;
|
static constexpr uint16_t kLastPort = 65535;
|
||||||
|
static constexpr std::size_t kMaxConcurrency = 256;
|
||||||
int timeout_ms_{300};
|
|
||||||
bool ip_ok_{false};
|
// State
|
||||||
bool ok_{false};
|
std::string ip_;
|
||||||
bool done_{false};
|
IoContext io_;
|
||||||
|
std::vector<uint16_t> openPorts_;
|
||||||
|
std::vector<std::unique_ptr<Probe>> active_; // <= kMaxConcurrency
|
||||||
|
uint32_t nextPort_{kFirstPort};
|
||||||
|
std::size_t outstanding_{0};
|
||||||
|
int timeoutMs_;
|
||||||
};
|
};
|
||||||
|
|||||||
+41
-18
@@ -1,20 +1,8 @@
|
|||||||
#include "cli_base.hpp"
|
#include "local_ping_scanner.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "port_scanner.hpp"
|
#include "port_scanner.hpp"
|
||||||
#include "portscan_cli.hpp"
|
#include "portscan_cli.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
static std::vector<uint16_t> allPorts()
|
|
||||||
{
|
|
||||||
std::vector<uint16_t> v;
|
|
||||||
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -27,12 +15,47 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string ip = cli.getIp();
|
const std::string baseIp = cli.getBaseIp();
|
||||||
auto ports = allPorts();
|
|
||||||
|
const int prefix = cli.getPrefix();
|
||||||
|
if (prefix < 0 || prefix > 32) {
|
||||||
|
Logger::fatal("Prefix must be in range 0..32\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalPingScanner scanner(baseIp, prefix);
|
||||||
|
Logger::info(std::format("Scanning subnet: {}/{}", baseIp, prefix));
|
||||||
|
|
||||||
Logger::info("Starting full port scan (1..65535)...");
|
|
||||||
PortScanner scanner(ip, ports);
|
|
||||||
scanner.run();
|
scanner.run();
|
||||||
Logger::info("Scan completed.");
|
|
||||||
|
const auto &alive = scanner.alive();
|
||||||
|
if (alive.empty()) {
|
||||||
|
Logger::info("No alive hosts found.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Alive hosts:\n";
|
||||||
|
for (const auto &ip : alive) {
|
||||||
|
std::cout << " " << ip << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each alive host, run full TCP port scan
|
||||||
|
for (const auto &ip : alive) {
|
||||||
|
std::cout << "Scanning ports on " << ip << " ...\n";
|
||||||
|
|
||||||
|
PortScanner ps(ip);
|
||||||
|
ps.run();
|
||||||
|
|
||||||
|
const auto &open = ps.openPorts();
|
||||||
|
if (open.empty()) {
|
||||||
|
std::cout << " No open TCP ports found on " << ip << "\n";
|
||||||
|
} else {
|
||||||
|
std::cout << " Open ports on " << ip << ":\n";
|
||||||
|
for (uint16_t port : open) {
|
||||||
|
std::cout << " " << port << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,18 @@ add_requires("cmake::Boost", {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
add_requires("cmake::Poco", {
|
||||||
|
alias = "poco",
|
||||||
|
system = true,
|
||||||
|
configs = {
|
||||||
|
components = { "Net", "Foundation" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
target "port_scanner"
|
target "port_scanner"
|
||||||
do
|
do
|
||||||
set_kind "binary"
|
set_kind "binary"
|
||||||
add_files("src/main.cpp", "src/cli/*.cpp", "src/common/*.cpp", "src/core/*.cpp")
|
add_files("src/main.cpp", "src/cli/*.cpp", "src/common/*.cpp", "src/core/*.cpp")
|
||||||
add_includedirs("src", "src/cli", "src/common", "src/core", { public = true })
|
add_includedirs("src", "src/cli", "src/common", "src/core", { public = true })
|
||||||
add_packages "boost"
|
add_packages("boost", "poco")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user