Skip to content
API Documentation
BastionGuard™
InotifyEngine Class Reference

Public Member Functions

 InotifyEngine (YaraEngine &y, DelayedScanQueue &dq, ArchiveInspector &ai)
 ~InotifyEngine ()
void add_watch (const std::string &path)
void add_recursive (const std::string &root)
bool init ()
void run ()

Private Member Functions

std::string decode_mask (uint32_t m)
void maybe_inspect_archive (const std::string &full)

Private Attributes

int in_fd = -1
std::map< int, std::string > watch_map
std::mutex map_mutex
YaraEngine & yara
DelayedScanQueue & delayed
ArchiveInspector & archive_inspector

Detailed Description

Definition at line 922 of file BastionGuard-ransomware-realtime.cpp.

Constructor & Destructor Documentation

◆ InotifyEngine()

InotifyEngine::InotifyEngine ( YaraEngine & y,
DelayedScanQueue & dq,
ArchiveInspector & ai )
inline

Definition at line 983 of file BastionGuard-ransomware-realtime.cpp.

References archive_inspector, delayed, and yara.

◆ ~InotifyEngine()

InotifyEngine::~InotifyEngine ( )
inline

Definition at line 986 of file BastionGuard-ransomware-realtime.cpp.

987 {
988 if (in_fd >= 0)
989 close(in_fd);
990 }

References in_fd.

Member Function Documentation

◆ add_recursive()

void InotifyEngine::add_recursive ( const std::string & root)
inline

Definition at line 1014 of file BastionGuard-ransomware-realtime.cpp.

1015 {
1016 std::error_code ec;
1017
1018 if (is_excluded_path(root)) {
1019 log_msg(_("SKIP: directory esclusa dal realtime: ") + root);
1020 return;
1021 }
1022
1023 if (!std::filesystem::exists(root, ec) || ec) {
1024 log_msg("SKIP: " + root + _(" non accessibile"));
1025 return;
1026 }
1027
1028 add_watch(root);
1029
1030 for (auto it = std::filesystem::recursive_directory_iterator(
1031 root,
1032 std::filesystem::directory_options::skip_permission_denied,
1033 ec);
1034 it != std::filesystem::recursive_directory_iterator();
1035 it.increment(ec))
1036 {
1037 if (ec) {
1038 ec.clear();
1039 continue;
1040 }
1041
1042 const auto& entry = *it;
1043 const std::string entry_path = entry.path().string();
1044
1045 if (is_excluded_path(entry_path)) {
1046 std::error_code type_ec;
1047 if (entry.is_directory(type_ec) && !type_ec)
1048 it.disable_recursion_pending();
1049 continue;
1050 }
1051
1052 ec.clear();
1053 if (entry.is_directory(ec) && !ec) {
1054 add_watch(entry_path);
1055 }
1056 }
1057 }
#define _(s)
static bool is_excluded_path(const std::string &path)
void log_msg(const std::string &msg)
void add_watch(const std::string &path)

References _, add_watch(), is_excluded_path(), and log_msg().

Referenced by init().

◆ add_watch()

void InotifyEngine::add_watch ( const std::string & path)
inline

Definition at line 992 of file BastionGuard-ransomware-realtime.cpp.

993 {
994 if (in_fd < 0)
995 return;
996
997 int wd = inotify_add_watch(
998 in_fd,
999 path.c_str(),
1000 IN_CREATE | IN_CLOSE_WRITE | IN_MODIFY |
1001 IN_MOVED_TO | IN_MOVED_FROM | IN_ATTRIB |
1002 IN_DELETE | IN_DELETE_SELF | IN_ISDIR
1003 );
1004
1005 if (wd >= 0) {
1006 std::lock_guard<std::mutex> lock(map_mutex);
1007 watch_map[wd] = path;
1008 log_msg("WATCH aggiunto: " + path);
1009 } else {
1010 log_msg("WATCH fallito: " + path + " | errno=" + std::to_string(errno));
1011 }
1012 }
std::map< int, std::string > watch_map

References in_fd, log_msg(), map_mutex, and watch_map.

Referenced by add_recursive(), and run().

◆ decode_mask()

