linux

package module
v0.2.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: GPL-3.0 Imports: 34 Imported by: 0

README

sysnet-linux

sysnet-linux implements the sysnet.System interface from the gonnect library for Linux.

The primary application for this package is Almagest. You can also use it as the Linux backend of another VPN application that needs one cross-platform system-networking abstraction.

[!WARNING] This project is experimental. APIs and behavior can change without notice. Do not use it for production systems without your own review and tests.

[!NOTE] Parts of the DNS implementation include code borrowed from the Tailscale project.

Features

  • Creates native Linux TUN interfaces.
  • Configures TUN names, MTUs, IPv4 and IPv6 addresses, and routes.
  • Builds and updates a default-route TUN for full-tunnel VPN operation.
  • Uses separate policy-routing tables instead of adding VPN default routes to the main table.
  • Supports strict, include, and exclude routing modes.
  • Marks VPN transport sockets so that they bypass the VPN and do not create routing loops.
  • Mirrors packet marks through conntrack to support reverse-path filtering.
  • Controls system DNS and restores the previous configuration when the VPN closes.
  • Detects and supports direct /etc/resolv.conf, systemd-resolved, openresolv, and Debian resolvconf setups.
  • Provides process rules for command names, executable paths, command lines, PIDs, users, UIDs, groups, and GIDs.
  • Supports socket-owner matching and optional eBPF-based process marking through p-mark.
  • Integrates with the killswitch daemon through its administration socket.
  • Allocates IPv4 and IPv6 addresses and subnets without conflicting with active local interfaces.
  • Reports the effective feature set at runtime and degrades optional features when the host does not support them.
  • Supports dependency injection for tests and custom integrations.

Requirements

  • Linux
  • Go 1.25.5 or later
  • /dev/net/tun and CAP_NET_ADMIN for TUN and routing operations
  • Permission to control the selected system DNS service for DNS integration
  • nftables support for connection-mark handling
  • A mounted BPF filesystem and a configured pin path for process-based TUN rules
  • A compatible killswitch daemon for killswitch integration

You do not need all optional integrations. The high-level constructor probes the current environment and disables unavailable features. Always use Features() and ListRules() to determine what the created system supports.

Installation

go get github.com/asciimoth/sysnet-linux

The package name is linux, so it is useful to use an explicit import alias:

import linux "github.com/asciimoth/sysnet-linux"

Quick start

Use New for normal application integration. The zero configuration requests all features and enables the features that are available on the host.

package main

import (
	"log"

	"github.com/asciimoth/gonnect/sysnet"
	linux "github.com/asciimoth/sysnet-linux"
)

func main() {
	var system sysnet.System

	linuxSystem, err := linux.New(linux.SystemConfig{
		Logf: log.Printf,
	})
	if err != nil {
		log.Fatal(err)
	}
	system = linuxSystem
	defer system.Close()

	features := system.Features()
	log.Printf("TUN: %t, default TUN: %t", features.Tun, features.DefaultTun)
}

Set SystemConfig.Pmark.PinPath to enable process-based include and exclude rules. You can also select a DNS backend, configure packet marks, set a killswitch socket path, and register lifecycle callbacks.

Use NewSystem when the application must supply its own DNS provider, routing manager, TUN factory, process marker, killswitch client, or other low-level component. This constructor is also useful for deterministic tests.

How it fits into a cross-platform VPN

Application code can depend on gonnect/sysnet.System instead of Linux-specific networking APIs. Select the platform implementation at the application boundary:

func runVPN(system sysnet.System) error {
	// The VPN core uses the common gonnect sysnet interface.
	return nil
}

sysnet-linux supplies that interface on Linux. The VPN core can use another sysnet.System implementation on each other operating system without changing its main networking logic.

Packages

  • dns: system DNS detection, configuration, forwarding, and rollback
  • routing: fail-closed Linux policy-routing reconciliation
  • tun: native TUN creation and configuration
  • subnet: Linux-aware address and subnet allocation
  • connmark: nftables packet-mark and connection-mark synchronization
  • killswitch: reconnecting client for temporary killswitch rules

Development

Run the unit tests:

go test ./...

Run all checks and privileged end-to-end tests with just and Docker:

just check

The end-to-end tests create network interfaces, change routes, and test DNS providers in privileged containers.

License

This project is licensed under the GNU General Public License v3.0.

