Skip to content

arner/netgen

Repository files navigation

netgen

netgen is a command-line tool that turns a single YAML file describing your home network into the config and firewall scripts required by sbnMerlin. Instead of editing sbnMerlin.conf and the iptables rules by hand you declare zones, devices, and access policies in one place — netgen validates the config and pushes the generated files to your router.

What is sbnMerlin?

sbnMerlin is a script for Asus-WRT Merlin firmware that creates isolated network segments (IoT, guest, kids, work, …) backed by per-zone DHCP and iptables rules. netgen is a companion tool that manages its configuration files. Credits to janico82 for the fantastic script! If you use sbnMerlin, consider sending him a donation.

Do you need netgen?

Probably not. sbnMerlin by itself is a great tool that likely covers all your needs. If you're happy with your zones and rarely change anything, keep it that way! However, if, like me,

  • you like granular control over your devices
  • you find yourself keeping an excel with mac/ip address mappings
  • you get dizzy from the contents of br5_staticlist
  • you want to have an up to date diagram of your setup

You may want to give it a go! The tool fits seamlessly with the sbnMerlin features. It works best if you use different IP subnets for your zones. You can already easily configure internet, one way access and router access. netgen makes it easy to use mac addresses to assign static IPs to some of your devices - outside of the DHCP range but within the subnet of the bridge. You can then easily create granular policies. For instance:

  • internet is blocked for IoT except for the vacuum cleaner
  • chromecast may reach jellyfin on the mediaserver
  • guests are isolated but can still reach the nas on another bridge

or whatever else you need. See examples for an idea of what that may look like.

Tip

Find the mac addresses of connected devices via: /jffs/scripts/sbnMerlin list-clients. Or, from outside the router: ssh www.asusrouter.com /jffs/scripts/sbnMerlin list-clients.

Prerequisites

  • Asus router running Asus-WRT Merlin with sbnMerlin installed and working
  • SSH access to the router with key authentication

Install

Download a binary from the Releases page, or, if you have go 1.26.1+:

go install github.com/arner/netgen/cmd/netgen@latest

Quick start

Tip

If you've already configured sbnMerlin, scroll down to the netgen recover command. It attempts to construct a network.yaml from your existing configuration!

  1. Copy the example that matches your router model (see examples/) to network.yaml
  2. Edit network.yaml — set router.ssh_host, update wan, adjust bridge numbers, and replace the placeholder MACs and IPs with your real devices
  3. Run netgen validate to catch errors before generating anything
  4. Run netgen generate --dry-run to preview the output without writing files
  5. Run netgen generate to write the files to out/
  6. Run netgen push --apply to generate, copy, and apply the config in one go

Use at your own risk, obviously. It's always a good idea to backup your config and check the output of the tool before pushing it to the router.

Examples

Three (contrived) examples of network setups can be found in the examples directory: one for each type of router that is supported by sbnMerlin. The .yaml files demonstrate the features of netgen. See the output directories for the resulting sbnMerlin config.

File Models Highlights
examples/dualband.yaml RT-AX86U, RT-AX88U, RT-AX58U, and other dual-band models (sbnMerlin default) PPPoE WAN with failover, wired LAN port in IoT zone, per-device DNS override, internet whitelist
examples/triband.yaml GT-AXE11000, RT-BE96U Work zone with router access, IoT zone with Pi-hole DNS, Kids zone with HTTP/HTTPS-only internet
examples/quadband.yaml GT-AXE16000, GT-BE98 Dual DNS (dns1 + dns2 fallback), mDNS via extra_rules, high-security 6 GHz-only zone

Each file opens with a comment block showing the bridge assignments and WiFi band mapping for that router family.

dualband.yaml dualband

triband.yaml triband

quadband.yaml quadband

Configuration reference

A complete annotated example is in examples/. The tables below list every supported field.

router

Field Type Default Description
ssh_host string SSH target used by push (e.g. admin@192.168.1.1)
wan string or list WAN interface name(s). Run nvram get wan0_ifname on the router to confirm. Common values: eth0 (cable/fibre), ppp0 (PPPoE). A single interface can be written as a scalar (wan: eth0) or as a one-element list.
wan_rule_position int 0 (unset) Position at which internet whitelist rules are inserted into the FORWARD chain (-I FORWARD N). Required when using PPPoE (ppp0) if a TCPMSS clamping rule is present — set to a value just above the TCPMSS line number. Check with: iptables -L FORWARD --line-numbers | grep TCPMSS on the router.

zones

Field Type Default Description
name string Zone identifier; referenced in exceptions
bridge string sbnMerlin bridge name. Valid range: br3br9, br11br14, br17br18, br21br24, br27br29. Use br0 for the main LAN (netgen does not generate config for it, but devices can be referenced in exceptions).
enabled bool true Set false to emit only brN_enabled=0 and skip all other settings — useful when decommissioning a bridge.
subnet CIDR Zone subnet (e.g. 10.0.5.0/24). The gateway is derived as the first host address (.1).
dhcp_start IP First address of the DHCP pool
dhcp_end IP Last address of the DHCP pool
ifnames list Extra interfaces to bridge into this zone (e.g. eth1 to wire in a LAN port). Do not use eth0 (WAN) or wl*.1 (main LAN SSID).
dns1 IP Zone-wide primary DNS override (e.g. a Pi-hole on your main LAN)
dns2 IP Zone-wide secondary DNS (e.g. 1.1.1.1 as a fallback if dns1 is down)
ap_isolate bool false Prevent WiFi clients in this zone from talking to each other. Exceptions can still open specific flows.
allow_internet bool false Allow all devices in this zone to reach the internet. For per-device control, leave this false and use the internet field on each device.
allow_onewayaccess bool false Allow devices on the main LAN (br0) to initiate connections into this zone. Traffic in the other direction is still blocked.
allow_routeraccess bool false Allow zone devices to reach services running on the router itself (e.g. a WireGuard server or the admin panel).
extra_rules list Verbatim iptables rules appended to the filter script. Must match the rule format sbnMerlin accepts (e.g. "-I INPUT -i br17 -p udp --dport 5353 -j ACCEPT").