std::string InotifyEngine::decode_mask ( uint32_t m)
inlineprivate

Definition at line 932 of file BastionGuard-ransomware-realtime.cpp.

933 {
934 std::stringstream ss;
935 if (m & IN_CREATE) ss << "CREATE ";
936 if (m & IN_CLOSE_WRITE) ss << "CLOSE_WRITE ";
937 if (m & IN_MODIFY) ss << "MODIFY ";
938 if (m & IN_MOVED_TO) ss << "MOVED_TO ";
939 if (m & IN_MOVED_FROM) ss << "MOVED_FROM ";
940 if (m & IN_ATTRIB) ss << "ATTRIB ";
941 if (m & IN_DELETE) ss << "DELETE ";
942 if (m & IN_DELETE_SELF) ss << "DELETE_SELF ";
943 if (m & IN_ISDIR) ss << "ISDIR ";
944 return ss.str();
945 }

Referenced by run().

◆ init()

bool InotifyEngine::init ( )
inline

Definition at line 1059 of file BastionGuard-ransomware-realtime.cpp.

1060 {
1061 in_fd = inotify_init1(IN_NONBLOCK);
1062 if (in_fd < 0)
1063 return false;
1064
1065 for (const auto& d : WATCH_DIRS)
1066 add_recursive(d);
1067
1068 return true;
1069 }
static std::vector< std::string > WATCH_DIRS
void add_recursive(const std::string &root)

References add_recursive(), in_fd, and WATCH_DIRS.

Referenced by main().

◆ maybe_inspect_archive()

void InotifyEngine::maybe_inspect_archive ( const std::string & full)
inlineprivate

Definition at line 947 of file BastionGuard-ransomware-realtime.cpp.

948 {
949 if (!looks_like_archive_path(full))
950 return;
951
952 if (!is_regular_file_safe(full))
953 return;
954
955 ArchiveInspectionResult ar = archive_inspector.inspect(full);
956
957 log_archive_result(full, ar);
958
959 if (!ar.success) {
960 log_msg(_("ArchiveInspector fallito su: ") + full +
961 " | " + ar.reason_code + " | " + ar.detail);
962 return;
963 }
964
965 if (!ar.is_zip)
966 return;
967
968 if (ar.risk != ArchiveRisk::CLEAN) {
969 std::stringstream ss;
970 ss << "ARCHIVE THREAT SIGNAL: "
971 << full
972 << " risk=" << archiveRiskToString(ar.risk)
973 << " score=" << ar.risk_score
974 << " reason=" << ar.reason_code
975 << " detail=" << ar.detail;
976 log_msg(ss.str());
977
978 send_archive_alert(full, ar);
979 }
980 }
const char * archiveRiskToString(ArchiveRisk risk)
static void send_archive_alert(const std::string &file, const ArchiveInspectionResult &ar)
static void log_archive_result(const std::string &path, const ArchiveInspectionResult &ar)
static bool looks_like_archive_path(const std::string &path)
static bool is_regular_file_safe(const std::string &path)
ArchiveInspectionResult inspect(const std::string &input_path) const

References _, archive_inspector, archiveRiskToString(), CLEAN, ArchiveInspectionResult::detail, ArchiveInspector::inspect(), is_regular_file_safe(), ArchiveInspectionResult::is_zip, log_archive_result(), log_msg(), looks_like_archive_path(), ArchiveInspectionResult::reason_code, ArchiveInspectionResult::risk, ArchiveInspectionResult::risk_score, send_archive_alert(), and ArchiveInspectionResult::success.

Referenced by run().

◆ run()

void InotifyEngine::run ( )
inline

Definition at line 1071 of file BastionGuard-ransomware-realtime.cpp.

