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. +
+
@@ -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. +
+
@@ -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. +
+
@@ -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. +
+
@@ -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)) {