diff --git a/aarch64/app/Tailscale_VPN_run b/aarch64/app/Tailscale_VPN_run
index 1bad46e..5dc76a1 100644
--- a/aarch64/app/Tailscale_VPN_run
+++ b/aarch64/app/Tailscale_VPN_run
@@ -18,6 +18,8 @@ CUSTOM_SERVER=""
AUTH_KEY=""
CONF_HTTP="8080"
CONF_SOCKS="1080"
+ACCEPT_DNS="false"
+ACCEPT_ROUTES="false"
if [ -f "$STATE_DIR/params.conf" ]; then
. "$STATE_DIR/params.conf"
@@ -56,7 +58,7 @@ TAILSCALED_PID=$!
sleep 2
-TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --hostname=$(hostname)"
+TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
if [ -n "$CUSTOM_SERVER" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
@@ -66,6 +68,14 @@ if [ -n "$AUTH_KEY" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
fi
+if [ "$ACCEPT_DNS" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
+fi
+
+if [ "$ACCEPT_ROUTES" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
+fi
+
eval $TAILSCALE_CMD
UP_EXIT=$?
diff --git a/aarch64/app/html/index.html b/aarch64/app/html/index.html
index 8aeaf67..e6b11e7 100644
--- a/aarch64/app/html/index.html
+++ b/aarch64/app/html/index.html
@@ -272,6 +272,23 @@
.save-status.ok { color: var(--green); }
.save-status.err { color: var(--red); }
+ /* Toggle switch */
+ .toggle-row { display: flex; align-items: flex-start; gap: 12px; }
+ .toggle-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; margin-top: 2px; }
+ .toggle-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
+ .toggle-slider {
+ position: absolute; cursor: pointer; inset: 0;
+ background: var(--border); border-radius: 20px; transition: background 0.2s;
+ }
+ .toggle-slider:before {
+ content: ''; position: absolute;
+ height: 14px; width: 14px; left: 3px; bottom: 3px;
+ background: white; border-radius: 50%; transition: transform 0.2s;
+ }
+ .toggle-switch input:checked + .toggle-slider { background: var(--green); }
+ .toggle-switch input:checked + .toggle-slider:before { transform: translateX(16px); }
+ .toggle-info { flex: 1; }
+
/* Refresh indicator */
.refresh-bar {
display: flex;
@@ -425,6 +442,26 @@
Port for the SOCKS5 proxy. Default: 1080.
+
+
+
+
+
+
+
Accept DNS
+
Pass --accept-dns=true to tailscale up. Allows the tailnet to push DNS settings to this device. Off by default to avoid overriding the camera's DNS configuration.
+
+
+
+
+
+
+
+
+
Accept Routes
+
Pass --accept-routes=true to tailscale up. Allows this device to use subnet routes advertised by other nodes in the tailnet.
+
+
Save & Restart
@@ -779,6 +816,8 @@
var authInput = document.getElementById('input-authkey');
var httpPortInput = document.getElementById('input-http-port');
var socksPortInput= document.getElementById('input-socks-port');
+ var acceptDnsInput = document.getElementById('input-accept-dns');
+ var acceptRoutesInput = document.getElementById('input-accept-routes');
var saveBtn = document.getElementById('save-btn');
var saveStatus = document.getElementById('save-status');
@@ -790,10 +829,14 @@
var am = txt.match(/root\.\S+\.AuthKey=(.*)/);
var hm = txt.match(/root\.\S+\.HttpProxyPort=(.*)/);
var km = txt.match(/root\.\S+\.Socks5Port=(.*)/);
+ var dm = txt.match(/root\.\S+\.AcceptDNS=(.*)/);
+ var rm = txt.match(/root\.\S+\.AcceptRoutes=(.*)/);
if (sm) serverInput.value = sm[1].trim();
if (am) authInput.value = am[1].trim();
if (hm) httpPortInput.value = hm[1].trim();
if (km) socksPortInput.value = km[1].trim();
+ if (dm) acceptDnsInput.checked = dm[1].trim() === 'true';
+ if (rm) acceptRoutesInput.checked = rm[1].trim() === 'true';
// Update proxy display card with authoritative param values
// and overwrite the localStorage cache so stale ports don't win on next render
var httpPort = hm ? hm[1].trim() : null;
@@ -819,7 +862,9 @@
'&root.' + APP + '.CustomServer=' + encodeURIComponent(serverInput.value.trim()) +
'&root.' + APP + '.AuthKey=' + encodeURIComponent(authInput.value.trim()) +
'&root.' + APP + '.HttpProxyPort=' + encodeURIComponent(httpPort) +
- '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort);
+ '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort) +
+ '&root.' + APP + '.AcceptDNS=' + (acceptDnsInput.checked ? 'true' : 'false') +
+ '&root.' + APP + '.AcceptRoutes=' + (acceptRoutesInput.checked ? 'true' : 'false');
fetch(PARAM_URL, {
method: 'POST',
credentials: 'same-origin',
diff --git a/aarch64/app/manifest.json b/aarch64/app/manifest.json
index 10fb07b..a3168e4 100644
--- a/aarch64/app/manifest.json
+++ b/aarch64/app/manifest.json
@@ -33,6 +33,16 @@
"name": "Socks5Port",
"default": "1080",
"type": "string"
+ },
+ {
+ "name": "AcceptDNS",
+ "default": "false",
+ "type": "string"
+ },
+ {
+ "name": "AcceptRoutes",
+ "default": "false",
+ "type": "string"
}
]
}
diff --git a/aarch64/app/param_bridge.c b/aarch64/app/param_bridge.c
index e2bd24a..b02a187 100644
--- a/aarch64/app/param_bridge.c
+++ b/aarch64/app/param_bridge.c
@@ -43,6 +43,8 @@ static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
static char *cfg_http_proxy_port = NULL;
static char *cfg_socks5_port = NULL;
+static char *cfg_accept_dns = NULL;
+static char *cfg_accept_routes = NULL;
static void cache_set(char **field, const char *value) {
if (!value) return;
@@ -139,6 +141,8 @@ static void load_config_cache(AXParameter *handle) {
LOAD("AuthKey", cfg_auth_key)
LOAD("HttpProxyPort", cfg_http_proxy_port)
LOAD("Socks5Port", cfg_socks5_port)
+ LOAD("AcceptDNS", cfg_accept_dns)
+ LOAD("AcceptRoutes", cfg_accept_routes)
#undef LOAD
}
@@ -153,6 +157,8 @@ static void write_config_file(void) {
fprintf(f, "AUTH_KEY=%s\n", cache_get(&cfg_auth_key, ""));
fprintf(f, "CONF_HTTP=%s\n", cache_get(&cfg_http_proxy_port, "8080"));
fprintf(f, "CONF_SOCKS=%s\n", cache_get(&cfg_socks5_port, "1080"));
+ fprintf(f, "ACCEPT_DNS=%s\n", cache_get(&cfg_accept_dns, "false"));
+ fprintf(f, "ACCEPT_ROUTES=%s\n", cache_get(&cfg_accept_routes, "false"));
fclose(f);
chmod(CONFIG_FILE, 0600);
syslog(LOG_INFO, "config updated: http=%s socks=%s server=%s",
@@ -185,6 +191,8 @@ static void parameter_changed(const gchar *name, const gchar *value,
else if (strcmp(short_name, "AuthKey") == 0) cache_set(&cfg_auth_key, value);
else if (strcmp(short_name, "HttpProxyPort") == 0) cache_set(&cfg_http_proxy_port, value);
else if (strcmp(short_name, "Socks5Port") == 0) cache_set(&cfg_socks5_port, value);
+ else if (strcmp(short_name, "AcceptDNS") == 0) cache_set(&cfg_accept_dns, value);
+ else if (strcmp(short_name, "AcceptRoutes") == 0) cache_set(&cfg_accept_routes, value);
if (reload_timer_id)
g_source_remove(reload_timer_id);
@@ -225,7 +233,8 @@ int main(void) {
start_child();
const char *params[] = {
- "CustomServer", "AuthKey", "HttpProxyPort", "Socks5Port"
+ "CustomServer", "AuthKey", "HttpProxyPort", "Socks5Port",
+ "AcceptDNS", "AcceptRoutes"
};
for (size_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
if (!ax_parameter_register_callback(handle, params[i],
diff --git a/aarch64_ROOT/app/Tailscale_VPN_run b/aarch64_ROOT/app/Tailscale_VPN_run
index 1bf556a..dfdb724 100644
--- a/aarch64_ROOT/app/Tailscale_VPN_run
+++ b/aarch64_ROOT/app/Tailscale_VPN_run
@@ -15,6 +15,8 @@ chmod 755 $TAILSCALE_PATH
CUSTOM_SERVER=""
AUTH_KEY=""
+ACCEPT_DNS="false"
+ACCEPT_ROUTES="false"
if [ -f "$STATE_DIR/params.conf" ]; then
. "$STATE_DIR/params.conf"
@@ -30,7 +32,7 @@ TAILSCALED_PID=$!
sleep 2
-TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --accept-routes --hostname=$(hostname)"
+TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
if [ -n "$CUSTOM_SERVER" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
@@ -40,6 +42,14 @@ if [ -n "$AUTH_KEY" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
fi
+if [ "$ACCEPT_DNS" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
+fi
+
+if [ "$ACCEPT_ROUTES" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
+fi
+
eval $TAILSCALE_CMD
UP_EXIT=$?
diff --git a/aarch64_ROOT/app/html/index.html b/aarch64_ROOT/app/html/index.html
index 8aeaf67..e6b11e7 100644
--- a/aarch64_ROOT/app/html/index.html
+++ b/aarch64_ROOT/app/html/index.html
@@ -272,6 +272,23 @@
.save-status.ok { color: var(--green); }
.save-status.err { color: var(--red); }
+ /* Toggle switch */
+ .toggle-row { display: flex; align-items: flex-start; gap: 12px; }
+ .toggle-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; margin-top: 2px; }
+ .toggle-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
+ .toggle-slider {
+ position: absolute; cursor: pointer; inset: 0;
+ background: var(--border); border-radius: 20px; transition: background 0.2s;
+ }
+ .toggle-slider:before {
+ content: ''; position: absolute;
+ height: 14px; width: 14px; left: 3px; bottom: 3px;
+ background: white; border-radius: 50%; transition: transform 0.2s;
+ }
+ .toggle-switch input:checked + .toggle-slider { background: var(--green); }
+ .toggle-switch input:checked + .toggle-slider:before { transform: translateX(16px); }
+ .toggle-info { flex: 1; }
+
/* Refresh indicator */
.refresh-bar {
display: flex;
@@ -425,6 +442,26 @@
Port for the SOCKS5 proxy. Default: 1080.
+
+
+
+
+
+
+
Accept DNS
+
Pass --accept-dns=true to tailscale up. Allows the tailnet to push DNS settings to this device. Off by default to avoid overriding the camera's DNS configuration.
+
+
+
+
+
+
+
+
+
Accept Routes
+
Pass --accept-routes=true to tailscale up. Allows this device to use subnet routes advertised by other nodes in the tailnet.
+
+
Save & Restart
@@ -779,6 +816,8 @@
var authInput = document.getElementById('input-authkey');
var httpPortInput = document.getElementById('input-http-port');
var socksPortInput= document.getElementById('input-socks-port');
+ var acceptDnsInput = document.getElementById('input-accept-dns');
+ var acceptRoutesInput = document.getElementById('input-accept-routes');
var saveBtn = document.getElementById('save-btn');
var saveStatus = document.getElementById('save-status');
@@ -790,10 +829,14 @@
var am = txt.match(/root\.\S+\.AuthKey=(.*)/);
var hm = txt.match(/root\.\S+\.HttpProxyPort=(.*)/);
var km = txt.match(/root\.\S+\.Socks5Port=(.*)/);
+ var dm = txt.match(/root\.\S+\.AcceptDNS=(.*)/);
+ var rm = txt.match(/root\.\S+\.AcceptRoutes=(.*)/);
if (sm) serverInput.value = sm[1].trim();
if (am) authInput.value = am[1].trim();
if (hm) httpPortInput.value = hm[1].trim();
if (km) socksPortInput.value = km[1].trim();
+ if (dm) acceptDnsInput.checked = dm[1].trim() === 'true';
+ if (rm) acceptRoutesInput.checked = rm[1].trim() === 'true';
// Update proxy display card with authoritative param values
// and overwrite the localStorage cache so stale ports don't win on next render
var httpPort = hm ? hm[1].trim() : null;
@@ -819,7 +862,9 @@
'&root.' + APP + '.CustomServer=' + encodeURIComponent(serverInput.value.trim()) +
'&root.' + APP + '.AuthKey=' + encodeURIComponent(authInput.value.trim()) +
'&root.' + APP + '.HttpProxyPort=' + encodeURIComponent(httpPort) +
- '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort);
+ '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort) +
+ '&root.' + APP + '.AcceptDNS=' + (acceptDnsInput.checked ? 'true' : 'false') +
+ '&root.' + APP + '.AcceptRoutes=' + (acceptRoutesInput.checked ? 'true' : 'false');
fetch(PARAM_URL, {
method: 'POST',
credentials: 'same-origin',
diff --git a/aarch64_ROOT/app/manifest.json b/aarch64_ROOT/app/manifest.json
index 52dd092..9c7cc8f 100644
--- a/aarch64_ROOT/app/manifest.json
+++ b/aarch64_ROOT/app/manifest.json
@@ -27,6 +27,16 @@
"name": "AuthKey",
"default": "",
"type": "string"
+ },
+ {
+ "name": "AcceptDNS",
+ "default": "false",
+ "type": "string"
+ },
+ {
+ "name": "AcceptRoutes",
+ "default": "false",
+ "type": "string"
}
]
}
diff --git a/aarch64_ROOT/app/param_bridge.c b/aarch64_ROOT/app/param_bridge.c
index 5337f79..84a4f26 100644
--- a/aarch64_ROOT/app/param_bridge.c
+++ b/aarch64_ROOT/app/param_bridge.c
@@ -31,6 +31,8 @@ static guint reload_timer_id = 0;
static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
+static char *cfg_accept_dns = NULL;
+static char *cfg_accept_routes = NULL;
static void cache_set(char **field, const char *value) {
if (!value) return;
@@ -119,6 +121,8 @@ static void load_config_cache(AXParameter *handle) {
LOAD("CustomServer", cfg_custom_server)
LOAD("AuthKey", cfg_auth_key)
+ LOAD("AcceptDNS", cfg_accept_dns)
+ LOAD("AcceptRoutes", cfg_accept_routes)
#undef LOAD
}
@@ -131,6 +135,8 @@ static void write_config_file(void) {
}
fprintf(f, "CUSTOM_SERVER=%s\n", cache_get(&cfg_custom_server, ""));
fprintf(f, "AUTH_KEY=%s\n", cache_get(&cfg_auth_key, ""));
+ fprintf(f, "ACCEPT_DNS=%s\n", cache_get(&cfg_accept_dns, "false"));
+ fprintf(f, "ACCEPT_ROUTES=%s\n", cache_get(&cfg_accept_routes, "false"));
fclose(f);
chmod(CONFIG_FILE, 0600);
syslog(LOG_INFO, "config updated: server=%s",
@@ -156,6 +162,8 @@ static void parameter_changed(const gchar *name, const gchar *value,
if (strcmp(short_name, "CustomServer") == 0) cache_set(&cfg_custom_server, value);
else if (strcmp(short_name, "AuthKey") == 0) cache_set(&cfg_auth_key, value);
+ else if (strcmp(short_name, "AcceptDNS") == 0) cache_set(&cfg_accept_dns, value);
+ else if (strcmp(short_name, "AcceptRoutes") == 0) cache_set(&cfg_accept_routes, value);
if (reload_timer_id)
g_source_remove(reload_timer_id);
@@ -190,7 +198,7 @@ int main(void) {
write_config_file();
start_child();
- const char *params[] = { "CustomServer", "AuthKey" };
+ const char *params[] = { "CustomServer", "AuthKey", "AcceptDNS", "AcceptRoutes" };
for (size_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
if (!ax_parameter_register_callback(handle, params[i],
parameter_changed, handle, &error)) {
diff --git a/arm/app/Tailscale_VPN_run b/arm/app/Tailscale_VPN_run
index 1bad46e..5dc76a1 100644
--- a/arm/app/Tailscale_VPN_run
+++ b/arm/app/Tailscale_VPN_run
@@ -18,6 +18,8 @@ CUSTOM_SERVER=""
AUTH_KEY=""
CONF_HTTP="8080"
CONF_SOCKS="1080"
+ACCEPT_DNS="false"
+ACCEPT_ROUTES="false"
if [ -f "$STATE_DIR/params.conf" ]; then
. "$STATE_DIR/params.conf"
@@ -56,7 +58,7 @@ TAILSCALED_PID=$!
sleep 2
-TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --hostname=$(hostname)"
+TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
if [ -n "$CUSTOM_SERVER" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
@@ -66,6 +68,14 @@ if [ -n "$AUTH_KEY" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
fi
+if [ "$ACCEPT_DNS" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
+fi
+
+if [ "$ACCEPT_ROUTES" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
+fi
+
eval $TAILSCALE_CMD
UP_EXIT=$?
diff --git a/arm/app/html/index.html b/arm/app/html/index.html
index 8aeaf67..e6b11e7 100644
--- a/arm/app/html/index.html
+++ b/arm/app/html/index.html
@@ -272,6 +272,23 @@
.save-status.ok { color: var(--green); }
.save-status.err { color: var(--red); }
+ /* Toggle switch */
+ .toggle-row { display: flex; align-items: flex-start; gap: 12px; }
+ .toggle-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; margin-top: 2px; }
+ .toggle-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
+ .toggle-slider {
+ position: absolute; cursor: pointer; inset: 0;
+ background: var(--border); border-radius: 20px; transition: background 0.2s;
+ }
+ .toggle-slider:before {
+ content: ''; position: absolute;
+ height: 14px; width: 14px; left: 3px; bottom: 3px;
+ background: white; border-radius: 50%; transition: transform 0.2s;
+ }
+ .toggle-switch input:checked + .toggle-slider { background: var(--green); }
+ .toggle-switch input:checked + .toggle-slider:before { transform: translateX(16px); }
+ .toggle-info { flex: 1; }
+
/* Refresh indicator */
.refresh-bar {
display: flex;
@@ -425,6 +442,26 @@
Port for the SOCKS5 proxy. Default: 1080.
+
+
+
+
+
+
+
Accept DNS
+
Pass --accept-dns=true to tailscale up. Allows the tailnet to push DNS settings to this device. Off by default to avoid overriding the camera's DNS configuration.
+
+
+
+
+
+
+
+
+
Accept Routes
+
Pass --accept-routes=true to tailscale up. Allows this device to use subnet routes advertised by other nodes in the tailnet.
+
+
Save & Restart
@@ -779,6 +816,8 @@
var authInput = document.getElementById('input-authkey');
var httpPortInput = document.getElementById('input-http-port');
var socksPortInput= document.getElementById('input-socks-port');
+ var acceptDnsInput = document.getElementById('input-accept-dns');
+ var acceptRoutesInput = document.getElementById('input-accept-routes');
var saveBtn = document.getElementById('save-btn');
var saveStatus = document.getElementById('save-status');
@@ -790,10 +829,14 @@
var am = txt.match(/root\.\S+\.AuthKey=(.*)/);
var hm = txt.match(/root\.\S+\.HttpProxyPort=(.*)/);
var km = txt.match(/root\.\S+\.Socks5Port=(.*)/);
+ var dm = txt.match(/root\.\S+\.AcceptDNS=(.*)/);
+ var rm = txt.match(/root\.\S+\.AcceptRoutes=(.*)/);
if (sm) serverInput.value = sm[1].trim();
if (am) authInput.value = am[1].trim();
if (hm) httpPortInput.value = hm[1].trim();
if (km) socksPortInput.value = km[1].trim();
+ if (dm) acceptDnsInput.checked = dm[1].trim() === 'true';
+ if (rm) acceptRoutesInput.checked = rm[1].trim() === 'true';
// Update proxy display card with authoritative param values
// and overwrite the localStorage cache so stale ports don't win on next render
var httpPort = hm ? hm[1].trim() : null;
@@ -819,7 +862,9 @@
'&root.' + APP + '.CustomServer=' + encodeURIComponent(serverInput.value.trim()) +
'&root.' + APP + '.AuthKey=' + encodeURIComponent(authInput.value.trim()) +
'&root.' + APP + '.HttpProxyPort=' + encodeURIComponent(httpPort) +
- '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort);
+ '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort) +
+ '&root.' + APP + '.AcceptDNS=' + (acceptDnsInput.checked ? 'true' : 'false') +
+ '&root.' + APP + '.AcceptRoutes=' + (acceptRoutesInput.checked ? 'true' : 'false');
fetch(PARAM_URL, {
method: 'POST',
credentials: 'same-origin',
diff --git a/arm/app/manifest.json b/arm/app/manifest.json
index b3311e9..4d3341e 100644
--- a/arm/app/manifest.json
+++ b/arm/app/manifest.json
@@ -33,6 +33,16 @@
"name": "Socks5Port",
"default": "1080",
"type": "string"
+ },
+ {
+ "name": "AcceptDNS",
+ "default": "false",
+ "type": "string"
+ },
+ {
+ "name": "AcceptRoutes",
+ "default": "false",
+ "type": "string"
}
]
}
diff --git a/arm/app/param_bridge.c b/arm/app/param_bridge.c
index 06c038c..481e5ff 100644
--- a/arm/app/param_bridge.c
+++ b/arm/app/param_bridge.c
@@ -43,6 +43,8 @@ static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
static char *cfg_http_proxy_port = NULL;
static char *cfg_socks5_port = NULL;
+static char *cfg_accept_dns = NULL;
+static char *cfg_accept_routes = NULL;
static void cache_set(char **field, const char *value) {
if (!value) return;
@@ -139,6 +141,8 @@ static void load_config_cache(AXParameter *handle) {
LOAD("AuthKey", cfg_auth_key)
LOAD("HttpProxyPort", cfg_http_proxy_port)
LOAD("Socks5Port", cfg_socks5_port)
+ LOAD("AcceptDNS", cfg_accept_dns)
+ LOAD("AcceptRoutes", cfg_accept_routes)
#undef LOAD
}
@@ -153,6 +157,8 @@ static void write_config_file(void) {
fprintf(f, "AUTH_KEY=%s\n", cache_get(&cfg_auth_key, ""));
fprintf(f, "CONF_HTTP=%s\n", cache_get(&cfg_http_proxy_port, "8080"));
fprintf(f, "CONF_SOCKS=%s\n", cache_get(&cfg_socks5_port, "1080"));
+ fprintf(f, "ACCEPT_DNS=%s\n", cache_get(&cfg_accept_dns, "false"));
+ fprintf(f, "ACCEPT_ROUTES=%s\n", cache_get(&cfg_accept_routes, "false"));
fclose(f);
chmod(CONFIG_FILE, 0600);
syslog(LOG_INFO, "config updated: http=%s socks=%s server=%s",
@@ -185,6 +191,8 @@ static void parameter_changed(const gchar *name, const gchar *value,
else if (strcmp(short_name, "AuthKey") == 0) cache_set(&cfg_auth_key, value);
else if (strcmp(short_name, "HttpProxyPort") == 0) cache_set(&cfg_http_proxy_port, value);
else if (strcmp(short_name, "Socks5Port") == 0) cache_set(&cfg_socks5_port, value);
+ else if (strcmp(short_name, "AcceptDNS") == 0) cache_set(&cfg_accept_dns, value);
+ else if (strcmp(short_name, "AcceptRoutes") == 0) cache_set(&cfg_accept_routes, value);
if (reload_timer_id)
g_source_remove(reload_timer_id);
@@ -225,7 +233,8 @@ int main(void) {
start_child();
const char *params[] = {
- "CustomServer", "AuthKey", "HttpProxyPort", "Socks5Port"
+ "CustomServer", "AuthKey", "HttpProxyPort", "Socks5Port",
+ "AcceptDNS", "AcceptRoutes"
};
for (size_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
if (!ax_parameter_register_callback(handle, params[i],
diff --git a/arm_ROOT/app/Tailscale_VPN_run b/arm_ROOT/app/Tailscale_VPN_run
index 1bf556a..dfdb724 100644
--- a/arm_ROOT/app/Tailscale_VPN_run
+++ b/arm_ROOT/app/Tailscale_VPN_run
@@ -15,6 +15,8 @@ chmod 755 $TAILSCALE_PATH
CUSTOM_SERVER=""
AUTH_KEY=""
+ACCEPT_DNS="false"
+ACCEPT_ROUTES="false"
if [ -f "$STATE_DIR/params.conf" ]; then
. "$STATE_DIR/params.conf"
@@ -30,7 +32,7 @@ TAILSCALED_PID=$!
sleep 2
-TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --accept-routes --hostname=$(hostname)"
+TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
if [ -n "$CUSTOM_SERVER" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
@@ -40,6 +42,14 @@ if [ -n "$AUTH_KEY" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
fi
+if [ "$ACCEPT_DNS" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
+fi
+
+if [ "$ACCEPT_ROUTES" = "true" ]; then
+ TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
+fi
+
eval $TAILSCALE_CMD
UP_EXIT=$?
diff --git a/arm_ROOT/app/html/index.html b/arm_ROOT/app/html/index.html
index 8aeaf67..e6b11e7 100644
--- a/arm_ROOT/app/html/index.html
+++ b/arm_ROOT/app/html/index.html
@@ -272,6 +272,23 @@
.save-status.ok { color: var(--green); }
.save-status.err { color: var(--red); }
+ /* Toggle switch */
+ .toggle-row { display: flex; align-items: flex-start; gap: 12px; }
+ .toggle-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; margin-top: 2px; }
+ .toggle-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
+ .toggle-slider {
+ position: absolute; cursor: pointer; inset: 0;
+ background: var(--border); border-radius: 20px; transition: background 0.2s;
+ }
+ .toggle-slider:before {
+ content: ''; position: absolute;
+ height: 14px; width: 14px; left: 3px; bottom: 3px;
+ background: white; border-radius: 50%; transition: transform 0.2s;
+ }
+ .toggle-switch input:checked + .toggle-slider { background: var(--green); }
+ .toggle-switch input:checked + .toggle-slider:before { transform: translateX(16px); }
+ .toggle-info { flex: 1; }
+
/* Refresh indicator */
.refresh-bar {
display: flex;
@@ -425,6 +442,26 @@
Port for the SOCKS5 proxy. Default: 1080.
+
+
+
+
+
+
+
Accept DNS
+
Pass --accept-dns=true to tailscale up. Allows the tailnet to push DNS settings to this device. Off by default to avoid overriding the camera's DNS configuration.
+
+
+
+
+
+
+
+
+
Accept Routes
+
Pass --accept-routes=true to tailscale up. Allows this device to use subnet routes advertised by other nodes in the tailnet.
+
+
Save & Restart
@@ -779,6 +816,8 @@
var authInput = document.getElementById('input-authkey');
var httpPortInput = document.getElementById('input-http-port');
var socksPortInput= document.getElementById('input-socks-port');
+ var acceptDnsInput = document.getElementById('input-accept-dns');
+ var acceptRoutesInput = document.getElementById('input-accept-routes');
var saveBtn = document.getElementById('save-btn');
var saveStatus = document.getElementById('save-status');
@@ -790,10 +829,14 @@
var am = txt.match(/root\.\S+\.AuthKey=(.*)/);
var hm = txt.match(/root\.\S+\.HttpProxyPort=(.*)/);
var km = txt.match(/root\.\S+\.Socks5Port=(.*)/);
+ var dm = txt.match(/root\.\S+\.AcceptDNS=(.*)/);
+ var rm = txt.match(/root\.\S+\.AcceptRoutes=(.*)/);
if (sm) serverInput.value = sm[1].trim();
if (am) authInput.value = am[1].trim();
if (hm) httpPortInput.value = hm[1].trim();
if (km) socksPortInput.value = km[1].trim();
+ if (dm) acceptDnsInput.checked = dm[1].trim() === 'true';
+ if (rm) acceptRoutesInput.checked = rm[1].trim() === 'true';
// Update proxy display card with authoritative param values
// and overwrite the localStorage cache so stale ports don't win on next render
var httpPort = hm ? hm[1].trim() : null;
@@ -819,7 +862,9 @@
'&root.' + APP + '.CustomServer=' + encodeURIComponent(serverInput.value.trim()) +
'&root.' + APP + '.AuthKey=' + encodeURIComponent(authInput.value.trim()) +
'&root.' + APP + '.HttpProxyPort=' + encodeURIComponent(httpPort) +
- '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort);
+ '&root.' + APP + '.Socks5Port=' + encodeURIComponent(socksPort) +
+ '&root.' + APP + '.AcceptDNS=' + (acceptDnsInput.checked ? 'true' : 'false') +
+ '&root.' + APP + '.AcceptRoutes=' + (acceptRoutesInput.checked ? 'true' : 'false');
fetch(PARAM_URL, {
method: 'POST',
credentials: 'same-origin',
diff --git a/arm_ROOT/app/manifest.json b/arm_ROOT/app/manifest.json
index 44e9ca6..b6b66e0 100644
--- a/arm_ROOT/app/manifest.json
+++ b/arm_ROOT/app/manifest.json
@@ -27,6 +27,16 @@
"name": "AuthKey",
"default": "",
"type": "string"
+ },
+ {
+ "name": "AcceptDNS",
+ "default": "false",
+ "type": "string"
+ },
+ {
+ "name": "AcceptRoutes",
+ "default": "false",
+ "type": "string"
}
]
}
diff --git a/arm_ROOT/app/param_bridge.c b/arm_ROOT/app/param_bridge.c
index a842e82..93b7893 100644
--- a/arm_ROOT/app/param_bridge.c
+++ b/arm_ROOT/app/param_bridge.c
@@ -31,6 +31,8 @@ static AXParameter *g_ax_handle = NULL;
static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
+static char *cfg_accept_dns = NULL;
+static char *cfg_accept_routes = NULL;
static void cache_set(char **field, const char *value) {
if (!value) return;
@@ -119,6 +121,8 @@ static void load_config_cache(AXParameter *handle) {
LOAD("CustomServer", cfg_custom_server)
LOAD("AuthKey", cfg_auth_key)
+ LOAD("AcceptDNS", cfg_accept_dns)
+ LOAD("AcceptRoutes", cfg_accept_routes)
#undef LOAD
}
@@ -131,6 +135,8 @@ static void write_config_file(void) {
}
fprintf(f, "CUSTOM_SERVER=%s\n", cache_get(&cfg_custom_server, ""));
fprintf(f, "AUTH_KEY=%s\n", cache_get(&cfg_auth_key, ""));
+ fprintf(f, "ACCEPT_DNS=%s\n", cache_get(&cfg_accept_dns, "false"));
+ fprintf(f, "ACCEPT_ROUTES=%s\n", cache_get(&cfg_accept_routes, "false"));
fclose(f);
chmod(CONFIG_FILE, 0600);
syslog(LOG_INFO, "config updated: server=%s",
@@ -156,6 +162,8 @@ static void parameter_changed(const gchar *name, const gchar *value,
if (strcmp(short_name, "CustomServer") == 0) cache_set(&cfg_custom_server, value);
else if (strcmp(short_name, "AuthKey") == 0) cache_set(&cfg_auth_key, value);
+ else if (strcmp(short_name, "AcceptDNS") == 0) cache_set(&cfg_accept_dns, value);
+ else if (strcmp(short_name, "AcceptRoutes") == 0) cache_set(&cfg_accept_routes, value);
if (reload_timer_id)
g_source_remove(reload_timer_id);
@@ -190,7 +198,7 @@ int main(void) {
write_config_file();
start_child();
- const char *params[] = { "CustomServer", "AuthKey" };
+ const char *params[] = { "CustomServer", "AuthKey", "AcceptDNS", "AcceptRoutes" };
for (size_t i = 0; i < sizeof(params) / sizeof(params[0]); i++) {
if (!ax_parameter_register_callback(handle, params[i],
parameter_changed, handle, &error)) {