Skip to content

Commit e93c9f8

Browse files
authored
feat: add async support for get_public_ip (#75)
- dep: replace vs-stun with stun
1 parent 1440a41 commit e93c9f8

File tree

4 files changed

+104
-25
lines changed

4 files changed

+104
-25
lines changed

Changes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11

22
#### N.N.N - YYYY-MM-DD
33

4+
5+
### [1.5.0] - 2022-12-20
6+
7+
- feat: add async support for get_public_ip
8+
- dep: replace vs-stun with stun
9+
- doc: use async/await syntax in examples (#74)
10+
11+
412
### [1.4.1] - 2022-07-22
513

614
- feat(get_mx): use async/await
@@ -178,3 +186,4 @@
178186
[1.3.6]: https://github.com/haraka/haraka-net-utils/releases/tag/1.3.6
179187
[1.3.7]: https://github.com/haraka/haraka-net-utils/releases/tag/1.3.7
180188
[1.4.1]: https://github.com/haraka/haraka-net-utils/releases/tag/1.4.1
189+
[1.5.0]: https://github.com/haraka/haraka-net-utils/releases/tag/1.5.0

index.js

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,45 @@ exports.same_ipv4_network = function (ip, ipList) {
239239
return false;
240240
}
241241

242-
exports.get_public_ip = function (cb) {
242+
exports.get_public_ip_async = async function () {
243+
244+
if (this.public_ip !== undefined) return this.public_ip; // cache
245+
246+
// manual config override, for the cases where we can't figure it out
247+
const smtpIni = exports.config.get('smtp.ini').main;
248+
if (smtpIni.public_ip) {
249+
this.public_ip = smtpIni.public_ip;
250+
return this.public_ip;
251+
}
252+
253+
// Initialise cache value to null to prevent running
254+
// should we hit a timeout or the module isn't installed.
255+
this.public_ip = null;
256+
257+
try {
258+
this.stun = require('stun');
259+
}
260+
catch (e) {
261+
e.install = 'Please install stun: "npm install -g stun"';
262+
console.error(`${e.msg}\n${e.install}`);
263+
return
264+
}
265+
266+
const timeout = 10;
267+
const timer = setTimeout(() => {
268+
return new Error('STUN timeout')
269+
}, timeout * 1000);
270+
271+
// Connect to STUN Server
272+
const res = await this.stun.request(get_stun_server())
273+
this.public_ip = res.getXorAddress().address
274+
clearTimeout(timer)
275+
return this.public_ip
276+
}
277+
278+
exports.get_public_ip = async function (cb) {
279+
if (!cb) return exports.get_public_ip_async()
280+
243281
const nu = this;
244282
if (nu.public_ip !== undefined) return cb(null, nu.public_ip); // cache
245283

@@ -255,10 +293,10 @@ exports.get_public_ip = function (cb) {
255293
nu.public_ip = null;
256294

257295
try {
258-
nu.stun = require('vs-stun');
296+
nu.stun = require('stun');
259297
}
260298
catch (e) {
261-
e.install = 'Please install stun: "npm install -g vs-stun"';
299+
e.install = 'Please install stun: "npm install -g stun"';
262300
console.error(`${e.msg}\n${e.install}`);
263301
return cb(e);
264302
}
@@ -269,34 +307,23 @@ exports.get_public_ip = function (cb) {
269307
}, timeout * 1000);
270308

271309
// Connect to STUN Server
272-
nu.stun.connect({ host: get_stun_server(), port: 19302 }, (error, socket) => {
310+
nu.stun.request(get_stun_server(), (error, res) => {
273311
if (timer) clearTimeout(timer);
274312
if (error) return cb(error);
275313

276-
socket.close();
277-
278-
/* sample socket.stun response
279-
*
280-
* { local: { host: '127.0.0.30', port: 26163 },
281-
* public: { host: '50.115.0.94', port: 57345, family: 'IPv4' },
282-
* type: 'Full Cone NAT'
283-
* }
284-
*/
285-
if (!socket.stun.public) return cb(new Error('invalid STUN result'));
286-
287-
nu.public_ip = socket.stun.public.host;
288-
cb(null, socket.stun.public.host);
314+
nu.public_ip = res.getXorAddress().address
315+
cb(null, nu.public_ip);
289316
})
290317
}
291318

292319
function get_stun_server () {
293320
// STUN servers by Google
294321
const servers = [
295-
'stun.l.google.com',
296-
'stun1.l.google.com',
297-
'stun2.l.google.com',
298-
'stun3.l.google.com',
299-
'stun4.l.google.com',
322+
'stun.l.google.com:19302',
323+
'stun1.l.google.com:19302',
324+
'stun2.l.google.com:19302',
325+
'stun3.l.google.com:19302',
326+
'stun4.l.google.com:19302',
300327
];
301328
return servers[Math.floor(Math.random()*servers.length)];
302329
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "haraka-net-utils",
3-
"version": "1.4.1",
3+
"version": "1.5.0",
44
"description": "haraka network utilities",
55
"main": "index.js",
66
"scripts": {
@@ -42,6 +42,6 @@
4242
"sprintf-js": "^1.1.2"
4343
},
4444
"optionalDependencies": {
45-
"vs-stun": "~0.0.7"
45+
"stun": "2.1.0"
4646
}
4747
}

test/net_utils.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ describe('get_public_ip', function () {
239239

240240
function has_stun () {
241241
try {
242-
require('vs-stun');
242+
require('stun');
243243
}
244244
catch (e) {
245245
return false;
@@ -281,6 +281,48 @@ describe('get_public_ip', function () {
281281
})
282282
})
283283

284+
describe('get_public_ip_async', function () {
285+
286+
beforeEach(() => {
287+
this.net_utils = require('../index');
288+
this.net_utils.config = this.net_utils.config.module_config(path.resolve('test'));
289+
})
290+
291+
function has_stun () {
292+
try {
293+
require('stun');
294+
}
295+
catch (e) {
296+
return false;
297+
}
298+
return true;
299+
}
300+
301+
it('cached', async () => {
302+
this.net_utils.public_ip='1.1.1.1';
303+
const ip = await this.net_utils.get_public_ip()
304+
assert.equal('1.1.1.1', ip);
305+
})
306+
307+
it('normal', async () => {
308+
this.net_utils.public_ip=undefined;
309+
310+
if (!has_stun()) {
311+
console.log("stun skipped");
312+
return
313+
}
314+
315+
try {
316+
const ip = await this.net_utils.get_public_ip()
317+
console.log(`stun success: ${ip}`);
318+
assert.ok(ip, ip);
319+
}
320+
catch (e) {
321+
console.error(e);
322+
}
323+
})
324+
})
325+
284326
describe('octets_in_string', function () {
285327
it('c-24-18-98-14.hsd1.wa.comcast.net', function (done) {
286328
const str = 'c-24-18-98-14.hsd1.wa.comcast.net';
@@ -1012,6 +1054,7 @@ describe('get_ips_by_host', function () {
10121054
for (const t in tests) {
10131055

10141056
it(`get_ips_by_host, ${t}`, function (done) {
1057+
this.timeout(4000)
10151058
net_utils.get_ips_by_host(t, function (err, res) {
10161059
if (err && err.length) {
10171060
console.error(err);

0 commit comments

Comments
 (0)