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

  1. Grant NET_ADMIN to the frpc process (root, --cap-add=NET_ADMIN, or ambient capabilities in the systemd unit)
  2. Confirm the route CIDR is valid and the TUN device name exists (ip link shows utunX) at failure time
  3. In restrictive runtimes (gVisor, some CI sandboxes), disable vnet or run frpc on the host network namespace
  4. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/27e01691ef9ee05c. Report an issue: GitHub.