cmd/containerboot: be more targeted when enabling IP forwarding.
Only enable forwarding for an IP family if any forwarding is required
for that family.
Fixes
@@ -91,9 +91,8 @@ func main() {
if err := ensureTunFile(); err != nil {
log.Fatalf("Unable to create tuntap device file: %v", err)
}
- }
if cfg.ProxyTo != "" || cfg.Routes != "" {
- if err := ensureIPForwarding(); err != nil {
+ if err := ensureIPForwarding(cfg.ProxyTo, strings.Split(cfg.Routes, ",")); err != nil {
log.Printf("Failed to enable IP forwarding: %v", err)
log.Printf("To run tailscale as a proxy or router container, IP forwarding must be enabled.")
if cfg.InKubernetes {
@@ -103,6 +102,7 @@ func main() {
}
}
}
+ }
// Context is used for all setup stuff until we're in steady
// state, so that if something is hanging we eventually time out
@@ -334,14 +334,46 @@ func ensureTunFile() error {
}
// ensureIPForwarding enables IPv4/IPv6 forwarding for the container.
-func ensureIPForwarding() error {
+func ensureIPForwarding(proxyTo string, routes []string) error {
+ var (
+ v4Forwarding, v6Forwarding bool
+ )
+ proxyIP, err := netip.ParseAddr(proxyTo)
+ if err != nil {
+ return fmt.Errorf("invalid proxy destination IP: %v", err)
+ }
+ if proxyIP.Is4() {
+ v4Forwarding = true
+ } else {
+ v6Forwarding = true
+ }
+ for _, route := range routes {
+ cidr, err := netip.ParsePrefix(route)
+ if err != nil {
+ return fmt.Errorf("invalid subnet route: %v", err)
+ }
+ if cidr.Addr().Is4() {
+ v4Forwarding = true
+ } else {
+ v6Forwarding = true
+ }
+ }
+
+ var paths []string
+ if v4Forwarding {
+ paths = append(paths, "/proc/sys/net/ipv4/ip_forward")
+ }
+ if v6Forwarding {
+ paths = append(paths, "/proc/sys/net/ipv6/conf/all/forwarding")
+ }
+
// In some common configurations (e.g. default docker,
// kubernetes), the container environment denies write access to
// most sysctls, including IP forwarding controls. Check the
// sysctl values before trying to change them, so that we
// gracefully do nothing if the container's already been set up
// properly by e.g. a k8s initContainer.
- for _, path := range []string{"/proc/sys/net/ipv4/ip_forward", "/proc/sys/net/ipv6/conf/all/forwarding"} {
+ for _, path := range paths {
bs, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("reading %q: %w", path, err)
