22 auto slash = str.find(
'/');
24 (slash != std::string::npos) ? str.substr(0, slash) : str;
26 if (inet_pton(AF_INET, ip_str.c_str(), &result.ip) != 1)
27 throw std::invalid_argument(
"invalid IP address: " + ip_str);
29 if (slash != std::string::npos) {
30 unsigned long pl = std::stoul(str.substr(slash + 1));
32 throw std::invalid_argument(
"invalid prefix length: " +
34 result.prefixlen =
static_cast<uint32_t
>(pl);
35 result.ip &= htonl(pl == 0 ? 0 : (0xFFFFFFFFu << (32 - pl)));
125static bool MatchesCIDR(uint32_t ip,
const std::string &cidr_str) {
126 auto slash = cidr_str.find(
'/');
127 if (slash == std::string::npos)
131 if (inet_pton(AF_INET, cidr_str.substr(0, slash).c_str(), &cidr_ip) != 1)
134 unsigned long pl = std::stoul(cidr_str.substr(slash + 1));
138 uint32_t mask = htonl(pl == 0 ? 0 : (0xFFFFFFFFu << (32 - pl)));
139 return (ip & mask) == (cidr_ip & mask);
151 const std::string sql =
152 "UPDATE blocked_ips SET last_blocked_at = datetime('now') WHERE ip = ?";
153 sqlite3_stmt *stmt =
nullptr;
154 if (sqlite3_prepare_v2(
db_, sql.c_str(), -1, &stmt,
nullptr) == SQLITE_OK) {
155 sqlite3_bind_text(stmt, 1, ip_str.c_str(), -1, SQLITE_TRANSIENT);
157 sqlite3_finalize(stmt);
163 const std::string sql =
"SELECT ip FROM blocked_ips WHERE ip LIKE '%/%'";
164 sqlite3_stmt *stmt =
nullptr;
165 if (sqlite3_prepare_v2(
db_, sql.c_str(), -1, &stmt,
nullptr) != SQLITE_OK)
168 std::vector<std::string> matching;
169 while (sqlite3_step(stmt) == SQLITE_ROW) {
170 const char *cidr_str =
171 reinterpret_cast<const char *
>(sqlite3_column_text(stmt, 0));
173 matching.emplace_back(cidr_str);
175 sqlite3_finalize(stmt);
177 for (
const auto &cidr : matching) {
178 const std::string upd =
"UPDATE blocked_ips SET last_blocked_at = "
179 "datetime('now') WHERE ip = ?";
180 sqlite3_stmt *us =
nullptr;
181 if (sqlite3_prepare_v2(
db_, upd.c_str(), -1, &us,
nullptr) == SQLITE_OK) {
182 sqlite3_bind_text(us, 1, cidr.c_str(), -1, SQLITE_TRANSIENT);
184 sqlite3_finalize(us);