added automatic ipv6 ipv4 detection

This commit is contained in:
BPplays
2024-12-25 16:42:58 -08:00
parent 7f2cf6f7e6
commit b0cb982978
2 changed files with 71 additions and 24 deletions

View File

@@ -7,9 +7,11 @@ cardsCacheCapacity: 100
# Listen for incoming connections # Listen for incoming connections
listen: false listen: false
# Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled! # Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled!
# - Use option "auto" to automatically detect support
# - Use "enabled" or "disabled" to enable or disabled each protocol
protocol: protocol:
ipv4: true ipv4: auto
ipv6: false ipv6: auto
# Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6 # Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6
dnsPreferIPv6: false dnsPreferIPv6: false
# The hostname that autorun opens. # The hostname that autorun opens.

View File

@@ -4,6 +4,7 @@
import fs from 'node:fs'; import fs from 'node:fs';
import http from 'node:http'; import http from 'node:http';
import https from 'node:https'; import https from 'node:https';
import os from 'os';
import path from 'node:path'; import path from 'node:path';
import util from 'node:util'; import util from 'node:util';
import net from 'node:net'; import net from 'node:net';
@@ -133,8 +134,8 @@ const DEFAULT_CSRF_DISABLED = false;
const DEFAULT_BASIC_AUTH = false; const DEFAULT_BASIC_AUTH = false;
const DEFAULT_PER_USER_BASIC_AUTH = false; const DEFAULT_PER_USER_BASIC_AUTH = false;
const DEFAULT_ENABLE_IPV6 = false; const DEFAULT_ENABLE_IPV6 = "auto";
const DEFAULT_ENABLE_IPV4 = true; const DEFAULT_ENABLE_IPV4 = "auto";
const DEFAULT_PREFER_IPV6 = false; const DEFAULT_PREFER_IPV6 = false;
@@ -149,11 +150,11 @@ const DEFAULT_PROXY_BYPASS = [];
const cliArguments = yargs(hideBin(process.argv)) const cliArguments = yargs(hideBin(process.argv))
.usage('Usage: <your-start-script> <command> [options]') .usage('Usage: <your-start-script> <command> [options]')
.option('enableIPv6', { .option('string', {
type: 'boolean', type: 'boolean',
default: null, default: null,
describe: `Enables IPv6.\n[config default: ${DEFAULT_ENABLE_IPV6}]`, describe: `Enables IPv6.\n[config default: ${DEFAULT_ENABLE_IPV6}]`,
}).option('enableIPv4', { }).option('string', {
type: 'boolean', type: 'boolean',
default: null, default: null,
describe: `Enables IPv4.\n[config default: ${DEFAULT_ENABLE_IPV4}]`, describe: `Enables IPv4.\n[config default: ${DEFAULT_ENABLE_IPV4}]`,
@@ -280,7 +281,7 @@ if (dnsPreferIPv6) {
console.log('Preferring IPv4 for DNS resolution'); console.log('Preferring IPv4 for DNS resolution');
} }
if (!enableIPv6 && !enableIPv4) { if (enableIPv6 == "disabled" && enableIPv4 == "disabled") {
console.error('error: You can\'t disable all internet protocols: at least IPv6 or IPv4 must be enabled.'); console.error('error: You can\'t disable all internet protocols: at least IPv6 or IPv4 must be enabled.');
process.exit(1); process.exit(1);
} }
@@ -365,6 +366,28 @@ function getSessionCookieAge() {
return undefined; return undefined;
} }
async function getHasIP() {
let hasIPv6 = false;
let hasIPv4 = false;
const interfaces = os.networkInterfaces();
for (const iface of Object.values(interfaces)) {
if (iface === undefined) {
continue
}
for (const info of iface) {
if (info.family === 'IPv6') {
hasIPv6 = true;
}
if (info.family === 'IPv4') {
hasIPv4 = true;
}
}
}
return [hasIPv6, hasIPv4];
}
app.use(cookieSession({ app.use(cookieSession({
name: getCookieSessionName(), name: getCookieSessionName(),
sameSite: 'strict', sameSite: 'strict',
@@ -685,18 +708,18 @@ const preSetupTasks = async function () {
* Gets the hostname to use for autorun in the browser. * Gets the hostname to use for autorun in the browser.
* @returns {string} The hostname to use for autorun * @returns {string} The hostname to use for autorun
*/ */
function getAutorunHostname() { function getAutorunHostname(useIPv6, useIPv4) {
if (autorunHostname === 'auto') { if (autorunHostname === 'auto') {
if (enableIPv6 && enableIPv4) { if (useIPv6 && useIPv4) {
if (avoidLocalhost) return '[::1]'; if (avoidLocalhost) return '[::1]';
return 'localhost'; return 'localhost';
} }
if (enableIPv6) { if (useIPv6) {
return '[::1]'; return '[::1]';
} }
if (enableIPv4) { if (useIPv4) {
return '127.0.0.1'; return '127.0.0.1';
} }
} }
@@ -709,10 +732,10 @@ function getAutorunHostname() {
* @param {boolean} v6Failed If the server failed to start on IPv6 * @param {boolean} v6Failed If the server failed to start on IPv6
* @param {boolean} v4Failed If the server failed to start on IPv4 * @param {boolean} v4Failed If the server failed to start on IPv4
*/ */
const postSetupTasks = async function (v6Failed, v4Failed) { const postSetupTasks = async function (v6Failed, v4Failed, useIPv6, useIPv4) {
const autorunUrl = new URL( const autorunUrl = new URL(
(cliArguments.ssl ? 'https://' : 'http://') + (cliArguments.ssl ? 'https://' : 'http://') +
(getAutorunHostname()) + (getAutorunHostname(useIPv6, useIPv4)) +
(':') + (':') +
((autorunPortOverride >= 0) ? autorunPortOverride : server_port), ((autorunPortOverride >= 0) ? autorunPortOverride : server_port),
); );
@@ -725,11 +748,11 @@ const postSetupTasks = async function (v6Failed, v4Failed) {
let logListen = 'SillyTavern is listening on'; let logListen = 'SillyTavern is listening on';
if (enableIPv6 && !v6Failed) { if (useIPv6 && !v6Failed) {
logListen += color.green(' IPv6: ' + tavernUrlV6.host); logListen += color.green(' IPv6: ' + tavernUrlV6.host);
} }
if (enableIPv4 && !v4Failed) { if (useIPv4 && !v4Failed) {
logListen += color.green(' IPv4: ' + tavernUrl.host); logListen += color.green(' IPv4: ' + tavernUrl.host);
} }
@@ -805,13 +828,13 @@ function logSecurityAlert(message) {
* @param {boolean} v6Failed If the server failed to start on IPv6 * @param {boolean} v6Failed If the server failed to start on IPv6
* @param {boolean} v4Failed If the server failed to start on IPv4 * @param {boolean} v4Failed If the server failed to start on IPv4
*/ */
function handleServerListenFail(v6Failed, v4Failed) { function handleServerListenFail(v6Failed, v4Failed, useIPv6, useIPv4) {
if (v6Failed && !enableIPv4) { if (v6Failed && !useIPv4) {
console.error(color.red('fatal error: Failed to start server on IPv6 and IPv4 disabled')); console.error(color.red('fatal error: Failed to start server on IPv6 and IPv4 disabled'));
process.exit(1); process.exit(1);
} }
if (v4Failed && !enableIPv6) { if (v4Failed && !useIPv6) {
console.error(color.red('fatal error: Failed to start server on IPv4 and IPv6 disabled')); console.error(color.red('fatal error: Failed to start server on IPv4 and IPv6 disabled'));
process.exit(1); process.exit(1);
} }
@@ -856,13 +879,13 @@ function createHttpServer(url) {
}); });
} }
async function startHTTPorHTTPS() { async function startHTTPorHTTPS(useIPv6, useIPv4) {
let v6Failed = false; let v6Failed = false;
let v4Failed = false; let v4Failed = false;
const createFunc = cliArguments.ssl ? createHttpsServer : createHttpServer; const createFunc = cliArguments.ssl ? createHttpsServer : createHttpServer;
if (enableIPv6) { if (useIPv6) {
try { try {
await createFunc(tavernUrlV6); await createFunc(tavernUrlV6);
} catch (error) { } catch (error) {
@@ -873,7 +896,7 @@ async function startHTTPorHTTPS() {
} }
} }
if (enableIPv4) { if (useIPv4) {
try { try {
await createFunc(tavernUrl); await createFunc(tavernUrl);
} catch (error) { } catch (error) {
@@ -888,10 +911,32 @@ async function startHTTPorHTTPS() {
} }
async function startServer() { async function startServer() {
const [v6Failed, v4Failed] = await startHTTPorHTTPS(); let useIPv6 = (enableIPv6 == "enabled")
let useIPv4 = (enableIPv4 == "enabled")
handleServerListenFail(v6Failed, v4Failed); const [hasIPv6, hasIPv4] = await getHasIP()
postSetupTasks(v6Failed, v4Failed); if (enableIPv6 == "auto") {
useIPv6 = hasIPv6;
if (useIPv6) {
console.log("IPv6 support detected")
}
}
if (enableIPv4 == "auto") {
useIPv4 = hasIPv4;
if (useIPv4) {
console.log("IPv4 support detected")
}
}
if (!useIPv6 && !useIPv4) {
console.log("No IPv6 and no IPv4 enabled")
}
const [v6Failed, v4Failed] = await startHTTPorHTTPS(useIPv6, useIPv4);
handleServerListenFail(v6Failed, v4Failed, useIPv6, useIPv4);
postSetupTasks(v6Failed, v4Failed, useIPv6, useIPv4);
} }
async function verifySecuritySettings() { async function verifySecuritySettings() {