Files
firewall_containers/network-go/implementation.md
gyurix c3de398f35
continuous-integration/drone/push Build encountered an error
added network-go project
2026-06-08 15:34:01 +02:00

5.7 KiB

network-go — Docker Network & Firewall Manager

A Go-based replacement for the firewall/firewall-add shell script. It watches /etc/user/config/networks.json for changes and reconciles Docker networks, container connections, and iptables firewall rules using the Docker SDK.

Project Structure

network-go/
├── main.go                  Entry point: watches config, orchestrates reconciliation
├── config/
│   └── config.go            Parses /etc/user/config/networks.json into typed structs
├── docker/
│   └── docker.go            Docker SDK wrapper (network create, container connect,
│                            container PID for nsenter, route management)
├── firewall/
│   └── firewall.go          Orchestrator: translates policies → iptables rules
├── iptables/
│   └── iptables.go          Manages iptables CLI: PREROUTING DNAT, POSTROUTING MASQUERADE,
│                            FORWARD ACCEPT, nsenter for container network namespaces
├── resolver/
│   └── resolver.go          Resolves names → IPs using networks.json config
├── watcher/
│   └── watcher.go           Periodic file change detection via MD5 hash polling
├── go.mod / go.sum          Module definition with Docker SDK dependency
└── .gitignore

Packages

config

  • NetworksConfig, NetworkConfig, IPConfig, PolicyConfig structs matching networks.json
  • FirewallRule struct for resolved executable rules
  • Helpers: IsIP, ToCIDR, NetworkPrefix, ParseCIDR, Load

docker

  • Client wrapping github.com/docker/docker/client
  • EnsureNetwork — creates a Docker network if it doesn't exist
  • ConnectContainer / DisconnectContainer — manages container ↔ network membership
  • GetContainerPID — returns the container PID for nsenter
  • AddRouteInContainer — adds routes inside a container namespace via nsenter
  • WaitForContainerRunning — polls until a container is running

resolver

  • Resolves names → IPs using the networks.json config only
  • Looks up by container_name and selector in the ips section
  • Falls back to prefix matching (e.g. smarthost-backend-1 → prefix smarthost)

iptables

  • Auto-detects iptables-legacy vs iptables (matching shell script logic)
  • EnsureIPForward — enables /proc/sys/net/ipv4/ip_forward
  • EnsureEstablishedRelated — inserts ESTABLISHED,RELATED ACCEPT at top of chain
  • InsertPreroutingRule / InsertPreroutingRuleInContainer — DNAT rules
  • InsertPostroutingMasquerade — MASQUERADE rules
  • InsertForwardAccept — FORWARD/DOCKER-USER ACCEPT rules
  • Rule deletion by line-number + grep pattern matching (matching shell script)
  • nsenter-based execution inside container network namespaces

firewall

  • Orchestrator ties all packages together
  • ReconcileAll runs the full reconciliation cycle:
    1. Enable IP forwarding
    2. Ensure all Docker networks from config
    3. Connect containers to networks with assigned IPs
    4. Apply firewall policies as iptables rules
  • Policy → rule mapping:
    • from field → FORWARD ACCEPT rule on DOCKER-USER or FORWARD chain
    • nat: dnat field → PREROUTING DNAT inside container namespace via nsenter
    • Interface-based rules (e.g. wg0) → host-level PREROUTING DNAT

watcher

  • FileWatcher polls a file at a configurable interval
  • Computes MD5 hash on each tick
  • Fires onChange callback when hash changes
  • Start / Stop for lifecycle management

Configuration

The file /etc/user/config/networks.json defines:

{
  "networks": {
    "smarthost-loadbalancer": {
      "network_name": "smarthost-loadbalancer",
      "subnet": "172.18.103.0/24",
      "gateway": "172.18.103.1"
    }
  },
  "ips": {
    "172.18.103.2": {
      "ip": "172.18.103.2",
      "container_name": "smarthostloadbalancer",
      "selector": "smarthostloadbalancer",
      "service_name": "smarthost-proxy"
    }
  },
  "policies": [
    {
      "service_name": "smarthost-proxy",
      "container_name": "smarthost_loadbalancer",
      "selector": "smarthostloadbalancer",
      "from": "publicbackend",
      "port": 80,
      "proto": "tcp"
    },
    {
      "service_name": "smarthost-proxy",
      "container_name": "smarthost_loadbalancer",
      "selector": "smarthostloadbalancer",
      "name": "wireguardproxy",
      "iface": "wg0",
      "nat": "dnat",
      "to": "smarthostloadbalancer",
      "port": 80,
      "proto": "tcp"
    }
  ]
}

Environment Variables

Variable Default Description
NETWORKS_CONFIG_PATH /etc/user/config/networks.json Path to the configuration file
WATCH_PERIOD_SECONDS 30 Polling interval in seconds for config file changes
DEBUG false Enable debug output (1 or true)

Key Differences from Shell Script

Shell Script (firewall-add) Go Implementation
docker ps --format, docker inspect Docker SDK (github.com/docker/docker)
/etc/dns/hosts.local lookup networks.json config lookup
$SOURCE / $TARGET env vars from / to fields in networks.json
iptables via bash + grep + awk Go os/exec with structured line matching
nsenter -t PID -n for container iptables nsenter via os/exec in iptables.Manager
$ROUTE=true + ip route docker.Client.AddRouteInContainer()
Manual per-rule invocation Orchestrator.ReconcileAll() batch reconciliation

Build & Run

go build -o network-go .
./network-go

In Docker:

go build -o network-go .
# Mount Docker socket and config
docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -v /etc/user/config:/etc/user/config \
           network-go