Documentation

Overview

Package linux implements gonnect/sysnet.System for Linux.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Callbacks

type Callbacks struct {
	TunCreated           func(tun gtun.Tun)
	TunConfigured        func(tun gtun.Tun, opts sysnet.TunOpts)
	DefaultTunCreated    func(tun sysnet.DefaultTun)
	DefaultTunConfigured func(tun sysnet.DefaultTun, opts sysnet.DefaultTunOpts)
	DefaultTunClosed     func()
	RoutingApplied       func(config routing.Config)
	DNSConfigured        func(server netip.Addr)
	KillswitchUpdated    func(rules killswitch.AllowRules)
}

Callbacks are optional hooks fired after successful lifecycle operations. Implementations must be quick; System never requires callbacks to be set.

type Config

type Config struct {
	Features  FeatureConfig
	Allocator *linuxsubnet.CombinedAllocator

	DNSProvider    dns.DNSProvider
	RoutingManager RoutingManager
	Connmark       ConnmarkManager
	Pmark          PmarkController
	Killswitch     KillswitchClient
	TUNFactory     TUNFactory
	TunConfig      TunConfigurator

	RuleTracker *multirule.Tracker
	OwnerLookup func(sockowner.FlowTuple) (*sockowner.SocketOwner, error)

	PacketListen PacketListenFunc
	TUNIndex     TUNIndexFunc

	AppBypassMark uint32
	AppBypassMask uint32
	UserMark      uint32
	UserMarkMask  uint32
	PmarkPriority int

	DefaultTunBaseName string

	KillswitchAllowExclude bool
	Logf                   func(format string, args ...any)
	Callbacks              Callbacks

	// ExtraClosers are resources owned by System in addition to the standard
	// injected components. They are closed by System.Close after DNS, routing,
	// and killswitch state has been released.
	ExtraClosers []io.Closer
}

Config supplies System dependencies. Privileged integrations are injected so tests and embedders can choose exactly which Linux components System owns.

type ConnmarkManager added in v0.2.2

type ConnmarkManager interface {
	Apply(linuxconnmark.Config) error
	Rollback() error
	Close() error
}

ConnmarkManager is the nftables conntrack-mark surface used by System.

type DNSConfig

type DNSConfig struct {
	Mode DNSMode

	ResolvconfInterface    string
	ResolvedInterfaceIndex int
	FallbackServers        []netip.AddrPort
}

DNSConfig configures the DNSProvider built by New.

FallbackServers are used by DNS providers only when no usable original upstream resolver is available. ResolvconfInterface is the provider-owned resolvconf record name; when empty, "sysnet-linux" is used.

type DNSMode

type DNSMode string

DNSMode selects the host DNS integration used by New.

DNSModeAuto uses dns.DnsMode to detect the host DNS integration.

const (
	DNSModeAuto             DNSMode = ""
	DNSModeDisabled         DNSMode = "disabled"
	DNSModeDirect           DNSMode = "direct"
	DNSModeOpenresolv       DNSMode = "openresolv"
	DNSModeDebianResolvconf DNSMode = "debian-resolvconf"
	DNSModeResolved         DNSMode = "systemd-resolved"
)

type FeatureConfig

type FeatureConfig struct {
	Tun             bool
	DefaultTun      bool
	DynTun          bool
	DynDefaultTun   bool
	TunNames        bool
	DefaultTunNames bool
	StrictMode      bool
	TunRules        bool
	MatcherRules    bool
	DNSControl      bool
	Routing         bool
	Pmark           bool
	Killswitch      bool
}

FeatureConfig describes features requested by the caller. Effective feature support is the requested value degraded by the components supplied in Config.

type KillswitchClient

type KillswitchClient interface {
	CreateTMPRuleset(killswitch.AllowRules) (uint64, error)
	UpdateTMPRuleset(uint64, killswitch.AllowRules) error
	DeleteTMPRuleset(uint64) error
	Close() error
}

KillswitchClient is the killswitch temporary-ruleset surface used by System.

type PacketListenFunc

type PacketListenFunc func(ctx context.Context, network, address string) (net.PacketConn, error)

PacketListenFunc opens the UDP socket backing the DefaultTun DNS server.

type PmarkConfig

type PmarkConfig struct {
	PinPath string

	Callbacks            pmark.Callbacks
	TombCollectionEvents uint64
	TombTTL              time.Duration
	Priority             int
}

