Thanks to visit codestin.com
Credit goes to github.com

Skip to content

A fast, cross-platform network port monitoring library and CLI tool written in Zig. PortWatchZ tracks listening ports and established connections, detects changes, and can send alerts via webhooks.

License

Notifications You must be signed in to change notification settings

zombocoder/PortwatchZ

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PortWatchZ

CI Release License Zig Platform

A fast, cross-platform network port monitoring library and CLI tool written in Zig. PortWatchZ tracks listening ports and established connections, detects changes, and can send alerts via webhooks.

Features

  • Multi-platform support: Linux (via /proc/net), macOS, FreeBSD, OpenBSD, NetBSD, Windows (IP Helper API)
  • Process information: Maps ports to process IDs, executables, command lines, and user/group IDs
  • Binary integrity: BLAKE3 hashing of executable files to detect changes
  • Flexible filtering: Include/exclude established connections, ephemeral ports, IPv4/IPv6
  • Multiple output formats: Human-readable text, JSON, ECS (Elastic Common Schema)
  • Webhook integration: Send alerts with HMAC authentication and mTLS support
  • Baseline comparison: Track changes against saved snapshots
  • Continuous monitoring: Watch mode for real-time detection
  • Native OS APIs: Platform-optimized implementations for maximum performance

Installation

From Source

git clone https://github.com/zombocoder/portwatchz.git
cd portwatchz
zig build -Doptimize=ReleaseFast

The compiled binary will be available at zig-out/bin/portwatchz.

As a Library

Add to your build.zig.zon:

.dependencies = .{
    .portwatchz = .{
        .url = "https://github.com/zombocoder/portwatchz/archive/v0.1.0.tar.gz",
        .hash = "12345...", // Replace with actual hash
    },
},

Quick Start

CLI Usage

  1. Create a configuration file (optional but recommended):

    portwatchz init-config
  2. Create a baseline of current network ports:

    portwatchz init
  3. Check for changes against the baseline:

    portwatchz check
  4. Monitor continuously for changes:

    portwatchz watch --interval 5

Library Usage

const std = @import("std");
const portwatchz = @import("portwatchz");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Take a snapshot of current ports
    const options = portwatchz.Options{
        .process_info = true,
        .hash_binaries = true,
    };

    var snapshot = try portwatchz.snapshot(allocator, options);
    defer snapshot.deinit(allocator);

    std.log.info("Found {} listening ports", .{snapshot.records.len});

    // Save as baseline
    try portwatchz.saveBaseline("baseline_net.db", &snapshot);
}

CLI Reference

Commands

  • portwatchz init - Create a baseline of current network ports
  • portwatchz check - Compare current ports against baseline
  • portwatchz watch - Continuously monitor for changes
  • portwatchz init-config - Create default configuration file
  • portwatchz help - Show help information

Options

General Options

  • --config <PATH> - Configuration file path (default: portwatchz.conf)
  • --baseline <PATH> - Baseline file path (default: baseline_net.db)
  • --output <FORMAT> - Output format: text, json, ecs (default: text)

Monitoring Options

  • --include-established - Include established TCP connections (not just listening ports)
  • --include-ephemeral - Include ports in ephemeral ranges
  • --no-process-info - Skip gathering process information
  • --no-hash-binaries - Skip computing executable hashes
  • --only-ipv4 - Only scan IPv4 addresses
  • --only-ipv6 - Only scan IPv6 addresses
  • --filter <PATTERN> - Add port filter (can be used multiple times)

Watch Mode Options

  • --interval <SECONDS> - Watch interval in seconds (default: 2)

Webhook Options

  • --webhook-url <URL> - Webhook endpoint URL
  • --webhook-hmac-key <KEY> - HMAC key for webhook authentication
  • --webhook-mtls-cert <PATH> - mTLS certificate file path
  • --webhook-mtls-key <PATH> - mTLS private key file path
  • --webhook-timeout <MS> - Webhook timeout in milliseconds (default: 30000)
  • --webhook-retries <N> - Number of retry attempts (default: 3)
  • --webhook-batch-size <N> - Events per webhook batch (default: 100)

Filter Patterns

Filters allow you to focus on specific ports or addresses:

  • :22 - Port 22 (any address)
  • 127.0.0.1: - Any port on localhost
  • tcp:8080 - Port 8080 TCP only
  • udp:53 - Port 53 UDP only

Examples

# Create default configuration file
portwatchz init-config

# Create baseline including established connections
portwatchz init --include-established

# Check only SSH and HTTPS ports
portwatchz check --filter :22 --filter :443

# Monitor with JSON output and webhook alerts
portwatchz watch --output json --webhook-url https://example.com/alerts

# Monitor only listening ports on specific interface
portwatchz watch --filter 192.168.1.100: --interval 10

# Use custom configuration file
portwatchz watch --config custom.conf

Configuration Files

PortWatchZ supports configuration files to set default options and simplify command-line usage.

Configuration File Format

Configuration files use a simple key=value format:

# PortWatchZ Configuration File
# Lines starting with # are comments

baseline_path=baseline_net.db
watch_interval=2
output_format=text

# Monitoring options
include_established=false
include_ephemeral=false
process_info=true
hash_binaries=true
only_ipv4=false
only_ipv6=false

# Port filters (can specify multiple)
port_filter=:22
port_filter=:443
port_filter=tcp:8080

# Webhook configuration
webhook_url=https://example.com/alerts
webhook_hmac_key=your-secret-key
webhook_timeout=30000
webhook_retries=3
webhook_batch_size=100

Configuration Options

Option Type Default Description
baseline_path string baseline_net.db Path to baseline file
watch_interval integer 2 Watch interval in seconds
output_format string text Output format (text, json, ecs)
include_established boolean false Include established connections
include_ephemeral boolean false Include ephemeral ports
process_info boolean true Gather process information
hash_binaries boolean true Compute executable hashes
only_ipv4 boolean false Only scan IPv4 addresses
only_ipv6 boolean false Only scan IPv6 addresses
port_filter string - Port filter pattern (repeatable)
webhook_url string - Webhook endpoint URL
webhook_hmac_key string - HMAC key for authentication
webhook_mtls_cert string - mTLS certificate file
webhook_mtls_key string - mTLS private key file
webhook_timeout integer 30000 Webhook timeout (milliseconds)
webhook_retries integer 3 Number of retry attempts
webhook_batch_size integer 100 Events per webhook batch

Using Configuration Files

  1. Create a default configuration:

    portwatchz init-config
  2. Edit the configuration in portwatchz.conf as needed

  3. Use with commands:

    # Uses portwatchz.conf automatically if present
    portwatchz watch
    
    # Or specify a custom config file
    portwatchz watch --config custom.conf
  4. Override config settings with command-line options:

    # Config sets interval=5, but this overrides to 10
    portwatchz watch --interval 10

API Reference

Core Types

// Configuration for taking snapshots
pub const Options = struct {
    include_established: bool = false,
    include_ephemeral: bool = false,
    process_info: bool = true,
    hash_binaries: bool = true,
    only_ipv4: bool = false,
    only_ipv6: bool = false,
    filters: []const []const u8 = &[_][]const u8{},
};

// A snapshot of network ports at a point in time
pub const Snapshot = struct {
    records: []PortRecord,
    timestamp: i64,
    options: Options,

    pub fn deinit(self: *Snapshot, allocator: std.mem.Allocator) void;
};

// Difference between two snapshots
pub const Diff = struct {
    opened: []PortRecord,
    closed: []PortRecord,
    binary_changed: []struct { old: PortRecord, new: PortRecord },
    process_changed: []struct { old: PortRecord, new: PortRecord },
    timestamp: i64,

    pub fn deinit(self: *Diff, allocator: std.mem.Allocator) void;
};

Core Functions

// Take a snapshot of current network ports
pub fn snapshot(alloc: std.mem.Allocator, opts: Options) !Snapshot;

// Compare two snapshots and return differences
pub fn diffSnapshots(old: *const Snapshot, new: *const Snapshot, alloc: std.mem.Allocator) !Diff;

// Save/load baselines
pub fn saveBaseline(path: []const u8, snap: *const Snapshot) !void;
pub fn loadBaseline(path: []const u8, alloc: std.mem.Allocator) !Snapshot;

// Convert diff to ECS events for webhooks
pub fn diffToEcsEvents(d: *const Diff, alloc: std.mem.Allocator) ![]EcsEvent;
pub fn sendWebhookBatch(cfg: *const WebhookConfig, events: []const u8) !void;

Platform Support

Platform Status Implementation
Linux βœ… Complete /proc/net parsing
macOS βœ… Complete netstat + lsof
macOS 🚧 Planned Native sysctl + libproc
FreeBSD 🚧 Planned BSD sysctl
OpenBSD 🚧 Planned BSD sysctl
NetBSD 🚧 Planned BSD sysctl
Windows 🚧 Planned IP Helper API

Output Formats

Text Format (Default)

Port changes detected (3 total):

Opened ports (2):
  tcp 0.0.0.0:8080 [LISTEN] (PID: 1234) /usr/bin/server
  udp 127.0.0.1:5353 [LISTEN] (PID: 5678) /usr/bin/mdns

Closed ports (1):
  tcp 0.0.0.0:3000 [LISTEN] (PID: 9999) /usr/bin/node

JSON Format

[
  {
    "@timestamp": "1640995200",
    "event": {
      "type": "network",
      "action": "port_opened"
    },
    "network": {
      "transport": "tcp",
      "direction": "ingress"
    },
    "process": {
      "pid": 1234,
      "executable": "/usr/bin/server"
    },
    "host": {
      "hostname": "web-server-01",
      "ip": ["0.0.0.0"]
    }
  }
]

Security Features

  • Process verification: BLAKE3 hashing detects binary tampering
  • Webhook security: HMAC authentication and mTLS support
  • Privilege separation: Runs with minimal required privileges
  • Filter validation: Input sanitization for all filter patterns

Performance

  • Fast enumeration: Efficient parsing of OS network tables
  • Memory efficient: Streaming processing for large port lists
  • Low overhead: Minimal impact on system performance
  • Concurrent safe: Thread-safe for library usage

Implementation Approaches

PortWatchZ uses different strategies optimized for each platform:

Linux

  • Current: /proc/net filesystem parsing
  • Benefits: Direct kernel data access, no external dependencies
  • Performance: Excellent for all use cases

macOS (Darwin)

  • Current: netstat + lsof command parsing
  • Benefits: Simple, reliable, works without special privileges
  • Planned: Native sysctl + libproc APIs
  • Future Benefits: ~50% faster enumeration, reduced memory usage, no subprocess overhead

BSD Systems (FreeBSD/OpenBSD/NetBSD)

  • Planned: Native sysctl API access
  • Benefits: Direct kernel PCB (Protocol Control Block) access
  • Performance: Expected to match Linux performance characteristics

Windows

  • Planned: IP Helper API (GetTcpTable, GetUdpTable)
  • Benefits: Native Windows networking APIs
  • Performance: Optimized for Windows network stack

Roadmap

Near Term (v0.2.x)

  • Native macOS Implementation: Direct sysctl + libproc APIs for improved performance
  • FreeBSD Support: Native BSD sysctl implementation
  • OpenBSD Support: Native BSD sysctl implementation
  • NetBSD Support: Native BSD sysctl implementation

Medium Term (v0.3.x)

  • Windows Support: IP Helper API implementation
  • Enhanced Process Tracking: Better process-to-port mapping across platforms
  • Configuration Enhancements: More granular filtering and monitoring options
  • Performance Optimization: Reduced memory footprint and faster enumeration

Long Term (v1.0+)

  • Container Support: Docker/Podman network namespace awareness
  • Historical Analysis: Trend analysis and port usage patterns
  • Advanced Alerting: Multiple webhook endpoints and alert routing
  • GUI/Web Interface: Optional web-based monitoring dashboard

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Development Setup

git clone https://github.com/zombocoder/portwatchz.git
cd portwatchz
zig build test  # Run all tests
zig build run -- help  # Test CLI

Implementing Platform Support

To add support for a new platform:

  1. Create src/enumerator_<platform>.zig
  2. Implement the enumerate() function
  3. Add platform detection in src/lib.zig
  4. Add tests for the new platform

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

Related Projects

  • netstat - Traditional network statistics tool
  • ss - Modern socket statistics tool

About

A fast, cross-platform network port monitoring library and CLI tool written in Zig. PortWatchZ tracks listening ports and established connections, detects changes, and can send alerts via webhooks.

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published