zones[].devices

Devices are listed under their zone. Each device gets a static DHCP lease.

Field Type Description
name string Device name used in exceptions. Must match [a-zA-Z][a-zA-Z0-9_-]{0,19}.
mac string MAC address. Any common format is accepted; normalised to uppercase colon-separated internally.
ip IP Static lease address. Must be within the zone's subnet and outside the DHCP pool (or a warning is issued).
dns IP Per-device DNS override. Overrides dns1 for this device only.
internet Internet access policy for this device (see variants below). Ignored when the zone already has allow_internet: true.

internet field variants

Value Meaning
absent or false No internet access
true Unrestricted internet (all protocols and ports)
{proto: tcp, dport: 443} Whitelist a single port
[{proto: tcp, dport: 80}, {proto: tcp, dport: 443}] Whitelist multiple ports

Valid protocols: tcp, udp, icmp. Ports can be a number (443) or a range (8000:8080).

exceptions

Exceptions open specific traffic flows that would otherwise be blocked (e.g. when ap_isolate is on, or between zones).

Field Type Description
from string Source device name
to string Destination device name
proto string Optional: restrict to tcp, udp, or icmp
dport number / range Optional: restrict to a destination port or range

Commands

All commands accept:

Flag Default Description
--config <path> network.yaml Path to the network config file
--out-dir <path> out Directory where generated files are written

netgen validate

Checks the config against all validation rules and prints any issues. Exits with code 1 if errors are found. Run this before generate or push.

netgen validate
netgen validate --config examples/dualband.yaml

netgen generate [--dry-run]

Generates sbnMerlin.conf and one br*_iptables.filter per active zone that has rules, written to --out-dir. With --dry-run, prints to stdout instead of writing files.

It also generates a *.puml PlantUML diagram. Convert it to png for a diagram of your network, for instance via plantuml.com.

netgen generate
netgen generate --dry-run
netgen generate --out-dir /tmp/preview

netgen push

Generates the files, writes them to --out-dir, and copies them to the router via scp. Destination paths on the router:

  • sbnMerlin.conf/jffs/addons/sbnMerlin.d/sbnMerlin.conf
  • br*_iptables.filter/jffs/addons/sbnMerlin.d/cscripts/
Flag Description
--dry-run Print the scp/ssh commands without executing them
--apply After pushing, run sbnMerlin run-config sc on the router via SSH
netgen push
netgen push --apply
netgen push --dry-run

netgen recover

Tip

Before running netgen recover, copy the files from the router.

mkdir -p out/cscripts && cd out
scp -O www.asusrouter.com:/jffs/addons/sbnMerlin.d/sbnMerlin.conf .
scp -O 'www.asusrouter.com:/jffs/addons/sbnMerlin.d/cscripts/*' cscripts/

Recover reads a generated or copied out/ directory (containing sbnMerlin.conf and brN_iptables.filter files) and reconstructs a network.yaml. Useful for importing an existing sbnMerlin setup into netgen.

Review all # TODO comments in the output — some information (e.g. ssh_host, WAN interface when no internet whitelist rules are present) cannot be recovered from the generated files.

Flag Default Description
--dir <path> out Directory containing sbnMerlin.conf and filter files
--output <path> stdout Write the recovered YAML to a file instead of stdout
netgen recover                            # print to stdout
netgen recover --dir /tmp/sbnMerlin      # read from custom dir
netgen recover --output network.yaml     # write to file

How it works

network.yaml ──► netgen validate
                       │
                       ▼
                 netgen generate
                  ├── out/sbnMerlin.conf
                  └── out/cscripts/br*_iptables.filter
                       │
                       ▼
                 netgen push  (scp to router)
                       │
                       ▼
                 sbnMerlin run-config

netgen reads the YAML, validates it against bridge numbering rules and IP constraints, then generates the config file and per-zone iptables filter scripts that sbnMerlin expects. The filter scripts contain the FORWARD rules for internet whitelists and cross-zone exceptions, and any verbatim extra_rules.

Important notes

Bridge numbers. The valid bridge range depends on your router model. Using a bridge index outside the model's supported set will cause sbnMerlin errors. Pick the example for your model as the starting point — bridge numbers and band mappings are listed in the comment block at the top.

BSB bridges (br1br4 depending on model) are basic single-band bridges whose IP and DHCP settings are set in NVRAM by sbnMerlin directly. netgen does not generate configuration for them and they are not listed as valid bridge values in zones.

Main LAN (br0) is always managed by the router firmware. Define a br0 zone only if you need to reference main-LAN devices in exceptions; no config is generated for it.

About

a companion tool to sbnMerlin for granular policies on asus merlin routers.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages