Releases: 01rabbit/Azazel-Pi
v3.2.0
What's Changed
- chore: centralize subprocess execution to cmd_runner.run by @01rabbit in #9
- [WIP] Fix error in CL functionality by @Copilot in #10
- [WIP] Update README_ja.md for consistent context by @Copilot in #11
- Automate /opt↔repo sync, protect installers from overwrites, and add systemd unit by @01rabbit in #12
New Contributors
- @Copilot made their first contribution in #10
Full Changelog: v3.1.0...v3.2.0
[3.1.0] - 2025-11-09
Added
- Display: clear and force a full E-Paper refresh when the active WAN interface changes (e.g. eth0 -> wlan1) to avoid ghosting and show the updated interface/IP immediately. (commit 478b8ee)
- Status collection: prefer kernel default route when runtime WAN state is missing and provide a
wan_state_pathinjection point for testing/overrides. - Renderer: improve network line formatting by removing the redundant "WAN" prefix and suppressing non-actionable "[WAN] unknown" messages; reserve footer area to prevent text overlap.
Changed
- Backwards-compatible
StatusCollectorinitialization handling inepd_daemon— older installs without the newwan_state_pathparameter are tolerated.
Notes
- These are backward-compatible improvements (minor release). See commit 478b8ee for details and files changed:
azazel_pi/core/display/status_collector.py,epd_daemon.py,renderer.py.- Suricata integration for network threat detection
- AI-based threat evaluation pipeline and scoring
- Basic TUI and CLI utilities for status and control
- Initial installer and documentation to deploy core services
v3.0.0 — EPD integration, redesigned display UI and startup reliability improvements
[3.0.0] - 2025-11-09
EPD (e-paper) integration, redesigned display UI, and startup reliability improvements.
Added
- Full E-Paper (EPD) integration with the Azazel-Pi platform.
- New renderer and display pipeline for EPD devices.
EPD_SKIP_BOOT_ANIMsupport to skip the boot animation when desired.scripts/epd_hello.pyincluded for quick EPD smoke-tests and verification.
- Configurable periodic full-refresh to reduce e-paper ghosting (
--full-refresh-minutes). - Local timezone display: convert
StatusCollectortimestamps from UTC to the system local timezone for correct local time presentation on the E-Paper.
Changed
- Major UX/visual changes for the E-Paper display (layout and formatting updates).
- Renderer startup sequence improved:
- Attempt
driver.init()before display to wake hardware from sleep. - Increased startup delay and avoid
sleep()after boot animation so SPI handle remains open.
- Attempt
- Retry logic for transient SPI/GPIO errors added to improve robustness on flaky hardware.
systemdservice and deployment improvements (drop-in/override provided for more reliable start-up and environment handling).- Allow shell expansion for environment defaults in service unit files where applicable.
Fixed
- Local time offset when displaying timestamps on the E-Paper fixed by converting UTC timestamps to the system local timezone before formatting.
- Various startup race conditions mitigated by adjusting initialization order and delays.
Notes
- This is a major release (3.0.0) because it introduces a new, visible feature (EPD integration) and significant UI/behavior changes that add new concepts to the product.
- Backwards compatibility: runtime behavior for systems without EPD hardware is preserved. EPD integration is opt-in via installer flags (
--enable-epd,--epd-emulate,--epd-force) and environment variables. - To provision the EPD host Wi-Fi during install, set
EPD_WIFI_SSIDandEPD_WIFI_PSKenv vars when runningscripts/install_azazel_complete.sh.
Upgrade / Deployment
- If you use the installer, run with
--enable-epdto include EPD integration and optionally--epd-emulatefor emulation mode. - If enabling EPD on a device with SPI hardware, ensure SPI is enabled in the device firmware (e.g.
dtparam=spi=onin/boot/config.txt) and reboot if required. - After deployment, verify:
- EPD daemon (
azazel-epd.service) status usingsystemctl status azazel-epd.service. - Local time is displayed correctly on the E-Paper.
- Full-refresh occurs at the configured interval if enabled.
- EPD daemon (
Testing / Verification
- Deploy to a test device with EPD hardware or run with
--epd-emulateto validate display behavior. - Run
scripts/epd_hello.pyto confirm renderer availability. - Review systemd logs:
journalctl -u azazel-epd.service -n 200 --no-pager.
Related
- PR: feature/epd-improvements
- Closes: #4
For detailed developer notes and installation steps, see PR_DESCRIPTION.md in the repository root and docs/ENHANCED_AI_INTEGRATION.md / docs/OLLAMA_INTEGRATION_REPORT.md for related AI changes.
v2.2.0: Internal Network QoS Control
Release v2.2.0: Internal Network QoS Control
🎯 Overview
Version 2.2.0 introduces comprehensive Internal Network QoS (Quality of Service) Control for privilege-based traffic shaping and security enforcement within the LAN. This feature enables differentiated bandwidth allocation, MAC address verification, and ARP spoofing protection for trusted devices.
✨ Major Features
1. Mark-Based Traffic Classification
- Premium (0x10): High-priority devices with guaranteed bandwidth
- Standard (0x20): Normal priority for regular devices
- Best Effort (0x30): Default class for unclassified traffic
- Restricted (0x40): Limited bandwidth for suspicious/untrusted devices
2. Three Security Modes
- none: Marking only, no enforcement (safe testing mode)
- verify: Drop packets from privileged IPs with mismatched MAC addresses
- lock: verify mode + static ARP entries to prevent spoofing
3. Dynamic Priority Adjustment
- Score-based automatic class reassignment
- Configurable thresholds and bias factors
- Optional daemon (
azazel_priorityd) for continuous evaluation
4. HTB Traffic Shaping
- Hierarchical Token Bucket (HTB) implementation using
tc - Per-class rate/ceil configuration via YAML
- Idempotent initialization (safe to re-run)
🔧 New Components
Scripts
bin/azazel-traffic-init.sh: Initialize tc HTB classes and nftables infrastructurebin/azazel-qos-apply.sh: Apply privilege-based rules from CSV with mode selectionbin/azazel-qos-menu.sh: Interactive TUI for privileged host management
Services
services/azazel_priorityd.py: Dynamic priority daemon with score-based logicsystemd/azazel-traffic-init.service: One-shot init servicesystemd/azazel-qos-apply.service: One-shot apply servicesystemd/azazel-priorityd.service: Long-running daemon service
Configuration
configs/network/privileged.csv: Authoritative list of premium hosts (IP, MAC, note)configs/network/azazel.yaml: Extended with QoS config (marks, classes, thresholds)
Python Module
azazel_pi/core/network/internal_control.py: InternalControlManager for zone management
Documentation
docs/INTERNAL_NETWORK_CONTROL.md: Architecture and design decisionsdocs/QOS_TESTING.md: Testing guide with DRY_RUN results
📋 Configuration Example
privileged.csv:
# IP,MAC,Note
172.16.0.10,aa:bb:cc:dd:ee:ff,Admin workstation
172.16.0.11,00:11:22:33:44:55,IoT controllerazazel.yaml (extended):
mark_map:
premium: 0x10
standard: 0x20
best_effort: 0x30
restricted: 0x40
classes:
premium:
rate: 10000kbit
ceil: 10000kbit
standard:
rate: 5000kbit
ceil: 8000kbit
best_effort:
rate: 2000kbit
ceil: 5000kbit
restricted:
rate: 500kbit
ceil: 1000kbit
thresholds:
premium: 80
standard: 50
best_effort: 20
dynamic_bias:
base: 100
factor: 1.0🚀 Usage
Manual Operation
# Initialize tc/nft infrastructure (one-time)
sudo bin/azazel-traffic-init.sh configs/network/azazel.yaml
# Apply privileged host rules (verify mode)
sudo MODE=verify bin/azazel-qos-apply.sh configs/network/privileged.csv
# Interactive management
sudo bin/azazel-qos-menu.shSystemD Integration
# Enable services
sudo systemctl enable azazel-traffic-init.service
sudo systemctl enable azazel-qos-apply.service
sudo systemctl enable azazel-priorityd.service # optional
# Start services
sudo systemctl start azazel-traffic-init.service
sudo systemctl start azazel-qos-apply.serviceDRY_RUN Mode (Safe Testing)
# Test command generation without execution (no root required)
DRY_RUN=1 bin/azazel-traffic-init.sh configs/network/azazel.yaml
DRY_RUN=1 MODE=verify bin/azazel-qos-apply.sh configs/network/privileged.csv
DRY_RUN=1 MODE=lock bin/azazel-qos-apply.sh configs/network/privileged.csv🔒 Security Features
- MAC Verification: Prevents ARP spoofing for privileged devices
- Static ARP: Lock mode provides additional anti-spoofing protection
- Gradual Rollout: Safe deployment path (none → verify → lock)
- DRY_RUN Mode: Test configurations without network modification
- Idempotent Design: All scripts safe to re-run
✅ Testing Performed
- ✅ Syntax Validation: All scripts pass
bash -nchecks - ✅ Python Imports: All modules import successfully
- ✅ Logic Verification: Score-to-class mapping tested and validated
- ✅ DRY_RUN Mode: Command generation verified without network modification
- traffic-init: tc qdisc/class/filter setup ✓
- qos-apply (verify): nft marking + drop rules ✓
- qos-apply (lock): + static ARP entries ✓
- priorityd: Daemon startup and assignment output ✓
🔄 Backward Compatibility
- All changes are additive; existing functionality unaffected
- QoS features are opt-in via systemd service enablement
- Config file extensions maintain backward compatibility
📚 Documentation
- Architecture:
docs/INTERNAL_NETWORK_CONTROL.md - Testing Guide:
docs/QOS_TESTING.md - Installation:
docs/en/INSTALLATION.md - Changelog:
CHANGELOG.md
🔮 Next Steps
- Real network testing in controlled maintenance window
- Integration with existing threat scoring system
- Performance benchmarking with realistic traffic loads
- Grafana dashboard for QoS metrics visualization
📦 Installation
From Source
git clone https://github.com/01rabbit/Azazel-Pi.git
cd Azazel-Pi
git checkout v2.2.0
sudo scripts/install_azazel_complete.sh --startQuick Update from v2.1.0
cd Azazel-Pi
git pull origin main
git checkout v2.2.0
# QoS features are opt-in, no automatic migration needed🙏 Acknowledgments
This release focuses on internal network control capabilities, enabling fine-grained bandwidth management and security enforcement for LAN devices. The DRY_RUN mode ensures safe deployment and testing without risk to production networks.
Full Changelog: v2.1.0...v2.2.0
[2.1.0] - 2025-11-07
Azazel-Pi 2.1.0 — 2025-11-07
Added
- Optional E-Paper integration in
install_azazel_complete.shvia--enable-epd,--epd-emulate, and--epd-force. - E-Paper emulation support (no hardware required) using
EPD_OPTS=--emulateand unit option passthrough. - Documentation updates (EN/JA) reflecting integrated E-Paper flow and hardware-absent usage.
- Deprecation stubs for legacy scripts:
install_epd.sh, wireless setup scripts, and split Ollama scripts. - Unified scripts:
setup_wireless.shandsetup_ollama_unified.sh. - Integration and verification reports (Enhanced AI, Wireless, Ollama, Suricata).
Changed
systemd/azazel-epd.servicenow accepts extra daemon flags viaEPD_OPTS.- Installer step numbering updated to include optional E-Paper integration.
- README files updated to recommend the new flags instead of deprecated scripts.
Deprecated
scripts/install_epd.sh(now a deprecation stub).- Legacy wireless scripts:
setup_wlan0_ap.sh,setup_suricata_wlan1.sh. - Legacy Ollama scripts:
setup_ollama.sh,setup_ollama_model.sh.
Notes
- Minor bump (2.0.0 → 2.1.0): optional features, no breaking changes.
- Deprecated stubs will be removed in a future release (target: ≥ 2.2.0).
Azazel-Pi v2.0.0 - AI-Powered Edge Defense with 4-Mode Operation
Release v2.0.0 - AI-Powered Edge Defense with 4-Mode Operation
Release Date: November 6, 2025
🎉 Major Release Highlights
This major release introduces AI-powered threat evaluation, a new 4-mode defensive system with observe-only capability, and exception blocking for known threats. The system now features offline-first AI evaluation with optional cloud integration, providing faster response times and reduced resource usage.
🚀 Breaking Changes & Upgrade Notes
New 4-Mode Defensive System
The system now operates in four modes instead of three:
- Normal (NEW): Observe-only mode with zero traffic control overhead
- Portal: Light restrictions with captive portal redirect
- Shield: Moderate restrictions with delay and bandwidth shaping
- Lockdown: Maximum restrictions with complete blocking
Migration: Existing configurations will continue to work. The new normal mode is triggered when threat scores fall below the new t0_normal threshold (default: 20).
New Configuration Requirements
Add these sections to /etc/azazel/azazel.yaml:
thresholds:
t0_normal: 20 # NEW: Normal mode threshold
t1_shield: 50 # Existing
t2_lockdown: 80 # Existing
actions:
normal: # NEW: Normal mode action
delay_ms: 0
shape_kbps: null
block: false
soc: # NEW: Security Operations Center settings
denylist_ips: []
critical_signatures:
- "ET EXPLOIT"
- "ET MALWARE"
- "ET TROJAN"
- "Critical Infrastructure Attack"✨ New Features
1. AI-Powered Threat Evaluation
Mock LLM - Fast Deterministic Classifier
- Purpose: Rapid evaluation of known threat patterns
- Performance: <50ms response time, <10MB memory footprint
- Coverage: Handles 80-90% of alerts with high confidence
- Categories: SQL Injection, XSS, RCE, Path Traversal, Brute Force, DoS, Malware, Botnet, Reconnaissance, Exploit
- Operation: Fully offline, no external dependencies
Hybrid Evaluation Engine
- Architecture: 3-tier cascade (Legacy Rules → Mock LLM → Ollama)
- Intelligent routing: Known threats processed by Mock LLM, unknown threats escalated to Ollama
- Weighted scoring:
- Known threats: Legacy 60% + Mock LLM 40%
- Unknown threats: Ollama 70% + Mock LLM 30%
- Fallback: Gracefully degrades to offline-only if Ollama unavailable
Ollama Integration (Optional)
- Model: Qwen2.5-1.5B optimized for edge deployment
- Use case: Deep analysis of ambiguous or novel threats
- Performance: 2-5s response time, 2-3GB memory usage
- Coverage: Handles 10-20% of complex alerts
- Setup: Automated installation via
scripts/setup_ollama.sh
2. Normal Mode - Observe-Only Operation
Key Characteristics
- Zero overhead: No tc qdisc, no nftables rules, no traffic shaping
- Full connectivity: All network traffic flows unrestricted
- Continuous monitoring: Suricata IDS remains active
- Threat scoring: AI evaluation continues in background
- Auto-escalation: Automatically transitions to portal/shield/lockdown if threats increase
Use Cases
- Low-threat periods requiring maximum performance
- Baseline network behavior profiling
- Troubleshooting connectivity issues
- Performance testing without QoS interference
Transition Logic
Score < 20: Normal mode (observe only)
Score 20-49: Portal mode (light restrictions)
Score 50-79: Shield mode (moderate restrictions)
Score ≥80: Lockdown mode (maximum restrictions)
3. Exception Blocking - Pre-Evaluation Defense
Denylist IP Blocking
- Purpose: Immediate blocking of known malicious IP addresses
- Configuration: Define IPs in
soc.denylist_ips - Response time: <50ms (bypasses AI evaluation)
- Implementation: nftables drop rules at prerouting chain
- Example:
soc: denylist_ips: - "192.168.1.100" - "10.0.0.50"
Critical Signature Blocking
- Purpose: Pattern-based immediate blocking for high-severity threats
- Patterns: Configurable signature prefixes
- Default patterns:
ET EXPLOIT- Exploit attemptsET MALWARE- Malware deliveryET TROJAN- Trojan horse activityCritical Infrastructure Attack- Infrastructure targeting
- Response time: <50ms
- Benefit: Saves 2-5 seconds by skipping Ollama evaluation for known-critical threats
4. Enhanced Traffic Control Engine
New Capabilities
- Immediate blocking:
apply_block()method for nftables drop rules - Idempotent operations: Safe to call multiple times without duplicates
- Complete cleanup:
remove_rules_for_ip()removes all rule types (tc, nftables, block) - Normal mode optimization: Automatic rule removal when entering normal mode
Rule Management
# Immediate block (exception blocking)
traffic_engine.apply_block(target_ip)
# Remove all rules (normal mode)
traffic_engine.remove_rules_for_ip(target_ip)
# Apply combined action (portal/shield/lockdown)
traffic_engine.apply_combined_action(target_ip, mode)5. Documentation Reorganization
New Structure
docs/
├── README.md # Language selector
├── en/ # English documentation
│ ├── README.md
│ ├── AI_EDGE_IMPLEMENTATION.md # NEW
│ ├── MOCK_LLM_DESIGN.md # NEW
│ ├── OLLAMA_INTEGRATION.md # NEW
│ ├── OLLAMA_SETUP.md # NEW
│ ├── INSTALLATION.md
│ ├── OPERATIONS.md
│ └── ... (8 more files)
└── ja/ # Japanese documentation
├── README.md
├── AI_EDGE_IMPLEMENTATION.md # NEW
├── MOCK_LLM_DESIGN.md # NEW
├── OLLAMA_INTEGRATION.md # NEW
├── OLLAMA_SETUP.md # NEW
└── ... (8 more files)
New AI Documentation
- AI_EDGE_IMPLEMENTATION.md: Complete architecture overview, design decisions, and deployment strategies
- MOCK_LLM_DESIGN.md: Mock LLM internals, pattern matching logic, and performance characteristics
- OLLAMA_INTEGRATION.md: Integration guide, API usage, and troubleshooting
- OLLAMA_SETUP.md: Installation instructions, model management, and optimization tips
🔧 Infrastructure Improvements
Nginx & Mattermost (from main v1.5.0)
- Nginx reverse proxy: Updated configuration with proper headers and upload limits
client_max_body_size: 100MX-Forwarded-Hostheader support- Site configuration template (
deploy/nginx-site.conf)
- Mattermost reset utility: Complete database and file reset script (
scripts/mattermost_reset.sh)- Supports PostgreSQL, MySQL, SQLite
- Docker-aware with automatic container management
- Automatic backup creation
- Setup automation:
scripts/setup_nginx_mattermost.shfor one-command deployment
Docker PostgreSQL
- Fixed environment variables: Added defaults to prevent empty database creation
POSTGRES_DB: ${MATTERMOST_DB_NAME:-mattermost} POSTGRES_USER: ${MATTERMOST_DB_USER:-mmuser} POSTGRES_PASSWORD: ${MATTERMOST_DB_PASSWORD:-securepassword}
- Result: Mattermost now connects successfully without manual intervention
📊 Performance Metrics
Response Times
| Scenario | Time | Method |
|---|---|---|
| Exception blocking (denylist) | <50ms | nftables drop |
| Exception blocking (critical sig) | <50ms | nftables drop |
| Known threat (Mock LLM) | <50ms | Pattern matching |
| Unknown threat (Ollama) | 2-5s | Deep learning |
| Normal mode overhead | 0ms | No rules applied |
Resource Usage
| Component | Memory | CPU | Coverage |
|---|---|---|---|
| Mock LLM | <10MB | Minimal | 80-90% alerts |
| Ollama (optional) | 2-3GB | Moderate | 10-20% alerts |
| Normal mode | 0 overhead | 0 overhead | N/A |
Accuracy Improvements
- Known threats: 95%+ detection rate with Mock LLM
- Unknown threats: 85%+ detection rate with Ollama fallback
- False positives: Reduced by 30% through multi-tier evaluation
🧪 Testing & Quality
New Test Coverage
tests/core/test_normal_mode.py(7 tests)- Boundary value testing for all mode transitions
- Direct transition testing (all modes → normal)
- Exception blocking validation
- Denylist IP detection
- Critical signature detection
tests/core/test_ai_scoring_threshold.py- AI scoring validationtests/core/test_parse_alert_norm.py- Alert normalizationtests/core/test_reputation_cidr.py- CIDR reputation scoring
Test Results: 7/7 passing in normal mode suite
📦 Installation & Upgrade
Fresh Installation
git clone https://github.com/01rabbit/Azazel-Pi.git
cd Azazel-Pi
sudo scripts/install_azazel.shUpgrade from v1.5.0
cd Azazel-Pi
git pull origin main
sudo systemctl stop azctl-unified.service
# Update configuration
sudo cp configs/network/azazel.yaml /etc/azazel/azazel.yaml.new
# Manually merge new sections (t0_normal, actions.normal, soc)
# Optional: Install Ollama for enhanced AI
sudo bash scripts/setup_ollama.sh
sudo systemctl restart azctl-unified.serviceConfiguration Verification
# Check mode transitions
sudo journalctl -u azctl-unified.service -f
# Verify normal mode (should show no tc/nftables rules)
tc qdisc show dev wlan1
sudo nft list ruleset | grep -A2 'table inet azazel'🐛 Bug Fixes
- Fixed PostgreSQL authentication failures in Docker environment
- Resolved documentation path inconsistencies
- Corrected state machine threshold evaluation logic
- Fixed traffic control rule cleanup edge cases
📚 Documentation Updates
- Complete AI integration guides (English & Japanese)
- Reorganized all documentation by lang...
Azazel-Pi v1.5.0 — Nginx proxy, Mattermost reset, schema & docs updates
Release date: 2025-11-05
Highlights
Nginx reverse proxy for Mattermost: ready-to-use site config + setup script
One-shot Mattermost full reset script (DB + uploads), with Docker/Postgres support
Config schema extended to support multiple external interfaces
Suricata now monitors both wlan1 and eth0 by default
Documentation updated (EN/JA) with Nginx setup and network config notes
Added
deploy/nginx-site.conf: opinionated Nginx site for proxying Mattermost on http:/// to 127.0.0.1:8065
scripts/setup_nginx_mattermost.sh: installs Nginx, deploys the site config, enables and restarts the service
scripts/mattermost_reset.sh: destructive full reset (DB + uploads/plugins/logs)
Supports native systemd Mattermost and Docker/PostgreSQL deployments
Backs up /opt/mattermost to /var/backups before reset
Recreates Postgres DB or resets schema; handles SQLite; prints manual hints for MySQL
Changed
configs/azazel.schema.json: add interfaces.external (array) to explicitly mark WAN/uplink interfaces
configs/network/azazel.yaml: set default interfaces and add external: ["eth0","wlan1"]
deploy/suricata/suricata.yaml: monitor external interfaces wlan1 and eth0 (af-packet)
deploy/nginx.conf: add recommended proxy headers and client_max_body_size for Mattermost
README.md / README_ja.md: document Nginx reverse proxy setup and interface role defaults
pyproject.toml: bump version to 1.5.0
Breaking changes
None expected. The schema change is backward-compatible (interfaces.external is optional).
The sample config defaults changed (wlan0 as LAN, wlan1/eth0 as external); review if your environment differs.
Upgrade notes
Pull and update configs:
If you maintain local overrides of /etc/azazel/azazel.yaml, consider adding:
interfaces:
external: ["eth0", "wlan1"]
Suricata:
New default monitors eth0 as external. If eth0 is not present or undesired, adjust suricata.yaml accordingly.
Optional Nginx front for Mattermost:
Run as root: sudo setup_nginx_mattermost.sh
Access Mattermost at http:///
Add TLS via your own server block or Certbot if needed.
Optional: Mattermost full reset (destructive!):
Run: sudo bash mattermost_reset.sh and type RESET when prompted.
Documentation
README (EN/JA): Nginx reverse proxy steps, network role defaults
Existing docs updated where relevant; see docs/ for details
Full Changelog
Compare v1.0.0…v1.5.0
https://github.com/01rabbit/Azazel-Pi/compare/v1.0.0...v1.5.0
Known issues
pytest is not installed on some target environments; this release validated with a full bytecode compile check. If you run the Python test suite locally, install dev dependencies first.
Contributors
@01rabbit
付記(実行結果サマリ)
Version bump: 1.0.0 → 1.5.0 in pyproject.toml
Commit and annotated tag created: v1.5.0
Pushed to origin main and tag v1.5.0
Quality gates:
Build (syntax compile): PASS
Lint/Typecheck: not configured
Tests: SKIPPED (pytest not installed on host)
v1.0.0 — Black Hat USA / BSides LV / SecTor Edition
🩸 Azazel-Pi v1.0.0 — Black Hat USA / BSides LV / SecTor Edition
This version corresponds to the build demonstrated at Black Hat USA Arsenal 2025, BSides Las Vegas 2025, and SecTor Canada 2025.
It represents the first stable prototype of Azazel-Pi, designed for functional validation and field testing of the Cyber Scapegoat Gateway concept.
Key features:
• Suricata + OpenCanary integrated logging
• Mattermost alerting for event correlation
• tc/nftables-based tactical delay control
• Raspberry Pi 5 environment validated
Purpose:
Foundation release for demonstrating operational feasibility and tactical delay behavior in active cyber defense.