From 35c232737972853b9d0a18c891b78236ad83e5e3 Mon Sep 17 00:00:00 2001 From: Derek Kaser Date: Tue, 27 Jun 2023 23:33:31 -0700 Subject: [PATCH] feat: add tailnet lock support --- .php-cs-fixer.dist.php | 1 - .../plugins/tailscale/Tailscale-2-Lock.page | 49 ++++++++++++++ ...cale-2-Info.page => Tailscale-3-Info.page} | 0 ...cale-3-Help.page => Tailscale-4-Help.page} | 0 ...lscale-4-Log.page => Tailscale-5-Log.page} | 0 .../plugins/tailscale/approve-nodes.php | 9 +++ .../tailscale/include/tailscale-lock.php | 66 +++++++++++++++++++ .../tailscale/include/tailscale-status.php | 6 ++ .../plugins/tailscale/include/webgui-info.php | 16 ++++- .../tailscale/include/webgui-interface.php | 11 +++- 10 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Lock.page rename src/usr/local/emhttp/plugins/tailscale/{Tailscale-2-Info.page => Tailscale-3-Info.page} (100%) rename src/usr/local/emhttp/plugins/tailscale/{Tailscale-3-Help.page => Tailscale-4-Help.page} (100%) rename src/usr/local/emhttp/plugins/tailscale/{Tailscale-4-Log.page => Tailscale-5-Log.page} (100%) create mode 100755 src/usr/local/emhttp/plugins/tailscale/approve-nodes.php create mode 100644 src/usr/local/emhttp/plugins/tailscale/include/tailscale-lock.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 50e80c5..664c92c 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -2,7 +2,6 @@ $finder = PhpCsFixer\Finder::create() ->files() - ->name('*.page') ->in(__DIR__) ; diff --git a/src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Lock.page b/src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Lock.page new file mode 100644 index 0000000..49dc17c --- /dev/null +++ b/src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Lock.page @@ -0,0 +1,49 @@ +Menu="Tailscale" +Icon="tailscale.png" +Title="Lock" +Type="xmenu" +Tag="lock" +--- +"; + echo "If you wish to make this a signing node, you will need to trust the following key from a signing node:

"; + echo $tailscale_output['lock_pubkey']; + break; + case $tailscale_output['lock_enabled']: + echo "Your tailnet has lock enabled and the current node is not signed. This node will not be able to communicate with the tailnet.
"; + echo "To enable this node, trust the following key from a signing node:

"; + echo $tailscale_output['lock_nodekey']; + break; + default: + echo "Your tailnet does not have lock enabled."; + break; +} + +if ($signingNode) { +?> + +
+ + +### Tailscale Lock: Approve Nodes + + + $lockKey) { + echo ""; +} +?> +
{$lockHost}
{$lockKey}
+ + +
+ + + \ No newline at end of file diff --git a/src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Info.page b/src/usr/local/emhttp/plugins/tailscale/Tailscale-3-Info.page similarity index 100% rename from src/usr/local/emhttp/plugins/tailscale/Tailscale-2-Info.page rename to src/usr/local/emhttp/plugins/tailscale/Tailscale-3-Info.page diff --git a/src/usr/local/emhttp/plugins/tailscale/Tailscale-3-Help.page b/src/usr/local/emhttp/plugins/tailscale/Tailscale-4-Help.page similarity index 100% rename from src/usr/local/emhttp/plugins/tailscale/Tailscale-3-Help.page rename to src/usr/local/emhttp/plugins/tailscale/Tailscale-4-Help.page diff --git a/src/usr/local/emhttp/plugins/tailscale/Tailscale-4-Log.page b/src/usr/local/emhttp/plugins/tailscale/Tailscale-5-Log.page similarity index 100% rename from src/usr/local/emhttp/plugins/tailscale/Tailscale-4-Log.page rename to src/usr/local/emhttp/plugins/tailscale/Tailscale-5-Log.page diff --git a/src/usr/local/emhttp/plugins/tailscale/approve-nodes.php b/src/usr/local/emhttp/plugins/tailscale/approve-nodes.php new file mode 100755 index 0000000..d9592d1 --- /dev/null +++ b/src/usr/local/emhttp/plugins/tailscale/approve-nodes.php @@ -0,0 +1,9 @@ +#!/usr/bin/php -q + $value) { + logmsg("Tailnet lock: signing {$value}"); + exec("tailscale lock sign {$value}"); +} diff --git a/src/usr/local/emhttp/plugins/tailscale/include/tailscale-lock.php b/src/usr/local/emhttp/plugins/tailscale/include/tailscale-lock.php new file mode 100644 index 0000000..047d13b --- /dev/null +++ b/src/usr/local/emhttp/plugins/tailscale/include/tailscale-lock.php @@ -0,0 +1,66 @@ +Enabled; +} + +function getTailscaleLockSigned($lock) +{ + if ( ! getTailscaleLockEnabled($lock)) { + return false; + } + + return $lock->NodeKeySigned; +} + +function getTailscaleLockNodekey($lock) +{ + if ( ! getTailscaleLockEnabled($lock)) { + return false; + } + + return $lock->NodeKey; +} + +function getTailscaleLockPubkey($lock) +{ + if ( ! getTailscaleLockEnabled($lock)) { + return false; + } + + return $lock->PublicKey; +} + +function getTailscaleLockSigning($lock) +{ + if ( ! getTailscaleLockSigned($lock)) { + return false; + } + + $isTrusted = false; + $myKey = getTailscaleLockPubkey($lock); + + foreach ($lock->TrustedKeys as $item) { + if ($item->Key == $myKey) { + $isTrusted = true; + } + } + + return $isTrusted; +} + +function getTailscaleLockPending($lock) +{ + if ( ! getTailscaleLockSigning($lock)) { + return array(); + } + + $pending = array(); + + foreach ($lock->FilteredPeers as $item) { + $pending[$item->Name] = $item->NodeKey; + } + + return $pending; +} diff --git a/src/usr/local/emhttp/plugins/tailscale/include/tailscale-status.php b/src/usr/local/emhttp/plugins/tailscale/include/tailscale-status.php index 3d6761a..c494f1a 100644 --- a/src/usr/local/emhttp/plugins/tailscale/include/tailscale-status.php +++ b/src/usr/local/emhttp/plugins/tailscale/include/tailscale-status.php @@ -11,3 +11,9 @@ function getTailscalePrefs() exec("tailscale debug prefs", $out_prefs); return json_decode(implode($out_prefs)); } + +function getTailscaleLock() +{ + exec("tailscale lock status -json=true", $out_status); + return json_decode(implode($out_status)); +} diff --git a/src/usr/local/emhttp/plugins/tailscale/include/webgui-info.php b/src/usr/local/emhttp/plugins/tailscale/include/webgui-info.php index b8d55a5..07788b0 100644 --- a/src/usr/local/emhttp/plugins/tailscale/include/webgui-info.php +++ b/src/usr/local/emhttp/plugins/tailscale/include/webgui-info.php @@ -5,7 +5,7 @@ function printRow($title, $value) return "{$title}{$value}" . PHP_EOL; } -function getStatusInfo($status, $prefs) +function getStatusInfo($status, $prefs, $lock) { $tsVersion = isset($status->Version) ? $status->Version : "Unknown"; $keyExpiration = isset($status->Self->KeyExpiry) ? $status->Self->KeyExpiry : "Disabled"; @@ -14,6 +14,7 @@ function getStatusInfo($status, $prefs) $tags = isset($status->Self->Tags) ? implode("
", $status->Self->Tags) : ""; $loggedIn = isset($prefs->LoggedOut) ? ($prefs->LoggedOut ? "No" : "Yes") : "Unknown"; $tsHealth = isset($status->Health) ? implode("
", $status->Health) : ""; + $lockEnabled = getTailscaleLockEnabled($lock) ? "Yes" : "No"; $output = ""; $output .= printRow("Tailscale Version", $tsVersion); @@ -23,6 +24,19 @@ function getStatusInfo($status, $prefs) $output .= printRow("Online", $online); $output .= printRow("Key Expiration", $keyExpiration); $output .= printRow("Tags", $tags); + $output .= printRow("Tailscale Lock: Enabled", $lockEnabled); + + if (getTailscaleLockEnabled($lock)) { + $lockSigned = getTailscaleLockSigned($lock) ? "Yes" : "No"; + $lockSigning = getTailscaleLockSigning($lock) ? "Yes" : "No"; + $pubKey = getTailscaleLockPubkey($lock); + $nodeKey = getTailscaleLockNodekey($lock); + + $output .= printRow("Tailscale Lock: Node Key Signed", $lockSigned); + $output .= printRow("Tailscale Lock: Is Signing Node", $lockSigning); + $output .= printRow("Tailscale Lock: Node Key", $nodeKey); + $output .= printRow("Tailscale Lock: Public Key", $pubKey); + } return $output; } diff --git a/src/usr/local/emhttp/plugins/tailscale/include/webgui-interface.php b/src/usr/local/emhttp/plugins/tailscale/include/webgui-interface.php index 14364dd..229cc56 100644 --- a/src/usr/local/emhttp/plugins/tailscale/include/webgui-interface.php +++ b/src/usr/local/emhttp/plugins/tailscale/include/webgui-interface.php @@ -4,15 +4,24 @@ require_once "{$docroot}/plugins/tailscale/include/tailscale-status.php"; require_once "{$docroot}/plugins/tailscale/include/webgui-info.php"; require_once "{$docroot}/plugins/tailscale/include/webgui-key-expiration.php"; +require_once "{$docroot}/plugins/tailscale/include/tailscale-lock.php"; $tailscale_output = array(); $tailscale_status = getTailscaleStatus(); $tailscale_prefs = getTailscalePrefs(); +$tailscale_lock = getTailscaleLock(); $tailscale_output['key_expiry_warning'] = getKeyExpirationWarning($tailscale_status); -$tailscale_output['status_info'] = getStatusInfo($tailscale_status, $tailscale_prefs); +$tailscale_output['status_info'] = getStatusInfo($tailscale_status, $tailscale_prefs, $tailscale_lock); $tailscale_output['connection_info'] = getConnectionInfo($tailscale_status, $tailscale_prefs); $tailscale_output['attach_file_tree'] = ($var['fsState'] == 'Started') ? "$('#taildropdir').fileTreeAttach();" : ""; $tailscale_output['background_color'] = strstr('white,azure', $display['theme']) ? '#f2f2f2' : '#1c1c1c'; + +$tailscale_output['lock_enabled'] = getTailscaleLockEnabled($tailscale_lock); +$tailscale_output['lock_signed'] = getTailscaleLockSigned($tailscale_lock); +$tailscale_output['lock_signing'] = getTailscaleLockSigning($tailscale_lock); +$tailscale_output['lock_pending'] = getTailscaleLockPending($tailscale_lock); +$tailscale_output['lock_pubkey'] = getTailscaleLockPubkey($tailscale_lock); +$tailscale_output['lock_nodekey'] = getTailscaleLockNodekey($tailscale_lock);