
Exit Routing
Control where your traffic goes. An exit node opens connections to destinations on your behalf - reach internal networks, specific IP ranges, or route by domain name.
Common scenarios:
- Route
10.0.0.0/8through an exit inside a corporate network - Route
*.internal.corpto an agent with access to internal DNS - Route
0.0.0.0/0for a general-purpose exit to the internet
Route Types
- CIDR routes: Match destinations by IP address (e.g.,
10.0.0.0/8) - Domain routes: Match destinations by domain name (e.g.,
*.example.com)
Domain routes only work with SOCKS5 clients that send the destination hostname. The Mutiauk TUN interface operates at Layer 3 (IP) and only sees IP addresses after DNS resolution, so it can only use CIDR routes. Mutiauk's autoroutes feature fetches only CIDR routes from Muti Metroo.
See Exit Configuration for all options including CIDR routes, domain routes, and DNS servers.
Route Advertisement
Routes are propagated through the mesh:
- Periodic: Every
routing.advertise_interval(default 2m) - On-demand: Via HTTP API
POST /routes/advertise
Trigger Immediate Advertisement
curl -X POST http://localhost:8080/routes/advertise
DNS Resolution
DNS resolution location depends on the route type:
CIDR Routes (DNS at Ingress)
For destinations matching CIDR routes:
- Client connects via SOCKS5 with domain (e.g., example.com)
- Ingress agent resolves domain using the system's DNS resolver
- Ingress performs route lookup using the resolved IP address
- Ingress opens a stream to the exit node with the IP address
- Exit opens TCP connection to the destination IP
Domain Routes (DNS at Exit)
For destinations matching domain routes:
- Client connects via SOCKS5 with domain (e.g., api.internal.corp)
- Ingress checks domain routes first
- If a domain route matches, ingress opens a stream to the exit node with the domain name
- Exit agent resolves domain using the configured DNS servers
- Exit opens TCP connection to the resolved IP
Domain routes are ideal for:
- Split-horizon DNS: Internal domains that resolve differently inside vs. outside the network
- Private services: Route
*.internal.corpto an internal exit with access to internal DNS - Geo-specific resolution: Different DNS results based on exit node location
Route Selection
Domain Routes
Domain routes are checked first for domain-based requests:
- Exact match:
api.example.commatches onlyapi.example.com - Wildcard match:
*.example.commatches single-level subdomains likefoo.example.com - If no domain route matches, fall back to CIDR routing
Wildcard matching is single-level only:
*.example.commatchesfoo.example.comandbar.example.com*.example.comdoes NOT matcha.b.example.comorexample.com
CIDR Routes
Uses longest-prefix match:
- Filter routes where CIDR contains destination IP
- Select route with longest prefix (most specific)
- If tied, select lowest metric (hop count)
Example:
1.2.3.4/32beats1.2.3.0/24for 1.2.3.41.2.3.0/24beats0.0.0.0/0for 1.2.3.5
Access Control
Exit nodes only allow connections to destinations matching their advertised routes. If an exit advertises 10.0.0.0/8, connections to any other IP range will be rejected. This provides implicit access control - you control what each exit can reach by configuring its routes.
Verifying Routes
Check which routes are available in the mesh:
# View all routes (CIDR and domain)
curl http://localhost:8080/healthz | jq '{routes: .routes, domain_routes: .domain_routes}'
# Trigger route advertisement after config changes
curl -X POST http://localhost:8080/routes/advertise
Troubleshooting
No Route to Host
curl: (7) Can't complete SOCKS5 connection to 10.1.2.3:443
Causes:
- No exit node advertising a route that covers the destination
- Exit node not connected to the mesh
- Route not yet propagated (wait for advertise interval)
Solutions:
# Check available routes
curl http://localhost:8080/healthz | jq '.routes'
# Verify peer connections
curl http://localhost:8080/healthz | jq '.peers'
# Trigger route advertisement on the exit node
curl -X POST http://exit-node:8080/routes/advertise
Domain Route Not Matching
# Expected to use internal DNS but resolved externally
Causes:
- Using
socks5://instead ofsocks5h://(DNS resolved locally) - Domain pattern doesn't match (wildcards are single-level only)
- CIDR route matching before domain route (IP-based request)
Solutions:
- Use
socks5h://to send hostname to the proxy - Check wildcard pattern:
*.example.commatchesfoo.example.combut nota.b.example.com - Verify domain routes exist:
curl http://localhost:8080/healthz | jq '.domain_routes'
Connection Timeout
curl: (7) Failed to connect to destination
Causes:
- Destination unreachable from exit node's network
- Firewall blocking outbound connections
- DNS resolution failing at exit (for domain routes)
Solutions:
- Verify exit node can reach the destination directly
- Check exit node's DNS configuration for domain routes
- Review firewall rules on the exit node's network
Related
- Configuration - Exit - Full configuration reference
- Concepts - Agent Roles - Understanding exit role
- Concepts - Routing - How routes propagate
- Security - Access Control - Route-based access control