diff --git a/cypress/config/settings.cypress.json b/cypress/config/settings.cypress.json index e3d31cc11..e49d8888b 100644 --- a/cypress/config/settings.cypress.json +++ b/cypress/config/settings.cypress.json @@ -23,6 +23,8 @@ "mediaServerType": 1, "partialRequestsEnabled": true, "enableSpecialEpisodes": false, + "forceIpv4First": false, + "dnsServers": "", "locale": "en" }, "plex": { diff --git a/overseerr-api.yml b/overseerr-api.yml index b707ae8b3..f3be28ad2 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -191,6 +191,12 @@ components: enableSpecialEpisodes: type: boolean example: false + forceIpv4First: + type: boolean + example: false + dnsServers: + type: string + example: '1.1.1.1' PlexLibrary: type: object properties: diff --git a/server/index.ts b/server/index.ts index 64233c0e2..dde0d5083 100644 --- a/server/index.ts +++ b/server/index.ts @@ -41,11 +41,6 @@ import path from 'path'; import swaggerUi from 'swagger-ui-express'; import YAML from 'yamljs'; -if (process.env.forceIpv4First === 'true') { - dns.setDefaultResultOrder('ipv4first'); - net.setDefaultAutoSelectFamily(false); -} - const API_SPEC_PATH = path.join(__dirname, '../overseerr-api.yml'); logger.info(`Starting Overseerr version ${getAppVersion()}`); @@ -79,6 +74,18 @@ app const settings = await getSettings().load(); restartFlag.initializeSettings(settings.main); + // Check if we force IPv4 first + if (process.env.forceIpv4First === 'true' || settings.main.forceIpv4First) { + dns.setDefaultResultOrder('ipv4first'); + net.setDefaultAutoSelectFamily(false); + } + + if (settings.main.dnsServers.trim() !== '') { + dns.setServers( + settings.main.dnsServers.split(',').map((server) => server.trim()) + ); + } + // Register HTTP proxy if (settings.main.proxy.enabled) { await createCustomProxyAgent(settings.main.proxy); diff --git a/server/lib/settings/index.ts b/server/lib/settings/index.ts index cd8ebb974..343c01e2f 100644 --- a/server/lib/settings/index.ts +++ b/server/lib/settings/index.ts @@ -132,6 +132,8 @@ export interface MainSettings { mediaServerType: number; partialRequestsEnabled: boolean; enableSpecialEpisodes: boolean; + forceIpv4First: boolean; + dnsServers: string; locale: string; proxy: ProxySettings; } @@ -346,6 +348,8 @@ class Settings { mediaServerType: MediaServerType.NOT_CONFIGURED, partialRequestsEnabled: true, enableSpecialEpisodes: false, + forceIpv4First: false, + dnsServers: '', locale: 'en', proxy: { enabled: false, diff --git a/server/utils/restartFlag.ts b/server/utils/restartFlag.ts index 18d03ea64..6b364d1f0 100644 --- a/server/utils/restartFlag.ts +++ b/server/utils/restartFlag.ts @@ -14,7 +14,9 @@ class RestartFlag { return ( this.settings.csrfProtection !== settings.csrfProtection || this.settings.trustProxy !== settings.trustProxy || - this.settings.proxy.enabled !== settings.proxy.enabled + this.settings.proxy.enabled !== settings.proxy.enabled || + this.settings.forceIpv4First !== settings.forceIpv4First || + this.settings.dnsServers !== settings.dnsServers ); } } diff --git a/src/components/Settings/SettingsMain/index.tsx b/src/components/Settings/SettingsMain/index.tsx index 199b220a3..fb1df6b5e 100644 --- a/src/components/Settings/SettingsMain/index.tsx +++ b/src/components/Settings/SettingsMain/index.tsx @@ -57,6 +57,12 @@ const messages = defineMessages('components.Settings.SettingsMain', { validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash', partialRequestsEnabled: 'Allow Partial Series Requests', enableSpecialEpisodes: 'Allow Special Episodes Requests', + forceIpv4First: 'IPv4 Resolution First', + forceIpv4FirstTip: + 'Force Jellyseerr to resolve IPv4 addresses first instead of IPv6', + dnsServers: 'Custom DNS Servers', + dnsServersTip: + 'Comma-separated list of custom DNS servers, e.g. "1.1.1.1,[2606:4700:4700::1111]"', locale: 'Display Language', proxyEnabled: 'HTTP(S) Proxy', proxyHostname: 'Proxy Hostname', @@ -160,6 +166,8 @@ const SettingsMain = () => { streamingRegion: data?.streamingRegion || 'US', partialRequestsEnabled: data?.partialRequestsEnabled, enableSpecialEpisodes: data?.enableSpecialEpisodes, + forceIpv4First: data?.forceIpv4First, + dnsServers: data?.dnsServers, trustProxy: data?.trustProxy, cacheImages: data?.cacheImages, proxyEnabled: data?.proxy?.enabled, @@ -191,6 +199,8 @@ const SettingsMain = () => { originalLanguage: values.originalLanguage, partialRequestsEnabled: values.partialRequestsEnabled, enableSpecialEpisodes: values.enableSpecialEpisodes, + forceIpv4First: values.forceIpv4First, + dnsServers: values.dnsServers, trustProxy: values.trustProxy, cacheImages: values.cacheImages, proxy: { @@ -524,6 +534,55 @@ const SettingsMain = () => { /> +