admin/options: listen-interface "any IPv4" and "any IPv6" #611
Massimo Melina committed
Jul 7, 2024 at 01:53 UTC
997da1d526054b417b2119205771f0a19d31be07
2 files changed
+26
-5
admin/src/OptionsPage.ts
+13
-1
@@ -117,7 +117,19 @@ export default function OptionsPage() {
117
helperText: "Not applied to localhost. Doesn't work with proxies."
118
},
119
120
- { k: 'listen_interface', comp: SelectField, sm: 4, options: [{ label: "any", value: '' }, '127.0.0.1', '::1', ...status?.ips||[]] },
120
+ {
121
+ k: 'listen_interface',
122
+ comp: SelectField,
123
+ sm: 4,
124
+ options: [
125
+ { label: "any", value: '' },
126
+ { label: "any IPv4", value: '0.0.0.0' },
127
+ { label: "any IPv6", value: '::' },
128
+ '127.0.0.1',
129
+ '::1',
130
+ ...status?.ips || []
131
+ ]
132
+ },
133
{ k: 'max_kbps', ...maxSpeedDefaults, sm: 4, label: "Limit output", helperText: "Doesn't apply to localhost" },
134
{ k: 'max_kbps_per_ip', ...maxSpeedDefaults, sm: 4, label: "Limit output per-IP" },
135
src/listen.ts
+13
-4
@@ -8,7 +8,7 @@ import { watchLoad } from './watchLoad'
8
import { networkInterfaces } from 'os';
9
import { newConnection } from './connections'
10
import open from 'open'
11
-import { debounceAsync, ipForUrl, makeNetMatcher, MINUTE, objSameKeys, onlyTruthy, prefix, runAt, wait, } from './misc'
11
+import { debounceAsync, ipForUrl, makeNetMatcher, MINUTE, objSameKeys, onlyTruthy, prefix, runAt, wait, xlate } from './misc'
12
import { PORT_DISABLED, ADMIN_URI, argv, DEV, IS_WINDOWS } from './const'
13
import findProcess from 'find-process'
14
import { anyAccountCanLoginAdmin } from './adminApis'
@@ -168,6 +168,14 @@ export const httpsPortCfg = defineConfig('https_port', PORT_DISABLED)
168
httpsPortCfg.sub(considerHttps)
169
listenInterface.sub(considerHttps)
170
171
+function renderHost(host: string) {
172
+ return xlate(host, {
173
+ '0.0.0.0': "any IPv4",
174
+ '::': "any IPv6",
175
+ '': "any network",
176
+ })
177
+}
178
+
179
interface StartServer { port: number, host?:string }
180
export function startServer(srv: typeof httpSrv, { port, host }: StartServer) {
181
return new Promise<number>(async resolve => {
@@ -179,7 +187,7 @@ export function startServer(srv: typeof httpSrv, { port, host }: StartServer) {
187
srv.on('checkContinue', (req, res) => srv.emit('request', req, res))
188
port = await listen(host)
189
if (port)
182
- console.log(srv.name, "serving on", host||"any network", ':', port)
190
+ console.log(srv.name, "serving on", renderHost(host || ''), ':', port)
191
resolve(port)
192
}
193
catch(e) {
@@ -272,8 +280,9 @@ const ignore = /^(lo|.*loopback.*|virtualbox.*|.*\(wsl\).*|llw\d|awdl\d|utun\d|a
280
const isLinkLocal = makeNetMatcher('169.254.0.0/16|FE80::/16')
281
282
export async function getIps(external=true) {
283
+ const only = { '0.0.0.0': 'IPv4', '::' : 'IPv6' }[listenInterface.get()] || ''
284
const ips = onlyTruthy(Object.entries(networkInterfaces()).flatMap(([name, nets]) =>
276
- nets && !ignore.test(name) && nets.map(net => !net.internal && net.address)
285
+ nets && !ignore.test(name) && nets.map(net => !net.internal && (!only || only === net.family) && net.address)
286
))
287
const e = external && defaultBaseUrl.externalIp
288
if (e && !ips.includes(e))
@@ -289,7 +298,7 @@ export async function getIps(external=true) {
298
299
export async function getUrls() {
300
const on = listenInterface.get()
292
- const ips = on ? [on] : await getIps()
301
+ const ips = on === renderHost(on) ? [on] : await getIps()
302
return Object.fromEntries(onlyTruthy([httpSrv, httpsSrv].map(srv => {
303
if (!srv?.listening)
304
return false