A toolkit for analyzing BACnet packet captures (PCAP files), processing message types, extracting device information, and generating Corona-compatible metrics.
- Analyzes BACnet packet captures (.pcap files)
- Detects and classifies message types by service choice
- Extracts device information from I-Am messages
- Handles both direct BACnet/IP messages and forwarded NPDUs
- Supports MS/TP devices through router forwarding
- Generates detailed traffic statistics and device reports
- Exports metrics in multiple formats:
- TTL (Turtle) format for RDF/Corona compatibility
- Project Haystack Zinc Grid format
- Project Haystack JSON format
- Prometheus exposition format with OpenTelemetry conventions
- Validates metrics against the Corona standard
The main components of the project are:
-
bacnet_analyzer/
- Refactored functional implementationanalyzer.py
- Main PCAP analyzer implementationcorona_metrics.py
- Corona metrics generatormodels.py
- Data models for analysis resultsconstants.py
- Constants for BACnet message typespacket_processors.py
- Functions for processing BACnet packetsdevice_catalog.py
- Device discovery and managementstats_collector.py
- Statistics collectionreporting.py
- Report generationdebug_utils.py
- Debug utilities
-
tests/
- Test suitetest_metrics.py
- Tests for the metrics generatortest_pcap_processor.py
- Tests for the PCAP processorvalidate_metrics.py
- Utility for validating metrics files
-
corona-standard/
- Corona standard referenceREADME.md
- Documentation for the Corona standardvalidate_model.py
- Tool for validating metrics against the standardexample.ttl
- Example metrics file
No installation required, just clone the repository and ensure you have the required dependencies:
pip install bacpypes3 rdflib
from bacnet_analyzer import BACnetAnalyzer
# Create an analyzer instance (with optional debug mode)
analyzer = BACnetAnalyzer(debug=False, debug_level=1)
# Analyze a PCAP file
results = analyzer.analyze_pcap("sample-pcap.pcap")
# Print a summary of the analysis
analyzer.print_summary(results)
from bacnet_analyzer import BACnetAnalyzer
from bacnet_analyzer.corona_metrics import CoronaMetricsGenerator
# Analyze a PCAP file
analyzer = BACnetAnalyzer()
results = analyzer.analyze_pcap("sample-pcap.pcap")
# Generate metrics (optionally with a capture device address)
metrics_gen = CoronaMetricsGenerator(results, capture_device="10.0.0.1")
metrics_gen.generate_metrics()
# Export in different formats
metrics_gen.export_ttl("metrics.ttl") # RDF Turtle format
metrics_gen.export_haystack_zinc("metrics.zinc") # Haystack Zinc format
metrics_gen.export_haystack_json("metrics.json") # Haystack JSON format
metrics_gen.export_prometheus("metrics.prom") # Prometheus exposition format
# Validate a metrics file
python tests/validate_metrics.py validate metrics.ttl
# Validate with analysis
python tests/validate_metrics.py validate metrics.ttl --analyze
# Process a PCAP file and generate metrics (default TTL format)
python generate_corona_metrics.py sample-pcap.pcap metrics.ttl
# Process with capture device
python generate_corona_metrics.py sample-pcap.pcap metrics.ttl --capture-device 10.0.0.1
# Generate in Haystack Zinc format
python generate_corona_metrics.py sample-pcap.pcap metrics.zinc --format zinc
# Generate in Haystack JSON format
python generate_corona_metrics.py sample-pcap.pcap metrics.json --format json
# Generate in Prometheus format with OpenTelemetry conventions
python generate_corona_metrics.py sample-pcap.pcap metrics.prom --format prom
# Generate with debug output
python generate_corona_metrics.py sample-pcap.pcap metrics.ttl --debug
The analyzer detects BACnet message types in two ways:
- Class-based detection: Looks at the APDU class names
- Service choice-based detection: Uses the
apduService
attribute:- Service Choice 0: "IAmRequest"
- Service Choice 1: "IHaveRequest"
- Service Choice 7: "WhoHasRequest"
- Service Choice 8: "WhoIsRequest"
The package can generate BACnet metrics in multiple formats:
Metrics in a format compatible with the Corona standard using RDF Turtle format:
- Uses RDF triples to represent metrics and relationships
- Follows the Corona metrics ontology for compatibility
- Enables semantic queries and integration with RDF tools
- Supports relationship modeling between devices and interfaces
Metrics in Project Haystack format for building automation systems:
- Zinc Grid Format: Compact, human-readable tabular format
- JSON Format: Project Haystack encoded in standard JSON
Haystack exports organize metrics with:
- Row-based representation of each metric
- Device and metric tagging
- Standard Haystack metadata
Metrics in Prometheus exposition format following OpenTelemetry semantic conventions:
- Text-based format: Standard Prometheus exposition format
- OpenTelemetry compliance: Follows OTel naming and labeling conventions
- Counter and gauge support: Properly categorizes metrics by type
- Rich metadata: Includes help text and type information
Example metrics in Prometheus format:
# HELP bacnet_packets_total Total number of BACnet packets observed from this device
# TYPE bacnet_packets_total counter
bacnet_packets_total{device_id="709101",address="0:10.21.86.4",network="0",name="Device 709101",address_type="bacnet_ip"} 5052
# HELP bacnet_whois_requests_total Number of WhoIs requests sent by this device
# TYPE bacnet_whois_requests_total counter
bacnet_whois_requests_total{device_id="709101",address="0:10.21.86.4",network="0",name="Device 709101",address_type="bacnet_ip"} 1579
All export formats cover the same metrics:
- Network interface metrics (broadcasts, unicasts, etc.)
- Application-level metrics (requests, responses by type)
- Router-specific metrics (forwarded messages, etc.)
- Device identification information
See the corona-standard/README.md
file for details on the Corona standard format.
The analyzer follows a functional architecture with the following components:
- Immutable data structures: Uses immutable or copied structures
- Pure functions: Functions with explicit inputs and outputs
- Separation of concerns: Each module has a single responsibility
- No hidden state: All state changes are explicit
- Type safety: Comprehensive type hints
Several debugging utilities are provided to help with packet inspection:
debug_pcap.py
: General packet inspectionfind_whohas.py
: Specifically looks for WHO-HAS messagesprocess_whohas.py
: Enhanced analyzer for WHO-HAS processing
This project is licensed under the MIT License.