libertaria-stack/core/l0-transport/quarantine.zig

124 lines
3.6 KiB
Zig

// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Libertaria Contributors
// This file is part of the Libertaria Core, licensed under
// The Libertaria Commonwealth License v1.0.
//! Quarantine List - Active Defense Enforcement
//!
//! Maintains a list of locally blocked/monitored DIDs based on SlashSignals.
const std = @import("std");
/// Status of a quarantined node
pub const QuarantineStatus = enum {
None, // Not quarantined
Blocked, // Drop all traffic
Honeypot, // Accept traffic, log analysis, send fake OKs?
};
/// Airlock state for graduated network control
pub const AirlockState = enum {
Open, // Normal operation - all traffic allowed
Restricted, // Only trusted DIDs allowed
Closed, // Emergency lockdown - drop ALL traffic
};
/// Global network state (atomic for thread-safety)
pub const GlobalState = struct {
lockdown: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
airlock: AirlockState = .Open,
lockdown_since: i64 = 0,
pub fn engage(self: *GlobalState) void {
self.lockdown.store(true, .release);
self.lockdown_since = std.time.timestamp();
self.airlock = .Closed;
}
pub fn disengage(self: *GlobalState) void {
self.lockdown.store(false, .release);
self.airlock = .Open;
}
pub fn isLocked(self: *const GlobalState) bool {
return self.lockdown.load(.acquire);
}
pub fn setAirlock(self: *GlobalState, state: AirlockState) void {
self.airlock = state;
if (state == .Closed) {
self.lockdown.store(true, .release);
self.lockdown_since = std.time.timestamp();
} else if (state == .Open) {
self.lockdown.store(false, .release);
}
}
};
pub const QuarantineEntry = struct {
until_ts: i64,
mode: QuarantineStatus,
reason: u8,
};
/// High-performance blocking list
pub const QuarantineList = struct {
allocator: std.mem.Allocator,
// Using u256 to represent [32]u8 DID as key for HashMap
lookup: std.AutoHashMap(u256, QuarantineEntry),
pub fn init(allocator: std.mem.Allocator) QuarantineList {
return QuarantineList{
.allocator = allocator,
.lookup = std.AutoHashMap(u256, QuarantineEntry).init(allocator),
};
}
pub fn deinit(self: *QuarantineList) void {
self.lookup.deinit();
}
/// Add a node to quarantine
pub fn add(self: *QuarantineList, did: [32]u8, mode: QuarantineStatus, duration_sec: i64, reason: u8) !void {
const key = std.mem.readInt(u256, &did, .little);
const now = std.time.timestamp();
const entry = QuarantineEntry{
.until_ts = now + duration_sec,
.mode = mode,
.reason = reason,
};
try self.lookup.put(key, entry);
}
/// Check status of a node
pub fn check(self: *const QuarantineList, did: [32]u8) QuarantineStatus {
const key = std.mem.readInt(u256, &did, .little);
if (self.lookup.get(key)) |entry| {
const now = std.time.timestamp();
if (now > entry.until_ts) {
// Expired
return .None;
}
return entry.mode;
}
return .None;
}
};
test "quarantine list basic" {
var list = QuarantineList.init(std.testing.allocator);
defer list.deinit();
// Valid hex for u8 (0xBB)
const bad_did = [_]u8{0xBB} ** 32;
try list.add(bad_did, .Blocked, 3600, 1);
try std.testing.expectEqual(QuarantineStatus.Blocked, list.check(bad_did));
const good_did = [_]u8{0xAA} ** 32;
try std.testing.expectEqual(QuarantineStatus.None, list.check(good_did));
}