PmarkConfig configures the optional p-mark integration built by New.

P-mark is attempted only when PinPath is non-empty. This avoids creating a global bpffs directory implicitly. When enabled, New also starts the fwmark eBPF manager, because DefaultTun include/exclude rules need p-mark values to become socket fwmarks before routing can see them.

type PmarkController

type PmarkController interface {
	SetChecker(pmark.CheckFunc) (uint64, error)
	ForceProcessTraversal() error
}

PmarkController is the p-mark daemon surface used by System.

type RoutingManager

type RoutingManager interface {
	Apply(routing.Config) error
	Refresh() error
	Rollback(routing.Config) error
	Status() (routing.DesiredState, bool)
	Close() error
}

RoutingManager is the routing.Manager surface used by System.

type System

type System struct {
	// contains filtered or unexported fields
}

System composes the Linux DNS, TUN, routing, p-mark, and killswitch helpers.

func New

func New(config SystemConfig) (*System, error)

New creates a Linux System by constructing native components under the hood.

New probes the current process environment and enables features on a best-effort basis. In particular, TUN and routing are enabled only when CAP_NET_ADMIN is effective and a throwaway TUN can be created; DNS control is enabled only when a configured provider can be built; killswitch is enabled only when requested and a daemon path is usable; TunRules are enabled only when p-mark starts successfully. A missing optional integration is logged and degrades Features(), rather than making construction fail.

Errors are reserved for invalid static configuration or failures in the underlying System constructor after feature degradation.

func NewSystem

func NewSystem(config Config) (*System, error)

NewSystem creates a Linux System from supplied components.

func (*System) AddTunAddr

func (s *System) AddTunAddr(t gtun.Tun, addr string) error

func (*System) AddTunRoute

func (s *System) AddTunRoute(t gtun.Tun, route string) error

func (*System) AllocIP

func (s *System) AllocIP() subnet.IPAllocator

AllocIP returns the shared IP allocator.

func (*System) AllocSubnet

func (s *System) AllocSubnet() subnet.SubnetAllocator

AllocSubnet returns the shared subnet allocator.

func (*System) BuildDefaultTun

func (s *System) BuildDefaultTun(
	opts sysnet.DefaultTunOpts,
) (sysnet.DefaultTun, error)

BuildDefaultTun creates or rebuilds the single active DefaultTun.

func (*System) BuildMatcher

func (s *System) BuildMatcher(rule sysnet.Rule) (sysnet.Matcher, error)

BuildMatcher builds a socket-owner based matcher for LocalNet/TUN flows.

func (*System) BuildTun

func (s *System) BuildTun(opts sysnet.TunOpts) (gtun.Tun, error)

BuildTun creates and configures a regular TUN.

func (*System) Close

func (s *System) Close() error

Close releases every object owned by System.

func (*System) DefaultTunWarnings added in v0.2.12

func (s *System) DefaultTunWarnings(t sysnet.DefaultTun) []sysnet.Warning

DefaultTunWarnings returns read-only runtime warnings for an active DefaultTun created by this System.

func (*System) Features

func (s *System) Features() sysnet.Features

Features returns effective support after degrading requested features by supplied component availability.

func (*System) GetTunAddrs

func (s *System) GetTunAddrs(t gtun.Tun) ([]string, error)

func (*System) GetTunRotue

func (s *System) GetTunRotue(t gtun.Tun) ([]string, error)

func (*System) ListRules

func (s *System) ListRules() sysnet.RulesInfo

ListRules reports rule types supported by enabled integrations.

func (*System) LocalNet

func (s *System) LocalNet() gonnect.Network

LocalNet returns app-marked local network.

func (*System) OutDNS

func (s *System) OutDNS() gdns.Interface

OutDNS returns the DNS interface used by OutNet resolution.

func (*System) OutNet

func (s *System) OutNet() gonnect.Network

OutNet returns app-marked outbound network.

func (*System) RuleCompl

func (s *System) RuleCompl(rule sysnet.Rule) (out []string)

RuleCompl returns quick best-effort completions for rules whose value space is enumerable without process traversal. Account completions are read from the local passwd and group databases, and executable path completion inspects only one directory with a small scan cap so large filesystems cannot make completion expensive.

func (*System) RuleVerify

func (s *System) RuleVerify(rule sysnet.Rule) bool