1072 {
1073 char buf[16384] __attribute__((aligned(8)));
1074
1075 while (running) {
1076 int len = read(in_fd, buf, sizeof(buf));
1077 if (len <= 0) {
1078 std::this_thread::sleep_for(std::chrono::milliseconds(25));
1079 continue;
1080 }
1081
1082 int i = 0;
1083 while (i < len) {
1084 auto* ev = (struct inotify_event*)&buf[i];
1085 std::string dir;
1086
1087 {
1088 std::lock_guard<std::mutex> lock(map_mutex);
1089 if (watch_map.count(ev->wd))
1090 dir = watch_map[ev->wd];
1091 }
1092
1093 if (!dir.empty() && ev->len > 0) {
1094 std::string full = dir + "/" + ev->name;
1095
1096 if (is_excluded_path(full)) {
1097 log_msg(_("INOTIFY IGNORATO: percorso escluso: ") + full);
1098 i += sizeof(struct inotify_event) + ev->len;
1099 continue;
1100 }
1101
1102 log_msg("INOTIFY EVENT: " + full + " [" +
1103 decode_mask(ev->mask) + "]");
1104
1105 if (ev->mask & IN_ISDIR) {
1106 add_watch(full);
1107 i += sizeof(struct inotify_event) + ev->len;
1108 continue;
1109 }
1110
1111 bool file_event =
1112 (ev->mask & (IN_CREATE |
1113 IN_CLOSE_WRITE |
1114 IN_MODIFY |
1115 IN_MOVED_TO |
1116 IN_DELETE_SELF |
1117 IN_ATTRIB));
1118
1119 if (!file_event) {
1120 i += sizeof(struct inotify_event) + ev->len;
1121 continue;
1122 }
1123
1124 bool atomic_rename =
1125 (ev->mask & IN_MOVED_TO) &&
1126 !(ev->mask & IN_CREATE);
1127
1128 if (atomic_rename) {
1129 log_msg(_("ATOMIC RENAME rilevato → ") + full);
1130 }
1131
1132 const bool writer_event =
1133 (ev->mask & IN_CLOSE_WRITE) ||
1134 (ev->mask & IN_MOVED_TO);
1135
1136 if (writer_event) {
1137 if (should_guess_pid(full, 600)) {
1138 pid_t pid = guess_writer_pid(full);
1139 if (pid > 0) {
1140 yara.scan_pid(pid);
1141 }
1142 }
1143
1145 yara.scan_file(full);
1146 delayed.enqueue(full);
1147 }
1148 }
1149
1150 i += sizeof(struct inotify_event) + ev->len;
1151 }
1152 }
1153 }
static bool should_guess_pid(const std::string &path, long long min_interval_ms=500)
static pid_t guess_writer_pid(const std::string &path)
static std::atomic< bool > running(true)
void enqueue(const std::string &path, int delay_ms=30000)
std::string decode_mask(uint32_t m)
void maybe_inspect_archive(const std::string &full)
bool scan_file(const std::string &path)

References _, add_watch(), decode_mask(), delayed, DelayedScanQueue::enqueue(), guess_writer_pid(), in_fd, is_excluded_path(), log_msg(), map_mutex, maybe_inspect_archive(), running(), YaraEngine::scan_file(), YaraEngine::scan_pid(), should_guess_pid(), watch_map, and yara.

Referenced by main().

Member Data Documentation

◆ archive_inspector

ArchiveInspector& InotifyEngine::archive_inspector
private

Definition at line 930 of file BastionGuard-ransomware-realtime.cpp.

Referenced by InotifyEngine(), and maybe_inspect_archive().

◆ delayed

DelayedScanQueue& InotifyEngine::delayed
private

Definition at line 929 of file BastionGuard-ransomware-realtime.cpp.

Referenced by InotifyEngine(), and run().

◆ in_fd

int InotifyEngine::in_fd = -1
private

Definition at line 924 of file BastionGuard-ransomware-realtime.cpp.

Referenced by add_watch(), init(), run(), and ~InotifyEngine().

◆ map_mutex

std::mutex InotifyEngine::map_mutex
private

Definition at line 926 of file BastionGuard-ransomware-realtime.cpp.

Referenced by add_watch(), and run().

◆ watch_map

std::map<int, std::string> InotifyEngine::watch_map
private

Definition at line 925 of file BastionGuard-ransomware-realtime.cpp.

Referenced by add_watch(), and run().

◆ yara

YaraEngine& InotifyEngine::yara
private

Definition at line 928 of file BastionGuard-ransomware-realtime.cpp.

Referenced by InotifyEngine(), and run().


The documentation for this class was generated from the following file: