internet.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // internet.js
  5. // ----------------------------------------------------------------------------------
  6. // Description: System Information - library
  7. // for Node.js
  8. // Copyright: (c) 2014 - 2022
  9. // Author: Sebastian Hildebrandt
  10. // ----------------------------------------------------------------------------------
  11. // License: MIT
  12. // ==================================================================================
  13. // 12. Internet
  14. // ----------------------------------------------------------------------------------
  15. // const exec = require('child_process').exec;
  16. const util = require('./util');
  17. let _platform = process.platform;
  18. const _linux = (_platform === 'linux' || _platform === 'android');
  19. const _darwin = (_platform === 'darwin');
  20. const _windows = (_platform === 'win32');
  21. const _freebsd = (_platform === 'freebsd');
  22. const _openbsd = (_platform === 'openbsd');
  23. const _netbsd = (_platform === 'netbsd');
  24. const _sunos = (_platform === 'sunos');
  25. // --------------------------
  26. // check if external site is available
  27. function inetChecksite(url, callback) {
  28. return new Promise((resolve) => {
  29. process.nextTick(() => {
  30. let result = {
  31. url: url,
  32. ok: false,
  33. status: 404,
  34. ms: null
  35. };
  36. if (typeof url !== 'string') {
  37. if (callback) { callback(result); }
  38. return resolve(result);
  39. }
  40. let urlSanitized = '';
  41. const s = util.sanitizeShellString(url, true);
  42. for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
  43. if (!(s[i] === undefined)) {
  44. s[i].__proto__.toLowerCase = util.stringToLower;
  45. const sl = s[i].toLowerCase();
  46. if (sl && sl[0] && !sl[1] && sl[0].length === 1) {
  47. urlSanitized = urlSanitized + sl[0];
  48. }
  49. }
  50. }
  51. result.url = urlSanitized;
  52. try {
  53. if (urlSanitized && !util.isPrototypePolluted()) {
  54. urlSanitized.__proto__.startsWith = util.stringStartWith;
  55. if (urlSanitized.startsWith('file:') || urlSanitized.startsWith('gopher:') || urlSanitized.startsWith('telnet:') || urlSanitized.startsWith('mailto:') || urlSanitized.startsWith('news:') || urlSanitized.startsWith('nntp:')) {
  56. if (callback) { callback(result); }
  57. return resolve(result);
  58. }
  59. let t = Date.now();
  60. if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
  61. let args = ['-I', '--connect-timeout', '5', '-m', '5'];
  62. args.push(urlSanitized);
  63. let cmd = 'curl';
  64. util.execSafe(cmd, args).then((stdout) => {
  65. const lines = stdout.split('\n');
  66. let statusCode = lines[0] && lines[0].indexOf(' ') >= 0 ? parseInt(lines[0].split(' ')[1], 10) : 404;
  67. result.status = statusCode || 404;
  68. result.ok = (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
  69. result.ms = (result.ok ? Date.now() - t : null);
  70. if (callback) { callback(result); }
  71. resolve(result);
  72. });
  73. }
  74. if (_windows) { // if this is stable, this can be used for all OS types
  75. const http = (urlSanitized.startsWith('https:') ? require('https') : require('http'));
  76. try {
  77. http.get(urlSanitized, (res) => {
  78. const statusCode = res.statusCode;
  79. result.status = statusCode || 404;
  80. result.ok = (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
  81. if (statusCode !== 200) {
  82. res.resume();
  83. result.ms = (result.ok ? Date.now() - t : null);
  84. if (callback) { callback(result); }
  85. resolve(result);
  86. } else {
  87. res.on('data', () => { });
  88. res.on('end', () => {
  89. result.ms = (result.ok ? Date.now() - t : null);
  90. if (callback) { callback(result); }
  91. resolve(result);
  92. });
  93. }
  94. }).on('error', () => {
  95. if (callback) { callback(result); }
  96. resolve(result);
  97. });
  98. } catch (err) {
  99. if (callback) { callback(result); }
  100. resolve(result);
  101. }
  102. }
  103. } else {
  104. if (callback) { callback(result); }
  105. resolve(result);
  106. }
  107. } catch (err) {
  108. if (callback) { callback(result); }
  109. resolve(result);
  110. }
  111. });
  112. });
  113. }
  114. exports.inetChecksite = inetChecksite;
  115. // --------------------------
  116. // check inet latency
  117. function inetLatency(host, callback) {
  118. // fallback - if only callback is given
  119. if (util.isFunction(host) && !callback) {
  120. callback = host;
  121. host = '';
  122. }
  123. host = host || '8.8.8.8';
  124. return new Promise((resolve) => {
  125. process.nextTick(() => {
  126. if (typeof host !== 'string') {
  127. if (callback) { callback(null); }
  128. return resolve(null);
  129. }
  130. let hostSanitized = '';
  131. const s = (util.isPrototypePolluted() ? '8.8.8.8' : util.sanitizeShellString(host, true)).trim();
  132. for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
  133. if (!(s[i] === undefined)) {
  134. s[i].__proto__.toLowerCase = util.stringToLower;
  135. const sl = s[i].toLowerCase();
  136. if (sl && sl[0] && !sl[1]) {
  137. hostSanitized = hostSanitized + sl[0];
  138. }
  139. }
  140. }
  141. hostSanitized.__proto__.startsWith = util.stringStartWith;
  142. if (hostSanitized.startsWith('file:') || hostSanitized.startsWith('gopher:') || hostSanitized.startsWith('telnet:') || hostSanitized.startsWith('mailto:') || hostSanitized.startsWith('news:') || hostSanitized.startsWith('nntp:')) {
  143. if (callback) { callback(null); }
  144. return resolve(null);
  145. }
  146. let params;
  147. let filt;
  148. if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
  149. if (_linux) {
  150. params = ['-c', '2', '-w', '3', hostSanitized];
  151. filt = 'rtt';
  152. }
  153. if (_freebsd || _openbsd || _netbsd) {
  154. params = ['-c', '2', '-t', '3', hostSanitized];
  155. filt = 'round-trip';
  156. }
  157. if (_darwin) {
  158. params = ['-c2', '-t3', hostSanitized];
  159. filt = 'avg';
  160. }
  161. util.execSafe('ping', params).then((stdout) => {
  162. let result = null;
  163. if (stdout) {
  164. const lines = stdout.split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
  165. const line = lines.split('=');
  166. if (line.length > 1) {
  167. const parts = line[1].split('/');
  168. if (parts.length > 1) {
  169. result = parseFloat(parts[1]);
  170. }
  171. }
  172. }
  173. if (callback) { callback(result); }
  174. resolve(result);
  175. });
  176. }
  177. if (_sunos) {
  178. const params = ['-s', '-a', hostSanitized, '56', '2'];
  179. const filt = 'avg';
  180. util.execSafe('ping', params, { timeout: 3000 }).then((stdout) => {
  181. let result = null;
  182. if (stdout) {
  183. const lines = stdout.split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
  184. const line = lines.split('=');
  185. if (line.length > 1) {
  186. const parts = line[1].split('/');
  187. if (parts.length > 1) {
  188. result = parseFloat(parts[1].replace(',', '.'));
  189. }
  190. }
  191. }
  192. if (callback) { callback(result); }
  193. resolve(result);
  194. });
  195. }
  196. if (_windows) {
  197. let result = null;
  198. try {
  199. const params = [hostSanitized, '-n', '1'];
  200. util.execSafe('ping', params, util.execOptsWin).then((stdout) => {
  201. if (stdout) {
  202. let lines = stdout.split('\r\n');
  203. lines.shift();
  204. lines.forEach(function (line) {
  205. if ((line.toLowerCase().match(/ms/g) || []).length === 3) {
  206. let l = line.replace(/ +/g, ' ').split(' ');
  207. if (l.length > 6) {
  208. result = parseFloat(l[l.length - 1]);
  209. }
  210. }
  211. });
  212. }
  213. if (callback) { callback(result); }
  214. resolve(result);
  215. });
  216. } catch (e) {
  217. if (callback) { callback(result); }
  218. resolve(result);
  219. }
  220. }
  221. });
  222. });
  223. }
  224. exports.inetLatency = inetLatency;