|
| 1 | +#!/bin/sh |
| 2 | + |
| 3 | +# SPDX-License-Identifier: GPL-2.0 |
| 4 | +# Copyright (C) 2026-present Team LibreELEC (https://libreelec.tv) |
| 5 | + |
| 6 | +. /etc/profile |
| 7 | +oe_setup_addon service.tailscale |
| 8 | + |
| 9 | +TAILSCALED="$ADDON_DIR/bin/tailscaled" |
| 10 | +TAILSCALE="$ADDON_DIR/bin/tailscale" |
| 11 | +STATE_DIR="/storage/.cache/tailscale" |
| 12 | +SOCKET="/run/tailscale/tailscaled.sock" |
| 13 | + |
| 14 | +mkdir -p "$STATE_DIR" "$(dirname $SOCKET)" |
| 15 | + |
| 16 | +# Enable IP forwarding (required for exit node and subnet routing) |
| 17 | +if [ "$ts_exit_node" = "true" ] || [ "$ts_subnet_routes" = "true" ]; then |
| 18 | + echo 1 > /proc/sys/net/ipv4/ip_forward |
| 19 | + echo 1 > /proc/sys/net/ipv6/conf/all/forwarding |
| 20 | +fi |
| 21 | + |
| 22 | +# Ensure LAN traffic is not misrouted through tailscale's routing table. |
| 23 | +# tailscaled adds "from all lookup 52" ip rules that catch all traffic. |
| 24 | +# With --netfilter-mode=off no fwmark rules exist to bypass table 52, |
| 25 | +# so add high-priority rules to keep private subnet traffic in the main |
| 26 | +# routing table before tailscaled starts. |
| 27 | +for subnet in 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12; do |
| 28 | + ip rule add to $subnet priority 100 lookup main 2>/dev/null |
| 29 | +done |
| 30 | + |
| 31 | +# Start tailscaled daemon in the background |
| 32 | +$TAILSCALED -state "$STATE_DIR/tailscaled.state" -socket "$SOCKET" & |
| 33 | +TAILSCALED_PID=$! |
| 34 | + |
| 35 | +# Wait for the socket to become available |
| 36 | +for i in $(seq 1 30); do |
| 37 | + [ -S "$SOCKET" ] && break |
| 38 | + sleep 1 |
| 39 | +done |
| 40 | + |
| 41 | +if [ ! -S "$SOCKET" ]; then |
| 42 | + echo "Error: tailscaled socket not available after 30s" |
| 43 | + kill $TAILSCALED_PID 2>/dev/null |
| 44 | + exit 1 |
| 45 | +fi |
| 46 | + |
| 47 | +# Build tailscale up arguments - always specify all flags via --reset |
| 48 | +# to avoid "re-run with --reset" errors when changing settings. |
| 49 | +# Use --netfilter-mode=off to preserve LAN access (SSH, Kodi, etc.) |
| 50 | +TS_ARGS="--reset --netfilter-mode=off" |
| 51 | + |
| 52 | +# Set node hostname |
| 53 | +if [ "$ts_auto_hostname" != "true" ] && [ -n "$ts_hostname" ]; then |
| 54 | + TS_ARGS="$TS_ARGS --hostname=$ts_hostname" |
| 55 | +fi |
| 56 | + |
| 57 | +# Accept subnet routes from other nodes |
| 58 | +if [ "$ts_accept_routes" = "true" ]; then |
| 59 | + TS_ARGS="$TS_ARGS --accept-routes" |
| 60 | +fi |
| 61 | + |
| 62 | +# Advertise as exit node and use exit node are mutually exclusive |
| 63 | +if [ "$ts_exit_node" = "true" ] && [ "$ts_use_exit_node" != "true" ]; then |
| 64 | + TS_ARGS="$TS_ARGS --advertise-exit-node" |
| 65 | +elif [ "$ts_use_exit_node" = "true" ] && [ "$ts_exit_node" != "true" ] && [ -n "$ts_exit_node_host" ]; then |
| 66 | + TS_ARGS="$TS_ARGS --exit-node=$ts_exit_node_host" |
| 67 | + if [ "$ts_exit_node_allow_lan" = "true" ]; then |
| 68 | + TS_ARGS="$TS_ARGS --exit-node-allow-lan-access" |
| 69 | + fi |
| 70 | +fi |
| 71 | + |
| 72 | +# Advertise local subnet routes (independent of exit node) |
| 73 | +if [ "$ts_subnet_routes" = "true" ] && [ -n "$ts_subnets" ]; then |
| 74 | + TS_ARGS="$TS_ARGS --advertise-routes=$ts_subnets" |
| 75 | +fi |
| 76 | + |
| 77 | +# Connect or disconnect based on settings |
| 78 | +if [ "$ts_connect" = "true" ]; then |
| 79 | + $TAILSCALE --socket="$SOCKET" up $TS_ARGS |
| 80 | + |
| 81 | + # With --netfilter-mode=off tailscale creates no iptables rules. |
| 82 | + # Exit node and subnet routing need manual NAT and forwarding rules. |
| 83 | + if [ "$ts_exit_node" = "true" ] || [ "$ts_subnet_routes" = "true" ]; then |
| 84 | + iptables -A FORWARD -i tailscale0 -j ACCEPT 2>/dev/null |
| 85 | + iptables -A FORWARD -o tailscale0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null |
| 86 | + iptables -t nat -A POSTROUTING -s 100.64.0.0/10 ! -o tailscale0 -j MASQUERADE 2>/dev/null |
| 87 | + fi |
| 88 | +else |
| 89 | + $TAILSCALE --socket="$SOCKET" down 2>/dev/null |
| 90 | +fi |
| 91 | + |
| 92 | +# Wait for tailscaled to exit |
| 93 | +wait $TAILSCALED_PID |
0 commit comments