RuleVerify checks whether a rule value is syntactically valid.

func (*System) SetTunAddrs

func (s *System) SetTunAddrs(t gtun.Tun, addrs []string) error

func (*System) SetTunMTU

func (s *System) SetTunMTU(t gtun.Tun, mtu int) error

func (*System) SetTunName

func (s *System) SetTunName(t gtun.Tun, name string) ([]string, error)

func (*System) SetTunRoutes

func (s *System) SetTunRoutes(t gtun.Tun, routes []string) error

func (*System) TunNameVerify

func (s *System) TunNameVerify(name string) (bool, bool)

TunNameVerify checks Linux interface name syntax and availability.

func (*System) TunWarnings added in v0.2.12

func (s *System) TunWarnings(t gtun.Tun) []sysnet.Warning

TunWarnings returns read-only runtime warnings for a regular TUN created by this System. sysnet-linux does not currently report regular TUN warnings.

func (*System) VerifyDefaultTunOpts

func (s *System) VerifyDefaultTunOpts(opts sysnet.DefaultTunOpts) error

VerifyDefaultTunOpts validates DefaultTun options without mutating host state.

func (*System) VerifyTunOpts

func (s *System) VerifyTunOpts(opts sysnet.TunOpts) error

VerifyTunOpts validates regular TUN options.

type SystemConfig

type SystemConfig struct {
	Features FeatureConfig

	Allocator      linuxsubnet.DefaultAllocatorConfig
	DNS            DNSConfig
	KillswitchPath string
	Pmark          PmarkConfig

	AppBypassMark uint32
	AppBypassMask uint32
	UserMark      uint32
	UserMarkMask  uint32

	DefaultTunBaseName string

	KillswitchAllowExclude bool
	Logf                   func(format string, args ...any)
	Callbacks              Callbacks
}

SystemConfig is the high-level, best-effort constructor configuration used by New.

The zero value requests all System-level features and lets New auto-detect which ones are actually available in the current process environment. Missing privileges, absent /dev/net/tun, unavailable routing/DNS/killswitch/p-mark integrations, and unsupported optional daemons disable the affected features while leaving allocation, OutNet, LocalNet, rule verification, and any other available features usable.

For exact dependency injection, deterministic tests, or integrations that need a DNS provider tied to a TUN created elsewhere, use NewSystem.

type TUNFactory

type TUNFactory interface {
	CreateTUN(baseName string, mtu int) (gtun.Tun, error)
}

TUNFactory creates a native TUN device.

type TUNIndexFunc

type TUNIndexFunc func(gtun.Tun) (int, error)

TUNIndexFunc returns the kernel interface index for a TUN.

type TunConfigurator

type TunConfigurator interface {
	SetTunMTU(gtun.Tun, int) error
	SetTunAddrs(gtun.Tun, []string) error
	AddTunAddr(gtun.Tun, string) error
	GetTunAddrs(gtun.Tun) ([]string, error)
	SetTunRoutes(gtun.Tun, []string) error
	AddTunRoute(gtun.Tun, string) error
	GetTunRotue(gtun.Tun) ([]string, error)
	SetTunName(gtun.Tun, string) ([]string, error)
}

TunConfigurator applies and reads mutable TUN state.

Directories

Path Synopsis
cmd
debug command
nolint
nolint
Package connmark mirrors sysnet packet marks through conntrack marks so inbound replies are marked before distribution rpfilter chains run.
Package connmark mirrors sysnet packet marks through conntrack marks so inbound replies are marked before distribution rpfilter chains run.
dns
dnsname
Package dnsname contains string functions for working with DNS names.
Package dnsname contains string functions for working with DNS names.
resolvconffile
Package resolvconffile parses & serializes /etc/resolv.conf-style files.
Package resolvconffile parses & serializes /etc/resolv.conf-style files.
e2e
routing command
nolint
nolint
system command
nolint
nolint
Package killswitch provides a minimal client for the killswitch daemon admin API.
Package killswitch provides a minimal client for the killswitch daemon admin API.
Package routing owns Linux policy routing for sending selected traffic through an already-created VPN TUN interface.
Package routing owns Linux policy routing for sending selected traffic through an already-created VPN TUN interface.
Package subnet provides Linux-aware wrappers around gonnect subnet allocation.
Package subnet provides Linux-aware wrappers around gonnect subnet allocation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL