fatedier/frp · error
add route to %v error: %v
Error message
add route to %v error: %v
What it means
Linux vnet route installation: after the TUN device is up, frp uses netlink.RouteReplace to install the configured CIDR route onto that interface; failure is wrapped here. Installing routes requires CAP_NET_ADMIN, so permission problems dominate, but invalid interfaces and netlink socket issues also surface here.
Source
Thrown at pkg/vnet/tun_linux.go:117
numSuffix, err := strconv.Atoi(suffix)
if err == nil && numSuffix > maxSuffix {
maxSuffix = numSuffix
}
}
}
nextSuffix := maxSuffix + 1
name := fmt.Sprintf("%s%d", basename, nextSuffix)
return name, nil
}
func addRoutes(ifn *net.Interface, cidr *net.IPNet) error {
r := netlink.Route{
Dst: cidr,
LinkIndex: ifn.Index,
}
if err := netlink.RouteReplace(&r); err != nil {
return fmt.Errorf("add route to %v error: %v", r.Dst, err)
}
return nil
}
// getFallbackTunName generates a deterministic fallback TUN device name
// based on the base name and the provided address string using a hash.
func getFallbackTunName(baseName, addr string) string {
hasher := sha256.New()
hasher.Write([]byte(addr))
hashBytes := hasher.Sum(nil)
// Use first 4 bytes -> 8 hex chars for brevity, respecting IFNAMSIZ limit.
shortHash := hex.EncodeToString(hashBytes[:4])
return fmt.Sprintf("%s%s", baseName, shortHash)
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Grant NET_ADMIN to the frpc process (root, --cap-add=NET_ADMIN, or ambient capabilities in the systemd unit)
- Confirm the route CIDR is valid and the TUN device name exists (ip link shows utunX) at failure time
- In restrictive runtimes (gVisor, some CI sandboxes), disable vnet or run frpc on the host network namespace
- Pair this with the modprobe/dev-tun steps from the TUN creation error — they usually fail together
Example fix
# before sudo -u frpcuser frpc -c frpc.toml # add route to 10.0.0.0/24 error: permission denied # after sudo setcap cap_net_admin+ep /usr/bin/frpc sudo -u frpcuser frpc -c frpc.toml
Defensive patterns
Strategy: validation
Validate before calling
// verify route-install capability before vnet start on linux
func canManageRoutes() bool {
return os.Geteuid() == 0 || hasCapNetAdmin()
} Try / catch
if err := setupVnetRoutes(); err != nil && strings.Contains(err.Error(), "add route to") {
// missing NET_ADMIN: report and disable vnet rather than retrying
log.Printf("vnet route install failed (need CAP_NET_ADMIN): %v", err)
} Prevention
- Grant NET_ADMIN to frpc (container flag, setcap, or systemd unit)
- Test in staging with the exact same sandboxing as production
- Check for SELinux/AppArmor/seccomp denials when capabilities look correct
When it happens
Trigger: frpc with vnet enabled runs without CAP_NET_ADMIN (container, dropped capabilities, non-root without caps); the interface index is stale; the netlink socket cannot talk to the kernel route table (network namespace restrictions, seccomp filtering netlink).
Common situations: Docker/K8s deployment missing --cap-add=NET_ADMIN even though /dev/net/tun works; systemd unit with CapabilityBoundingSet= stripping NET_ADMIN; gVisor/sandboxed runtimes where netlink route modification is unsupported.
Related errors
- failed to create TUN device '%s': %w
- no route found for destination %s
- no route found for source %s
- subdomain is not supported because this feature is not enabl
- '.' and '*' are not supported in subdomain
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/27e01691ef9ee05c.
Report an issue: GitHub.