Skip to content

Latest commit

 

History

History
277 lines (208 loc) · 6.73 KB

File metadata and controls

277 lines (208 loc) · 6.73 KB

ZNetlink

A Zig library for interacting with Linux netlink sockets, providing a type-safe interface for network configuration and monitoring.

Features

  • Core Netlink Socket Support: Low-level netlink socket operations
  • Route Netlink Protocol: Query network interfaces, addresses, and routes
  • Network Namespace Management: Create, delete, enter, and list network namespaces
  • Message Parsing: Parse netlink messages and attributes
  • Error Handling: Comprehensive error handling with custom error types
  • Memory Safety: RAII-style resource management

Project Structure

src/
├── root.zig      # Core netlink functionality
├── route.zig     # Route netlink protocol implementation
├── netns.zig     # Network namespace management
└── main.zig      # Example application

Core Components

NetlinkSocket

The main socket interface for netlink communication:

const socket = try NetlinkSocket.init(NetlinkFamily.route, 0);
defer socket.close();
try socket.bind();

Route Protocol

High-level interface for network information:

const route_socket = try RouteSocket.init(0);
defer route_socket.close();

// Get network interfaces
const links = try route_socket.getLinks(allocator);
defer {
    for (links.items) |*link| {
        link.deinit(allocator);
    }
    links.deinit();
}

// Get addresses
const addresses = try route_socket.getAddresses(allocator);
defer {
    for (addresses.items) |*addr| {
        addr.deinit(allocator);
    }
    addresses.deinit();
}

// Get routes
const routes = try route_socket.getRoutes(allocator);
defer {
    for (routes.items) |*route| {
        route.deinit(allocator);
    }
    routes.deinit();
}

// List routes with formatting
try route_socket.listRoutes(allocator, stdout);

// List routes with filtering
const filter = RouteFilter.init()
    .withFamily(std.posix.AF.INET)
    .withGateway(true);
try route_socket.listRoutesFiltered(allocator, stdout, filter);

Building

zig build        # Build library and example
zig build test   # Run tests
zig build run    # Run example (requires root)

Usage

The library provides both low-level netlink socket operations and high-level protocol-specific interfaces.

Example Application

The included example demonstrates querying network interfaces, addresses, and routes:

sudo ./zig-out/bin/znetlink

Note: Netlink sockets require root privileges for most operations.

Supported Netlink Families

  • NETLINK_ROUTE: Network interface and routing information
  • NETLINK_GENERIC: Generic netlink protocol
  • NETLINK_AUDIT: Audit subsystem
  • NETLINK_NETFILTER: Netfilter subsystem
  • And many more...

Error Handling

The library defines comprehensive error types:

pub const NetlinkError = error{
    InvalidMessage,
    InvalidMessageType,
    InvalidMessageLength,
    SocketError,
    BindError,
    SendError,
    ReceiveError,
    InsufficientBuffer,
    InvalidPid,
    InvalidSeq,
    PermissionDenied,
    AddressNotAvailable,
    NoSuchDevice,
    OperationNotSupported,
    NamespaceNotFound,
    NamespaceSwitchFailed,
};

Data Structures

LinkInfo

Network interface information:

  • Interface index and name
  • MTU and flags
  • Hardware addresses

AddressInfo

Network address information:

  • Address family and prefix length
  • Interface index and scope
  • Address data

RouteInfo

Routing table information:

  • Route family and table
  • Destination and gateway
  • Priority and flags

RouteFilter

Route filtering configuration:

  • Family (IPv4/IPv6)
  • Table and protocol
  • Interface and gateway presence

NetworkNamespace

Network namespace management:

  • Name and filesystem path
  • Creation and deletion operations
  • Namespace switching capabilities
  • Existence checking

Route Listing and Filtering

The library provides convenient functions for listing and filtering routes:

// List all routes with formatted output
try route_socket.listRoutes(allocator, writer);

// Filter routes by various criteria
const filter = RouteFilter.init()
    .withFamily(std.posix.AF.INET)        // IPv4 only
    .withTable(254)                       // Main routing table
    .withProtocol(2)                      // Kernel routes
    .withInterface(1)                     // Specific interface
    .withGateway(true);                   // Routes with gateway

try route_socket.listRoutesFiltered(allocator, writer, filter);

Network Namespaces

Manage Linux network namespaces for network isolation:

const netns = @import("netns.zig");

// Create a new network namespace
var network_ns = try netns.NetworkNamespace.init(allocator, "my-netns");
defer network_ns.deinit();

// Create the namespace
try network_ns.create();

// Check if namespace exists
if (network_ns.exists()) {
    std.debug.print("Namespace exists!\n", .{});
}

// Enter the namespace
try network_ns.enter();

// Delete the namespace when done
try network_ns.delete();

// List all available namespaces
var namespaces = try netns.listNamespaces(allocator);
defer netns.cleanupNamespaceList(allocator, &namespaces);

for (namespaces.items) |ns_name| {
    std.debug.print("Found namespace: {s}\n", .{ns_name});
}

Available Filters

  • withFamily(family): Filter by address family (IPv4/IPv6)
  • withTable(table): Filter by routing table
  • withProtocol(protocol): Filter by routing protocol
  • withInterface(interface): Filter by output interface
  • withGateway(has_gateway): Filter by gateway presence

Network Namespace Operations

Network namespaces provide network isolation, allowing multiple independent network stacks on a single Linux system. The library provides comprehensive namespace management:

Basic Operations

const netns = @import("netns.zig");

// Initialize a namespace handler
var ns = try netns.NetworkNamespace.init(allocator, "test-ns");
defer ns.deinit();

// Create namespace (requires root privileges)
try ns.create();

// Check existence
const exists = ns.exists();

// Enter namespace (affects current process)
try ns.enter();

// Clean up when done
try ns.delete();

Listing Namespaces

// Get all available namespaces
var namespaces = try netns.listNamespaces(allocator);
defer netns.cleanupNamespaceList(allocator, &namespaces);

for (namespaces.items) |name| {
    std.debug.print("Namespace: {s}\n", .{name});
}

Important Notes

  • Root Privileges: Network namespace operations require root privileges
  • Process Context: Entering a namespace affects the current process and its children
  • Persistence: Created namespaces persist in /var/run/netns/ until explicitly deleted
  • Isolation: Each namespace has its own network interfaces, routing tables, and firewall rules

License

This project is available under the MIT License.