diff --git a/lib/builder/linux.js b/lib/builder/linux.js index 08f69f0..a8fb96d 100644 --- a/lib/builder/linux.js +++ b/lib/builder/linux.js @@ -22,6 +22,7 @@ var defaultConfig = { v6: false, sourceAddr: '', packetSize: 56, + ignoreDifferentAddressReply: false, extra: [], }; @@ -40,7 +41,7 @@ builder.getCommandArguments = function (target, config) { // Make every key in config has been setup properly var keys = ['numeric', 'timeout', 'deadline', 'min_reply', 'v6', - 'sourceAddr', 'extra', 'packetSize']; + 'sourceAddr', 'extra', 'packetSize', 'ignoreDifferentAddressReply']; keys.forEach(function (k) { // Falsy value will be overridden without below checking if (typeof (_config[k]) !== 'boolean') { diff --git a/lib/index.js b/lib/index.js index 4f6e311..69a6278 100644 --- a/lib/index.js +++ b/lib/index.js @@ -18,7 +18,14 @@ * @property {string} [sourceAddr] - source address for sending the ping * @property {number} [packetSize] - Specifies the number of data bytes to be sent * Default: Linux / MAC: 56 Bytes, - * Window: 32 Bytes + * Windows: 32 Bytes + * @property {boolean} [ignoreDifferentAddressReply] - Enables ignoring replies from different addresses + * Default: Linux: false + * Other platforms do not need this option. + * If set to true and a reply is received from an address which does not match the parsed + * `PingResponse.numeric_host`, the ping response is ignored. + * This helps against detecting a host as alive by accident when another host replies to the ping. + * This workaround addresses an imperfection in the ping implementation within the package iputils.* * @property {string[]} [extra] - Optional options does not provided */ diff --git a/lib/parser/mac.js b/lib/parser/mac.js index 9163349..4b56a17 100644 --- a/lib/parser/mac.js +++ b/lib/parser/mac.js @@ -43,7 +43,13 @@ MacParser.prototype._processBody = function (line) { if (count >= 3) { var regExp = /([0-9.]+)[ ]*ms/; var match = regExp.exec(line); - this._times.push(getFloatOrUnknown(match[1])); + + // XXX: This option is only provided in linux builder, but the parser is shared. + // This option should have no effect on macOS, + // as ping on macOS does not accept replies from a different address + if (!this._pingConfig.ignoreDifferentAddressReply || line.includes(this._response.numeric_host)) { + this._times.push(getFloatOrUnknown(match[1])); + } } // Change state if it see a '---' diff --git a/test/fixture/answer.json b/test/fixture/answer.json index 10941ef..b95ea9d 100644 --- a/test/fixture/answer.json +++ b/test/fixture/answer.json @@ -107,6 +107,25 @@ "packetLoss": "100.000", "stddev": "unknown" }, + "linux_en_sample_reply_from_different_address": { + "inputHost": "whatever", + "host": "192.168.178.1", + "numeric_host": "192.168.178.1", + "alive": true, + "output": "PING 192.168.178.1 (192.168.178.1) 56(84) bytes of data.\n64 bytes from 192.168.178.8: icmp_seq=1 ttl=64 time=0.578 ms (DIFFERENT ADDRESS!)\n64 bytes from 192.168.178.8: icmp_seq=2 ttl=64 time=0.348 ms (DIFFERENT ADDRESS!)\n64 bytes from 192.168.178.8: icmp_seq=3 ttl=64 time=0.994 ms (DIFFERENT ADDRESS!)\n64 bytes from 192.168.178.8: icmp_seq=4 ttl=64 time=0.349 ms (DIFFERENT ADDRESS!)\n\n--- 192.168.178.1 ping statistics ---\n4 packets transmitted, 4 received, 0% packet loss, time 3004ms\nrtt min/avg/max/mdev = 0.348/0.567/0.994/0.263 ms", + "time": 0.578, + "times": [ + 0.578, + 0.348, + 0.994, + 0.349 + ], + "min": "0.348", + "max": "0.994", + "avg": "0.567", + "stddev": "0.263", + "packetLoss": "0.000" + }, "linux_en_sample4": { "inputHost": "whatever", "host": "google.com", diff --git a/test/fixture/linux/en/sample_reply_from_different_address.txt b/test/fixture/linux/en/sample_reply_from_different_address.txt new file mode 100644 index 0000000..b0c23f8 --- /dev/null +++ b/test/fixture/linux/en/sample_reply_from_different_address.txt @@ -0,0 +1,9 @@ +PING 192.168.178.1 (192.168.178.1) 56(84) bytes of data. +64 bytes from 192.168.178.8: icmp_seq=1 ttl=64 time=0.578 ms (DIFFERENT ADDRESS!) +64 bytes from 192.168.178.8: icmp_seq=2 ttl=64 time=0.348 ms (DIFFERENT ADDRESS!) +64 bytes from 192.168.178.8: icmp_seq=3 ttl=64 time=0.994 ms (DIFFERENT ADDRESS!) +64 bytes from 192.168.178.8: icmp_seq=4 ttl=64 time=0.349 ms (DIFFERENT ADDRESS!) + +--- 192.168.178.1 ping statistics --- +4 packets transmitted, 4 received, 0% packet loss, time 3004ms +rtt min/avg/max/mdev = 0.348/0.567/0.994/0.263 ms diff --git a/test/test-ping.js b/test/test-ping.js index b8e9de2..953ae1c 100644 --- a/test/test-ping.js +++ b/test/test-ping.js @@ -124,6 +124,39 @@ var createTestCase = function (platform, pingExecution) { }); }; +describe('ping reply from a different address', function () { + describe('on linux platform', function() { + beforeEach(function() { + this.platformStub = sinon.stub(os, 'platform').callsFake(function() { + return 'linux'; + }); + const fixturePath = path.join(__dirname, 'fixture', 'linux', 'en', 'sample_reply_from_different_address.txt'); + this.spawnStub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fixturePath)); + }); + + afterEach(function() { + this.platformStub.restore(); + this.spawnStub.restore(); + }); + + it('host is not considered alive if ignoreDifferentAddressReply is true', async function() { + const res = await ping.promise + .probe('whatever', { + ignoreDifferentAddressReply: true, + }); + expect(res.alive).to.be.false; + }); + + it('host is considered alive if ignoreDifferentAddressReply is false', async function() { + const res = await ping.promise + .probe('whatever', { + ignoreDifferentAddressReply: false, + }); + expect(res.alive).to.be.true; + }); + }); +}); + describe('ping timeout and deadline options', function () { describe('on linux platform', function () { beforeEach(function () {