Skip to content

Commit 7424598

Browse files
committed
feat: configure peer relay port via GUI
Signed-off-by: Derek Kaser <[email protected]>
1 parent 2743971 commit 7424598

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ function showTailscaleConfig() {
121121
var res = await $.post('/plugins/tailscale/include/data/Config.php',{action: 'add-route', route: $('#tailscaleRoute').val()});
122122
showTailscaleConfig();
123123
}
124+
async function setTailscaleRelayPort() {
125+
$('div.spinner.fixed').show('fast');
126+
tailscaleControlsDisabled(true);
127+
var res = await $.post('/plugins/tailscale/include/data/Config.php',{action: 'set-relay-port', port: $('#tailscaleRelayPort').val()});
128+
showTailscaleConfig();
129+
}
124130
function isValidCIDR(ip) {
125131
if (ip === undefined) {
126132
return false;

src/usr/local/emhttp/plugins/tailscale/include/data/Config.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,24 @@
9999
}
100100
$exitSelect .= "</select>";
101101

102+
$relayPort = $tailscaleInfo->getRelayServerPort() ?: "";
103+
$relayPortWarning = $relayPort !== "" && ! $tailscaleInfo->isApprovedPeerRelay() ? $tr->tr("warnings.peer_relay_no_acl") : "&nbsp;";
104+
102105
$configRows = <<<EOT
103106
<tr><td>{$tr->tr("info.accept_routes")}</td><td>{$tailscaleConInfo->AcceptRoutes}</td><td style="text-align: right;">{$acceptRoutesButton}</td></tr>
104107
<tr><td>{$tr->tr("info.accept_dns")}</td><td>{$tailscaleConInfo->AcceptDNS}</td><td style="text-align: right;">{$acceptDNSButton}</td></tr>
105108
<tr><td>{$tr->tr("info.run_ssh")}</td><td>{$tailscaleConInfo->RunSSH}</td><td style="text-align: right;">{$sshButton}</td></tr>
106109
<tr><td>{$tr->tr("info.advertise_exit_node")}</td><td>{$tailscaleConInfo->AdvertiseExitNode}</td><td style="text-align: right;">{$advertiseExitButton}</td></tr>
107110
<tr><td>{$tr->tr("info.use_exit_node")}</td><td>&nbsp;</td><td style="text-align: right;">{$exitSelect}</td></tr>
108111
<tr><td>{$tr->tr("info.exit_node_local")}</td><td>{$tailscaleConInfo->ExitNodeLocal}</td><td style="text-align: right;">{$exitLocalButton}</td></tr>
112+
<tr>
113+
<td>{$tr->tr("info.peer_relay")}</td>
114+
<td><strong>{$relayPortWarning}</strong></td>
115+
<td style="text-align: right;">
116+
<input id='tailscaleRelayPort' class="narrow" type='number' min='0' max='65535' value='{$relayPort}' placeholder='Disabled' oninput='$("#tailscaleRelaySave").prop("disabled", false)'>
117+
<input id='tailscaleRelaySave' disabled type='button'value='{$tr->tr("save")}' onclick='setTailscaleRelayPort()'>
118+
</td>
119+
</tr>
109120
110121
EOT;
111122

@@ -333,6 +344,28 @@
333344
$utils->logmsg("Object: " . json_encode($serveConfig->getConfig(), JSON_UNESCAPED_SLASHES));
334345
$localAPI->setServeConfig($serveConfig);
335346
break;
347+
case 'set-relay-port':
348+
if ( ! isset($_POST['port'])) {
349+
throw new \Exception("Missing port parameter");
350+
}
351+
352+
$port = null;
353+
354+
if ($_POST['port'] === '') {
355+
$port = null;
356+
} elseif (ctype_digit($_POST['port'])) {
357+
$port = intval($_POST['port']);
358+
if (($port < 0) || ($port > 65535)) {
359+
throw new \Exception("Port out of range: {$_POST['port']}");
360+
}
361+
} else {
362+
throw new \Exception("Invalid port: {$_POST['port']}");
363+
}
364+
365+
$utils->logmsg("Setting relay server port to: {$port}");
366+
367+
$localAPI->patchPref("RelayServerPort", $port);
368+
break;
336369
}
337370
} catch (\Throwable $e) {
338371
file_put_contents("/var/log/tailscale-error.log", print_r($e, true) . PHP_EOL, FILE_APPEND);

src/usr/local/emhttp/plugins/tailscale/locales/en_US.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"tailscale_disabled": "Tailscale is currently disabled. It can be enabled via the Settings tab.",
2929
"tailscale_lock": "Tailscale Lock",
3030
"warning": "Warning",
31+
"save": "Save",
3132
"settings": {
3233
"basic": "Basic View",
3334
"advanced": "Advanced View",
@@ -87,6 +88,7 @@
8788
"connected_via": "Connected via Tailscale",
8889
"funnel_port": "Funnel Port for WebGUI",
8990
"port_in_use": "Port in Use",
91+
"peer_relay": "Peer Relay Port",
9092
"lock": {
9193
"node_key": "Node Key",
9294
"public_key": "Public Key",
@@ -102,7 +104,8 @@
102104
"subnet": "Accepting Tailscale subnets on your Unraid server can disrupt local network connectivity in certain network configurations. Accepting routes is not required for your Unraid server to function as a subnet router or exit node. Only enable this option if your Unraid server needs to connect to remote subnets advertised by other devices.",
103105
"dns": "Enabling Tailscale MagicDNS on your server can disrupt name resolution inside Docker containers, potentially causing connectivity issues for applications. MagicDNS does not need to be enabled on the server for you to access your Unraid server using MagicDNS names (e.g., 'unraid.tailnet.ts.net') from other devices. Enabling 'Add Peers to /etc/hosts' is a safer alternative that allows Tailscale names to be used on the server.",
104106
"caution": "Proceed with caution and ensure you understand the implications of this change before continuing.",
105-
"more_info": "For more information:"
107+
"more_info": "For more information:",
108+
"peer_relay_no_acl": "Not configured in Tailnet policy (access controls)."
106109
},
107110
"lock": {
108111
"sign": "Sign Nodes",

src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Info.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,4 +471,31 @@ public function getDNSName(): string
471471

472472
return $this->status->Self->DNSName;
473473
}
474+
475+
public function isApprovedPeerRelay(): bool
476+
{
477+
$netmapRules = (array) $this->localAPI->getPacketFilterRules();
478+
479+
// Parse the packet filter rules to see if peer relay is approved
480+
// TODO: Get a better way to do this from Tailscale
481+
foreach ($netmapRules as $key => $rule) {
482+
if (isset($rule->CapGrant) && is_array($rule->CapGrant)) {
483+
foreach ($rule->CapGrant as $capGrant) {
484+
if (is_object($capGrant) && isset($capGrant->CapMap) && is_object($capGrant->CapMap) && isset($capGrant->CapMap->{'tailscale.com/cap/relay'})) {
485+
return true;
486+
}
487+
}
488+
}
489+
}
490+
491+
return false;
492+
}
493+
494+
public function getRelayServerPort(): int|false
495+
{
496+
if (isset($this->prefs->RelayServerPort) && is_int($this->prefs->RelayServerPort)) {
497+
return $this->prefs->RelayServerPort;
498+
}
499+
return false;
500+
}
474501
}

src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ public function getServeConfig(): \stdClass
101101
return (object) json_decode($this->tailscaleLocalAPI('v0/serve-config'));
102102
}
103103

104+
public function getPacketFilterRules(): \stdClass
105+
{
106+
return (object) json_decode($this->tailscaleLocalAPI('v0/debug-packet-filter-rules'));
107+
}
108+
104109
public function resetServeConfig(): void
105110
{
106111
$this->tailscaleLocalAPI("v0/serve-config", APIMethods::POST, new \stdClass());

0 commit comments

Comments
 (0)