1 | // Licensed to the Software Freedom Conservancy (SFC) under one
|
2 | // or more contributor license agreements. See the NOTICE file
|
3 | // distributed with this work for additional information
|
4 | // regarding copyright ownership. The SFC licenses this file
|
5 | // to you under the Apache License, Version 2.0 (the
|
6 | // "License"); you may not use this file except in compliance
|
7 | // with the License. You may obtain a copy of the License at
|
8 | //
|
9 | // http://www.apache.org/licenses/LICENSE-2.0
|
10 | //
|
11 | // Unless required by applicable law or agreed to in writing,
|
12 | // software distributed under the License is distributed on an
|
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14 | // KIND, either express or implied. See the License for the
|
15 | // specific language governing permissions and limitations
|
16 | // under the License.
|
17 |
|
18 |
|
19 |
|
20 | const os = require('os')
|
21 |
|
22 | function getLoInterface() {
|
23 | let name
|
24 | if (process.platform === 'darwin') {
|
25 | name = 'lo0'
|
26 | } else if (process.platform === 'linux') {
|
27 | name = 'lo'
|
28 | }
|
29 | return name ? os.networkInterfaces()[name] : null
|
30 | }
|
31 |
|
32 | /**
|
33 | * Queries the system network interfaces for an IP address.
|
34 | * @param {boolean} loopback Whether to find a loopback address.
|
35 | * @param {string} family The IP family (IPv4 or IPv6). Defaults to IPv4.
|
36 | * @return {(string|undefined)} The located IP address or undefined.
|
37 | */
|
38 | function getAddress(loopback, family) {
|
39 | let interfaces
|
40 | if (loopback) {
|
41 | let lo = getLoInterface()
|
42 | interfaces = lo ? [lo] : null
|
43 | }
|
44 | interfaces = interfaces || os.networkInterfaces()
|
45 | for (let key in interfaces) {
|
46 | if (!Object.prototype.hasOwnProperty.call(interfaces, key)) {
|
47 | continue
|
48 | }
|
49 |
|
50 | for (let ipAddress of interfaces[key]) {
|
51 | if (ipAddress.family === family && ipAddress.internal === loopback) {
|
52 | return ipAddress.address
|
53 | }
|
54 | }
|
55 | }
|
56 | return undefined
|
57 | }
|
58 |
|
59 | // PUBLIC API
|
60 |
|
61 | /**
|
62 | * Retrieves the external IP address for this host.
|
63 | * @param {string=} family The IP family to retrieve. Defaults to "IPv4".
|
64 | * @return {(string|undefined)} The IP address or undefined if not available.
|
65 | */
|
66 | exports.getAddress = function (family = 'IPv4') {
|
67 | return getAddress(false, family)
|
68 | }
|
69 |
|
70 | /**
|
71 | * Retrieves a loopback address for this machine.
|
72 | * @param {string=} family The IP family to retrieve. Defaults to "IPv4".
|
73 | * @return {(string|undefined)} The IP address or undefined if not available.
|
74 | */
|
75 | exports.getLoopbackAddress = function (family = 'IPv4') {
|
76 | return getAddress(true, family)
|
77 | }
|
78 |
|
79 | /**
|
80 | * Splits a hostport string, e.g. "www.example.com:80", into its component
|
81 | * parts.
|
82 | *
|
83 | * @param {string} hostport The string to split.
|
84 | * @return {{host: string, port: ?number}} A host and port. If no port is
|
85 | * present in the argument `hostport`, port is null.
|
86 | */
|
87 | exports.splitHostAndPort = function (hostport) {
|
88 | let lastIndex = hostport.lastIndexOf(':')
|
89 | if (lastIndex < 0) {
|
90 | return { host: hostport, port: null }
|
91 | }
|
92 |
|
93 | let firstIndex = hostport.indexOf(':')
|
94 | if (firstIndex != lastIndex && !hostport.includes('[')) {
|
95 | // Multiple colons but no brackets, so assume the string is an IPv6 address
|
96 | // with no port (e.g. "1234:5678:9:0:1234:5678:9:0").
|
97 | return { host: hostport, port: null }
|
98 | }
|
99 |
|
100 | let host = hostport.slice(0, lastIndex)
|
101 | if (host.startsWith('[') && host.endsWith(']')) {
|
102 | host = host.slice(1, -1)
|
103 | }
|
104 |
|
105 | let port = parseInt(hostport.slice(lastIndex + 1), 10)
|
106 | return { host, port }
|
107 | }
|