mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Backed out 3 changesets (bug 1540656) for xpcshell failures on test_immutable.js. CLOSED TREE
Backed out changeset 70a90b960aef (bug 1540656) Backed out changeset 631a1aae6fb0 (bug 1540656) Backed out changeset 408104f784ef (bug 1540656)
This commit is contained in:
parent
b4eecfd1a6
commit
03a4c6187b
@ -332,9 +332,6 @@ testing/raptor/raptor/playback/scripts/catapult/**
|
||||
testing/web-platform/**
|
||||
testing/xpcshell/moz-http2/**
|
||||
testing/xpcshell/node-http2/**
|
||||
testing/xpcshell/dns-packet/**
|
||||
testing/xpcshell/node-ip/**
|
||||
|
||||
|
||||
# Third party services
|
||||
services/common/kinto-http-client.js
|
||||
|
@ -1,445 +1,581 @@
|
||||
"use strict";
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
var prefs;
|
||||
var origin;
|
||||
var h2Port;
|
||||
|
||||
const dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService);
|
||||
const mainThread = Services.tm.currentThread;
|
||||
var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService);
|
||||
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
var mainThread = threadManager.currentThread;
|
||||
|
||||
const defaultOriginAttributes = {};
|
||||
let h2Port = null;
|
||||
|
||||
add_task(function setup() {
|
||||
dump("start!\n");
|
||||
function run_test() {
|
||||
dump ("start!\n");
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
h2Port = env.get("MOZHTTP2_PORT");
|
||||
Assert.notEqual(h2Port, null);
|
||||
Assert.notEqual(h2Port, "");
|
||||
|
||||
// Set to allow the cert presented by our H2 server
|
||||
do_get_profile();
|
||||
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
|
||||
Services.prefs.setBoolPref("network.http.spdy.enabled", true);
|
||||
Services.prefs.setBoolPref("network.http.spdy.enabled.http2", true);
|
||||
prefs.setBoolPref("network.http.spdy.enabled", true);
|
||||
prefs.setBoolPref("network.http.spdy.enabled.http2", true);
|
||||
// the TRR server is on 127.0.0.1
|
||||
Services.prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1");
|
||||
prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1");
|
||||
|
||||
// use the h2 server as DOH provider
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns`);
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
// make all native resolve calls "secretly" resolve localhost instead
|
||||
Services.prefs.setBoolPref("network.dns.native-is-localhost", true);
|
||||
prefs.setBoolPref("network.dns.native-is-localhost", true);
|
||||
|
||||
// 0 - off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR first
|
||||
Services.prefs.setBoolPref("network.trr.wait-for-portal", false);
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR first
|
||||
prefs.setBoolPref("network.trr.wait-for-portal", false);
|
||||
// don't confirm that TRR is working, just go!
|
||||
Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
|
||||
// The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem
|
||||
// so add that cert to the trust list as a signing cert. // the foo.example.com domain name.
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
|
||||
});
|
||||
do_test_pending();
|
||||
run_dns_tests();
|
||||
}
|
||||
|
||||
function resetTRRPrefs() {
|
||||
prefs.clearUserPref("network.trr.mode");
|
||||
prefs.clearUserPref("network.trr.uri");
|
||||
prefs.clearUserPref("network.trr.credentials");
|
||||
prefs.clearUserPref("network.trr.wait-for-portal");
|
||||
prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
prefs.clearUserPref("network.trr.useGET");
|
||||
prefs.clearUserPref("network.trr.confirmationNS");
|
||||
prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
prefs.clearUserPref("network.trr.blacklist-duration");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
prefs.clearUserPref("network.trr.disable-ECS");
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("network.trr.mode");
|
||||
Services.prefs.clearUserPref("network.trr.uri");
|
||||
Services.prefs.clearUserPref("network.trr.credentials");
|
||||
Services.prefs.clearUserPref("network.trr.wait-for-portal");
|
||||
Services.prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
Services.prefs.clearUserPref("network.trr.useGET");
|
||||
Services.prefs.clearUserPref("network.trr.confirmationNS");
|
||||
Services.prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
Services.prefs.clearUserPref("network.trr.blacklist-duration");
|
||||
Services.prefs.clearUserPref("network.trr.request-timeout");
|
||||
Services.prefs.clearUserPref("network.trr.disable-ECS");
|
||||
Services.prefs.clearUserPref("network.trr.excluded-domains");
|
||||
|
||||
Services.prefs.clearUserPref("network.http.spdy.enabled");
|
||||
Services.prefs.clearUserPref("network.http.spdy.enabled.http2");
|
||||
Services.prefs.clearUserPref("network.dns.localDomains");
|
||||
Services.prefs.clearUserPref("network.dns.native-is-localhost");
|
||||
prefs.clearUserPref("network.http.spdy.enabled");
|
||||
prefs.clearUserPref("network.http.spdy.enabled.http2");
|
||||
prefs.clearUserPref("network.dns.localDomains");
|
||||
prefs.clearUserPref("network.dns.native-is-localhost");
|
||||
resetTRRPrefs();
|
||||
});
|
||||
|
||||
class DNSListener {
|
||||
constructor(name, expectedAnswer, expectedSuccess = true) {
|
||||
this.name = name;
|
||||
this.expectedAnswer = expectedAnswer;
|
||||
this.expectedSuccess = expectedSuccess;
|
||||
this.promise = new Promise(resolve => { this.resolve = resolve; });
|
||||
this.request = dns.asyncResolve(name, 0, this, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
function testsDone()
|
||||
{
|
||||
do_test_finished();
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
onLookupComplete(inRequest, inRecord, inStatus) {
|
||||
Assert.ok(inRequest == this.request);
|
||||
var test_loops;
|
||||
var test_answer="127.0.0.1";
|
||||
|
||||
// If we don't expect success here, just resolve and the caller will
|
||||
// decide what to do with the results.
|
||||
if (!this.expectedSuccess) {
|
||||
this.resolve([inRequest, inRecord, inStatus]);
|
||||
return;
|
||||
// check that we do lookup the name fine
|
||||
var listenerFine = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if (inRequest == listen) {
|
||||
Assert.equal(inStatus, Cr.NS_OK);
|
||||
var answer = inRecord.getNextAddrAsString();
|
||||
Assert.equal(answer, test_answer);
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
}
|
||||
|
||||
Assert.equal(inStatus, Cr.NS_OK);
|
||||
let answer = inRecord.getNextAddrAsString();
|
||||
Assert.equal(answer, this.expectedAnswer);
|
||||
this.resolve([inRequest, inRecord, inStatus]);
|
||||
}
|
||||
|
||||
QueryInterface(aIID) {
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
// Implement then so we can await this as a promise.
|
||||
then() {
|
||||
return this.promise.then.apply(this.promise, arguments);
|
||||
// check that the name lookup fails
|
||||
var listenerFails = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if (inRequest == listen) {
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `must be failure code: ${inStatus}`);
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
}
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// check that we do lookup the name fine
|
||||
var listenerUntilFine = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if ((inRequest == listen) && (inRecord != null)) {
|
||||
var answer = inRecord.getNextAddrAsString();
|
||||
if (answer == test_answer) {
|
||||
Assert.equal(answer, test_answer);
|
||||
dump("Got what we were waiting for!\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// not the one we want, try again
|
||||
dump("Waiting for " + test_answer + " but got " + answer + "\n");
|
||||
--test_loops;
|
||||
Assert.ok(test_loops != 0);
|
||||
current_test--;
|
||||
}
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
var listen;
|
||||
|
||||
// verify basic A record
|
||||
add_task(async function test1() {
|
||||
function test1()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2`);
|
||||
|
||||
await new DNSListener("bar.example.com", "2.2.2.2");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
test_answer="127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify basic A record - without bootstrapping
|
||||
add_task(async function test1b() {
|
||||
function test1b()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`);
|
||||
Services.prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com");
|
||||
|
||||
await new DNSListener("bar.example.com", "3.3.3.3");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
prefs.setCharPref("network.dns.localDomains", "foo.example.com");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify that the name was put in cache - it works with bad DNS URI
|
||||
add_task(async function test2() {
|
||||
function test2()
|
||||
{
|
||||
// Don't clear the cache. That is what we're checking.
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/404`);
|
||||
|
||||
await new DNSListener("bar.example.com", "3.3.3.3");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
//prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
//prefs.setCharPref("network.dns.localDomains", "foo.example.com");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify working credentials in DOH request
|
||||
add_task(async function test3() {
|
||||
function test3()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=4.4.4.4&auth=true`);
|
||||
Services.prefs.setCharPref("network.trr.credentials", "user:password");
|
||||
|
||||
await new DNSListener("bar.example.com", "4.4.4.4");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-auth");
|
||||
prefs.setCharPref("network.trr.credentials", "user:password");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify failing credentials in DOH request
|
||||
add_task(async function test4() {
|
||||
function test4()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=4.4.4.4&auth=true`);
|
||||
Services.prefs.setCharPref("network.trr.credentials", "evil:person");
|
||||
|
||||
let [, , inStatus] = await new DNSListener("wrong.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-auth");
|
||||
prefs.setCharPref("network.trr.credentials", "evil:person");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("wrong.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify DOH push, part A
|
||||
add_task(async function test5() {
|
||||
function test5()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=5.5.5.5&push=true`);
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-push");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("first.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
await new DNSListener("first.example.com", "5.5.5.5");
|
||||
});
|
||||
|
||||
add_task(async function test5b() {
|
||||
function test5b()
|
||||
{
|
||||
// At this point the second host name should've been pushed and we can resolve it using
|
||||
// cache only. Set back the URI to a path that fails.
|
||||
// Don't clear the cache, otherwise we lose the pushed record.
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/404`);
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
dump("test5b - resolve push.example.now please\n");
|
||||
|
||||
await new DNSListener("push.example.com", "2018::2018");
|
||||
});
|
||||
test_answer = "2018::2018";
|
||||
listen = dns.asyncResolve("push.example.com", 0, listenerUntilFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify AAAA entry
|
||||
add_task(async function test6() {
|
||||
function test6()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020`);
|
||||
await new DNSListener("aaaa.example.com", "2020:2020::2020");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-aaaa");
|
||||
test_answer = "2020:2020::2020";
|
||||
listen = dns.asyncResolve("aaaa.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify RFC1918 address from the server is rejected
|
||||
add_task(async function test7() {
|
||||
function test7()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.168.0.1`);
|
||||
let [, , inStatus] = await new DNSListener("rfc1918.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-rfc1918");
|
||||
listen = dns.asyncResolve("rfc1918.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify RFC1918 address from the server is fine when told so
|
||||
add_task(async function test8() {
|
||||
function test8()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.168.0.1`);
|
||||
Services.prefs.setBoolPref("network.trr.allow-rfc1918", true);
|
||||
await new DNSListener("rfc1918.example.com", "192.168.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-rfc1918");
|
||||
prefs.setBoolPref("network.trr.allow-rfc1918", true);
|
||||
test_answer = "192.168.0.1";
|
||||
listen = dns.asyncResolve("rfc1918.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// use GET and disable ECS (makes a larger request)
|
||||
// verify URI template cutoff
|
||||
add_task(async function test8b() {
|
||||
function test8b()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh{?dns}`);
|
||||
Services.prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
Services.prefs.setBoolPref("network.trr.useGET", true);
|
||||
Services.prefs.setBoolPref("network.trr.disable-ECS", true);
|
||||
await new DNSListener("ecs.example.com", "5.5.5.5");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ecs{?dns}");
|
||||
prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
prefs.setBoolPref("network.trr.useGET", true);
|
||||
prefs.setBoolPref("network.trr.disable-ECS", true);
|
||||
test_answer = "5.5.5.5";
|
||||
listen = dns.asyncResolve("ecs.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// use GET
|
||||
add_task(async function test9() {
|
||||
function test9()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh`);
|
||||
Services.prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
Services.prefs.setBoolPref("network.trr.useGET", true);
|
||||
Services.prefs.setBoolPref("network.trr.disable-ECS", false);
|
||||
await new DNSListener("get.example.com", "5.5.5.5");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-get");
|
||||
prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
prefs.setBoolPref("network.trr.useGET", true);
|
||||
prefs.setBoolPref("network.trr.disable-ECS", false);
|
||||
test_answer = "1.2.3.4";
|
||||
listen = dns.asyncResolve("get.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// confirmationNS set without confirmed NS yet
|
||||
// NOTE: this requires test9 to run before, as the http2 server resets state there
|
||||
add_task(async function test10() {
|
||||
function test10()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.clearUserPref("network.trr.useGET");
|
||||
Services.prefs.clearUserPref("network.trr.disable-ECS");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-confirm`);
|
||||
Services.prefs.setCharPref("network.trr.confirmationNS", "confirm.example.com");
|
||||
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.clearUserPref("network.trr.useGET");
|
||||
prefs.clearUserPref("network.trr.disable-ECS");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-confirm");
|
||||
prefs.setCharPref("network.trr.confirmationNS", "confirm.example.com");
|
||||
test_loops = 100; // set for test10b
|
||||
try {
|
||||
let [, , inStatus] = await new DNSListener("wrong.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
listen = dns.asyncResolve("wrong.example.com", 0, listenerFails,
|
||||
mainThread, defaultOriginAttributes);
|
||||
} catch (e) {
|
||||
await new Promise(resolve => do_timeout(200, resolve));
|
||||
// NS_ERROR_UNKNOWN_HOST exception is expected
|
||||
do_test_finished();
|
||||
do_timeout(200, run_dns_tests);
|
||||
//run_dns_tests();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// confirmationNS, retry until the confirmed NS works
|
||||
add_task(async function test10b() {
|
||||
function test10b()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
let test_loops = 100;
|
||||
print("test confirmationNS, retry until the confirmed NS works");
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
// same URI as in test10
|
||||
|
||||
// this test needs to resolve new names in every attempt since the DNS
|
||||
test_answer = "1::ffff"
|
||||
// this test needs to resolve new names in every attempt since the DNS cache
|
||||
// will keep the negative resolved info
|
||||
while (test_loops > 0) {
|
||||
print(`loops remaining: ${test_loops}`);
|
||||
try {
|
||||
let [, inRecord, inStatus] = await new DNSListener(`10b-${test_loops}.example.com`, undefined, false);
|
||||
if (inRecord) {
|
||||
Assert.equal(inStatus, Cr.NS_OK);
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
dump(e);
|
||||
}
|
||||
|
||||
try {
|
||||
listen = dns.asyncResolve("10b-" + test_loops + ".example.com", 0, listenerUntilFine,
|
||||
mainThread, defaultOriginAttributes);
|
||||
} catch(e) {
|
||||
// wait a while and try again
|
||||
test_loops--;
|
||||
await new Promise(resolve => do_timeout(0, resolve));
|
||||
do_timeout(200, test10b);
|
||||
}
|
||||
Assert.notEqual(test_loops, 0);
|
||||
});
|
||||
|
||||
}
|
||||
// use a slow server and short timeout!
|
||||
add_task(async function test11() {
|
||||
function test11()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms`);
|
||||
Services.prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
let [, , inStatus] = await new DNSListener("test11.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
listen = dns.asyncResolve("test11.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// gets an NS back from DOH
|
||||
add_task(async function test12() {
|
||||
function test12()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-ns`);
|
||||
Services.prefs.clearUserPref("network.trr.request-timeout");
|
||||
await new DNSListener("test12.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ns");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test12.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first gets a 404 back from DOH
|
||||
add_task(async function test13() {
|
||||
function test13()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/404`);
|
||||
await new DNSListener("test13.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test13.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow gets a 404 back from DOH
|
||||
add_task(async function test14() {
|
||||
function test14()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/404`);
|
||||
await new DNSListener("test14.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test14.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow and timed out TRR
|
||||
add_task(async function test15() {
|
||||
function test15()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms`);
|
||||
Services.prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
await new DNSListener("test15.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test15.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first and timed out TRR
|
||||
add_task(async function test16() {
|
||||
function test16()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms`);
|
||||
Services.prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
await new DNSListener("test16.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test16.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only and chase CNAME
|
||||
add_task(async function test17() {
|
||||
function test17()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname`);
|
||||
Services.prefs.clearUserPref("network.trr.request-timeout");
|
||||
await new DNSListener("cname.example.com", "99.88.77.66");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
test_answer = "99.88.77.66";
|
||||
listen = dns.asyncResolve("cname.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only and a CNAME loop
|
||||
add_task(async function test18() {
|
||||
function test18()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname-loop`);
|
||||
let [, , inStatus] = await new DNSListener("test18.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
listen = dns.asyncResolve("test18.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-race and a CNAME loop
|
||||
add_task(async function test19() {
|
||||
function test19()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 1); // Race them!
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname-loop`);
|
||||
await new DNSListener("test19.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 1); // Race them!
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test19.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first and a CNAME loop
|
||||
add_task(async function test20() {
|
||||
function test20()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname-loop`);
|
||||
await new DNSListener("test20.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test20.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow and a CNAME loop
|
||||
add_task(async function test21() {
|
||||
function test21()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 4); // shadow
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname-loop`);
|
||||
await new DNSListener("test21.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 4); // shadow
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test21.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify that basic A record name mismatch gets rejected.
|
||||
// Gets a response for bar.example.com instead of what it requested
|
||||
add_task(async function test22() {
|
||||
// verify that basic A record name mismatch gets rejected. Gets the same DOH
|
||||
// response back as test1
|
||||
function test22()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only to avoid native fallback
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns`);
|
||||
let [, , inStatus] = await new DNSListener("mismatch.example.com", undefined, false);
|
||||
Assert.ok(!Components.isSuccessCode(inStatus), `${inStatus} should be an error code`);
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only to avoid native fallback
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
listen = dns.asyncResolve("mismatch.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only, with a CNAME response with a bundled A record for that CNAME!
|
||||
add_task(async function test23() {
|
||||
function test23()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname-a`);
|
||||
await new DNSListener("cname-a.example.com", "9.8.7.6");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-a");
|
||||
test_answer = "9.8.7.6";
|
||||
listen = dns.asyncResolve("cname-a.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first check that TRR result is used
|
||||
add_task(async function test24() {
|
||||
function test24()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`);
|
||||
await new DNSListener("bar.example.com", "192.192.192.192");
|
||||
});
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.excluded-domains", "");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ip");
|
||||
test_answer = "192.192.192.192";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first check that DNS result is used if domain is part of the excluded-domains pref
|
||||
add_task(async function test24b() {
|
||||
function test24b()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "bar.example.com");
|
||||
await new DNSListener("bar.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setCharPref("network.trr.excluded-domains", "bar.example.com");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first check that DNS result is used if domain is part of the excluded-domains pref
|
||||
add_task(async function test24c() {
|
||||
function test24c()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "example.com");
|
||||
await new DNSListener("bar.example.com", "127.0.0.1");
|
||||
});
|
||||
prefs.setCharPref("network.trr.excluded-domains", "example.com");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only that resolving localhost with TRR-only mode will use the remote
|
||||
// resolver if it's not in the excluded domains
|
||||
add_task(async function test25() {
|
||||
// TRR-only check that localhost doesn't work if not in the excluded-domains list
|
||||
function test25()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`);
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.excluded-domains", "");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ip");
|
||||
|
||||
await new DNSListener("localhost", "192.192.192.192", true);
|
||||
});
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("localhost", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only check that localhost goes directly to native lookup when in the excluded-domains
|
||||
add_task(async function test25b() {
|
||||
// TRR-only check that localhost goes directly to native lookup when in the excluded-domains
|
||||
function test25b()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "localhost");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`);
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.excluded-domains", "localhost");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ip");
|
||||
|
||||
await new DNSListener("localhost", "127.0.0.1");
|
||||
});
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("localhost", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only check that test.local is resolved via native DNS
|
||||
add_task(async function test25c() {
|
||||
function test25c()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "localhost,local");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`);
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.excluded-domains", "localhost,local");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ip");
|
||||
|
||||
await new DNSListener("test.local", "127.0.0.1");
|
||||
});
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test.local", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only check that .other is resolved via native DNS when the pref is set
|
||||
add_task(async function test25d() {
|
||||
function test25d()
|
||||
{
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref("network.trr.excluded-domains", "localhost,local,other");
|
||||
Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`);
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.excluded-domains", "localhost,local,other");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ip");
|
||||
|
||||
await new DNSListener("domain.other", "127.0.0.1");
|
||||
});
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("domain.other", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
var tests = [ test1,
|
||||
test1b,
|
||||
test2,
|
||||
test3,
|
||||
test4,
|
||||
test5,
|
||||
test5b,
|
||||
test6,
|
||||
test7,
|
||||
test8,
|
||||
test8b,
|
||||
test9,
|
||||
test10,
|
||||
test10b,
|
||||
test11,
|
||||
test12,
|
||||
test13,
|
||||
test14,
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
test18,
|
||||
test19,
|
||||
test20,
|
||||
test21,
|
||||
test22,
|
||||
test23,
|
||||
test24,
|
||||
test24b,
|
||||
test24c,
|
||||
test25,
|
||||
test25b,
|
||||
test25c,
|
||||
test25d,
|
||||
testsDone
|
||||
];
|
||||
|
||||
var current_test = 0;
|
||||
|
||||
function run_dns_tests()
|
||||
{
|
||||
if (current_test < tests.length) {
|
||||
dump(`starting test ${tests[current_test].name}`);
|
||||
do_test_pending();
|
||||
tests[current_test++]();
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
@ -1,9 +0,0 @@
|
||||
root: true
|
||||
|
||||
parserOptions:
|
||||
ecmaVersion: 2015
|
||||
|
||||
env:
|
||||
node: true
|
||||
|
||||
extends: standard
|
4
testing/xpcshell/dns-packet/.gitignore
vendored
4
testing/xpcshell/dns-packet/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
node_modules/
|
||||
.nyc_output/
|
||||
coverage/
|
||||
package-lock.json
|
@ -1,11 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- node
|
||||
- lts/*
|
||||
install:
|
||||
- npm install
|
||||
- npm install coveralls
|
||||
script:
|
||||
- npm run coverage
|
||||
after_success:
|
||||
- npx nyc report --reporter=text-lcov | npx coveralls
|
@ -1,30 +0,0 @@
|
||||
# Version 5.2.0 - 2019-02-21
|
||||
|
||||
- Feature: Added support for de/encoding certain OPT options.
|
||||
|
||||
# Version 5.1.0 - 2019-01-22
|
||||
|
||||
- Feature: Added support for the RP record type.
|
||||
|
||||
# Version 5.0.0 - 2018-06-01
|
||||
|
||||
- Breaking: Node.js 6.0.0 or greater is now required.
|
||||
- Feature: Added support for DNSSEC record types.
|
||||
|
||||
# Version 4.1.0 - 2018-02-11
|
||||
|
||||
- Feature: Added support for the MX record type.
|
||||
|
||||
# Version 4.0.0 - 2018-02-04
|
||||
|
||||
- Feature: Added `streamEncode` and `streamDecode` methods for encoding TCP packets.
|
||||
- Breaking: Changed the decoded value of TXT records to an array of Buffers. This is to accomodate DNS-SD records which rely on the individual strings record being separated.
|
||||
- Breaking: Renamed the `flag_trunc` and `flag_auth` to `flag_tc` and `flag_aa` to match the names of these in the dns standards.
|
||||
|
||||
# Version 3.0.0 - 2018-01-12
|
||||
|
||||
- Breaking: The `class` option has been changed from integer to string.
|
||||
|
||||
# Version 2.0.0 - 2018-01-11
|
||||
|
||||
- Breaking: Converted module to ES2015, now requires Node.js 4.0 or greater
|
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Mathias Buus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@ -1,365 +0,0 @@
|
||||
# dns-packet
|
||||
[![](https://img.shields.io/npm/v/dns-packet.svg?style=flat)](https://www.npmjs.org/package/dns-packet) [![](https://img.shields.io/npm/dm/dns-packet.svg)](https://www.npmjs.org/package/dns-packet) [![](https://api.travis-ci.org/mafintosh/dns-packet.svg?style=flat)](https://travis-ci.org/mafintosh/dns-packet) [![Coverage Status](https://coveralls.io/repos/github/mafintosh/dns-packet/badge.svg?branch=master)](https://coveralls.io/github/mafintosh/dns-packet?branch=master)
|
||||
|
||||
An [abstract-encoding](https://github.com/mafintosh/abstract-encoding) compliant module for encoding / decoding DNS packets. Lifted out of [multicast-dns](https://github.com/mafintosh/multicast-dns) as a separate module.
|
||||
|
||||
```
|
||||
npm install dns-packet
|
||||
```
|
||||
|
||||
## UDP Usage
|
||||
|
||||
``` js
|
||||
const dnsPacket = require('dns-packet')
|
||||
const dgram = require('dgram')
|
||||
|
||||
const socket = dgram.createSocket('udp4')
|
||||
|
||||
const buf = dnsPacket.encode({
|
||||
type: 'query',
|
||||
id: 1,
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'google.com'
|
||||
}]
|
||||
})
|
||||
|
||||
socket.on('message', message => {
|
||||
console.log(dnsPacket.decode(message)) // prints out a response from google dns
|
||||
})
|
||||
|
||||
socket.send(buf, 0, buf.length, 53, '8.8.8.8')
|
||||
```
|
||||
|
||||
Also see [the UDP example](examples/udp.js).
|
||||
|
||||
## TCP, TLS, HTTPS
|
||||
|
||||
While DNS has traditionally been used over a datagram transport, it is increasingly being carried over TCP for larger responses commonly including DNSSEC responses and TLS or HTTPS for enhanced security. See below examples on how to use `dns-packet` to wrap DNS packets in these protocols:
|
||||
|
||||
- [TCP](examples/tcp.js)
|
||||
- [DNS over TLS](examples/tls.js)
|
||||
- [DNS over HTTPS](examples/doh.js)
|
||||
|
||||
## API
|
||||
|
||||
#### `var buf = packets.encode(packet, [buf], [offset])`
|
||||
|
||||
Encodes a DNS packet into a buffer containing a UDP payload.
|
||||
|
||||
#### `var packet = packets.decode(buf, [offset])`
|
||||
|
||||
Decode a DNS packet from a buffer containing a UDP payload.
|
||||
|
||||
#### `var buf = packets.streamEncode(packet, [buf], [offset])`
|
||||
|
||||
Encodes a DNS packet into a buffer containing a TCP payload.
|
||||
|
||||
#### `var packet = packets.streamDecode(buf, [offset])`
|
||||
|
||||
Decode a DNS packet from a buffer containing a TCP payload.
|
||||
|
||||
#### `var len = packets.encodingLength(packet)`
|
||||
|
||||
Returns how many bytes are needed to encode the DNS packet
|
||||
|
||||
## Packets
|
||||
|
||||
Packets look like this
|
||||
|
||||
``` js
|
||||
{
|
||||
type: 'query|response',
|
||||
id: optionalIdNumber,
|
||||
flags: optionalBitFlags,
|
||||
questions: [...],
|
||||
answers: [...],
|
||||
additionals: [...],
|
||||
authorities: [...]
|
||||
}
|
||||
```
|
||||
|
||||
The bit flags available are
|
||||
|
||||
``` js
|
||||
packet.RECURSION_DESIRED
|
||||
packet.RECURSION_AVAILABLE
|
||||
packet.TRUNCATED_RESPONSE
|
||||
packet.AUTHORITATIVE_ANSWER
|
||||
packet.AUTHENTIC_DATA
|
||||
packet.CHECKING_DISABLED
|
||||
```
|
||||
|
||||
To use more than one flag bitwise-or them together
|
||||
|
||||
``` js
|
||||
var flags = packet.RECURSION_DESIRED | packet.RECURSION_AVAILABLE
|
||||
```
|
||||
|
||||
And to check for a flag use bitwise-and
|
||||
|
||||
``` js
|
||||
var isRecursive = message.flags & packet.RECURSION_DESIRED
|
||||
```
|
||||
|
||||
A question looks like this
|
||||
|
||||
``` js
|
||||
{
|
||||
type: 'A', // or SRV, AAAA, etc
|
||||
class: 'IN', // one of IN, CS, CH, HS, ANY. Default: IN
|
||||
name: 'google.com' // which record are you looking for
|
||||
}
|
||||
```
|
||||
|
||||
And an answer, additional, or authority looks like this
|
||||
|
||||
``` js
|
||||
{
|
||||
type: 'A', // or SRV, AAAA, etc
|
||||
class: 'IN', // one of IN, CS, CH, HS
|
||||
name: 'google.com', // which name is this record for
|
||||
ttl: optionalTimeToLiveInSeconds,
|
||||
(record specific data, see below)
|
||||
}
|
||||
```
|
||||
|
||||
## Supported record types
|
||||
|
||||
#### `A`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'IPv4 address' // fx 127.0.0.1
|
||||
}
|
||||
```
|
||||
|
||||
#### `AAAA`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'IPv6 address' // fx fe80::1
|
||||
}
|
||||
```
|
||||
|
||||
#### `CAA`
|
||||
|
||||
``` js
|
||||
{
|
||||
flags: 128, // octet
|
||||
tag: 'issue|issuewild|iodef',
|
||||
value: 'ca.example.net',
|
||||
issuerCritical: false
|
||||
}
|
||||
```
|
||||
|
||||
#### `CNAME`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'cname.to.another.record'
|
||||
}
|
||||
```
|
||||
|
||||
#### `DNAME`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'dname.to.another.record'
|
||||
}
|
||||
```
|
||||
|
||||
#### `DNSKEY`
|
||||
|
||||
``` js
|
||||
{
|
||||
flags: 257, // 16 bits
|
||||
algorithm: 1, // octet
|
||||
key: Buffer
|
||||
}
|
||||
```
|
||||
|
||||
#### `DS`
|
||||
|
||||
``` js
|
||||
{
|
||||
keyTag: 12345,
|
||||
algorithm: 8,
|
||||
digestType: 1,
|
||||
digest: Buffer
|
||||
}
|
||||
```
|
||||
|
||||
#### `HINFO`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: {
|
||||
cpu: 'cpu info',
|
||||
os: 'os info'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `MX`
|
||||
|
||||
``` js
|
||||
{
|
||||
preference: 10,
|
||||
exchange: 'mail.example.net'
|
||||
}
|
||||
```
|
||||
|
||||
#### `NS`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: nameServer
|
||||
}
|
||||
```
|
||||
|
||||
#### `NSEC`
|
||||
|
||||
``` js
|
||||
{
|
||||
nextDomain: 'a.domain',
|
||||
rrtypes: ['A', 'TXT', 'RRSIG']
|
||||
}
|
||||
```
|
||||
|
||||
#### `NSEC3`
|
||||
|
||||
``` js
|
||||
{
|
||||
algorithm: 1,
|
||||
flags: 0,
|
||||
iterations: 2,
|
||||
salt: Buffer,
|
||||
nextDomain: Buffer, // Hashed per RFC5155
|
||||
rrtypes: ['A', 'TXT', 'RRSIG']
|
||||
}
|
||||
```
|
||||
|
||||
#### `NULL`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: Buffer('any binary data')
|
||||
}
|
||||
```
|
||||
|
||||
#### `OPT`
|
||||
|
||||
[EDNS0](https://tools.ietf.org/html/rfc6891) options.
|
||||
|
||||
``` js
|
||||
{
|
||||
type: 'OPT',
|
||||
name: '.',
|
||||
udpPayloadSize: 4096,
|
||||
flags: packet.DNSSEC_OK,
|
||||
options: [{
|
||||
// pass in any code/data for generic EDNS0 options
|
||||
code: 12,
|
||||
data: Buffer.alloc(31)
|
||||
}, {
|
||||
// Several EDNS0 options have enhanced support
|
||||
code: 'PADDING',
|
||||
length: 31,
|
||||
}, {
|
||||
code: 'CLIENT_SUBNET',
|
||||
family: 2, // 1 for IPv4, 2 for IPv6
|
||||
sourcePrefixLength: 64, // used to truncate IP address
|
||||
scopePrefixLength: 0,
|
||||
ip: 'fe80::',
|
||||
}, {
|
||||
code: 'TCP_KEEPALIVE',
|
||||
timeout: 150 // increments of 100ms. This means 15s.
|
||||
}, {
|
||||
code: 'KEY_TAG',
|
||||
tags: [1, 2, 3],
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
The options `PADDING`, `CLIENT_SUBNET`, `TCP_KEEPALIVE` and `KEY_TAG` support enhanced de/encoding. See [optionscodes.js](https://github.com/mafintosh/dns-packet/blob/master/optioncodes.js) for all supported option codes. If the `data` property is present on a option, it takes precedence. On decoding, `data` will always be defined.
|
||||
|
||||
#### `PTR`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'points.to.another.record'
|
||||
}
|
||||
```
|
||||
|
||||
#### `RP`
|
||||
|
||||
``` js
|
||||
{
|
||||
mbox: 'admin.example.com',
|
||||
txt: 'txt.example.com'
|
||||
}
|
||||
```
|
||||
|
||||
#### `RRSIG`
|
||||
|
||||
``` js
|
||||
{
|
||||
typeCovered: 'A',
|
||||
algorithm: 8,
|
||||
labels: 1,
|
||||
originalTTL: 3600,
|
||||
expiration: timestamp,
|
||||
inception: timestamp,
|
||||
keyTag: 12345,
|
||||
signersName: 'a.name',
|
||||
signature: Buffer
|
||||
}
|
||||
```
|
||||
|
||||
#### `SOA`
|
||||
|
||||
``` js
|
||||
{
|
||||
data:
|
||||
{
|
||||
mname: domainName,
|
||||
rname: mailbox,
|
||||
serial: zoneSerial,
|
||||
refresh: refreshInterval,
|
||||
retry: retryInterval,
|
||||
expire: expireInterval,
|
||||
minimum: minimumTTL
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `SRV`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: {
|
||||
port: servicePort,
|
||||
target: serviceHostName,
|
||||
priority: optionalServicePriority,
|
||||
weight: optionalServiceWeight
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `TXT`
|
||||
|
||||
``` js
|
||||
{
|
||||
data: 'text' || Buffer || [ Buffer || 'text' ]
|
||||
}
|
||||
```
|
||||
|
||||
When encoding, scalar values are converted to an array and strings are converted to UTF-8 encoded Buffers. When decoding, the return value will always be an array of Buffer.
|
||||
|
||||
If you need another record type, open an issue and we'll try to add it.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
@ -1,23 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
exports.toString = function (klass) {
|
||||
switch (klass) {
|
||||
case 1: return 'IN'
|
||||
case 2: return 'CS'
|
||||
case 3: return 'CH'
|
||||
case 4: return 'HS'
|
||||
case 255: return 'ANY'
|
||||
}
|
||||
return 'UNKNOWN_' + klass
|
||||
}
|
||||
|
||||
exports.toClass = function (name) {
|
||||
switch (name.toUpperCase()) {
|
||||
case 'IN': return 1
|
||||
case 'CS': return 2
|
||||
case 'CH': return 3
|
||||
case 'HS': return 4
|
||||
case 'ANY': return 255
|
||||
}
|
||||
return 0
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
* Sample code to make DNS over HTTPS request using POST
|
||||
* AUTHOR: Tom Pusateri <pusateri@bangj.com>
|
||||
* DATE: March 17, 2018
|
||||
* LICENSE: MIT
|
||||
*/
|
||||
|
||||
const dnsPacket = require('..')
|
||||
const https = require('https')
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
const buf = dnsPacket.encode({
|
||||
type: 'query',
|
||||
id: getRandomInt(1, 65534),
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'google.com'
|
||||
}]
|
||||
})
|
||||
|
||||
const options = {
|
||||
hostname: 'dns.google.com',
|
||||
port: 443,
|
||||
path: '/experimental',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/dns-udpwireformat',
|
||||
'Content-Length': Buffer.byteLength(buf)
|
||||
}
|
||||
}
|
||||
|
||||
const request = https.request(options, (response) => {
|
||||
console.log('statusCode:', response.statusCode)
|
||||
console.log('headers:', response.headers)
|
||||
|
||||
response.on('data', (d) => {
|
||||
console.log(dnsPacket.decode(d))
|
||||
})
|
||||
})
|
||||
|
||||
request.on('error', (e) => {
|
||||
console.error(e)
|
||||
})
|
||||
request.write(buf)
|
||||
request.end()
|
@ -1,52 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const dnsPacket = require('..')
|
||||
const net = require('net')
|
||||
|
||||
var response = null
|
||||
var expectedLength = 0
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
const buf = dnsPacket.streamEncode({
|
||||
type: 'query',
|
||||
id: getRandomInt(1, 65534),
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'google.com'
|
||||
}]
|
||||
})
|
||||
|
||||
const client = new net.Socket()
|
||||
client.connect(53, '8.8.8.8', function () {
|
||||
console.log('Connected')
|
||||
client.write(buf)
|
||||
})
|
||||
|
||||
client.on('data', function (data) {
|
||||
console.log('Received response: %d bytes', data.byteLength)
|
||||
if (response == null) {
|
||||
if (data.byteLength > 1) {
|
||||
const plen = data.readUInt16BE(0)
|
||||
expectedLength = plen
|
||||
if (plen < 12) {
|
||||
throw new Error('below DNS minimum packet length')
|
||||
}
|
||||
response = Buffer.from(data)
|
||||
}
|
||||
} else {
|
||||
response = Buffer.concat([response, data])
|
||||
}
|
||||
|
||||
if (response.byteLength >= expectedLength) {
|
||||
console.log(dnsPacket.streamDecode(response))
|
||||
client.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
client.on('close', function () {
|
||||
console.log('Connection closed')
|
||||
})
|
@ -1,61 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const tls = require('tls')
|
||||
const dnsPacket = require('..')
|
||||
|
||||
var response = null
|
||||
var expectedLength = 0
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
const buf = dnsPacket.streamEncode({
|
||||
type: 'query',
|
||||
id: getRandomInt(1, 65534),
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'google.com'
|
||||
}]
|
||||
})
|
||||
|
||||
const context = tls.createSecureContext({
|
||||
secureProtocol: 'TLSv1_2_method'
|
||||
})
|
||||
|
||||
const options = {
|
||||
port: 853,
|
||||
host: 'getdnsapi.net',
|
||||
secureContext: context
|
||||
}
|
||||
|
||||
const client = tls.connect(options, () => {
|
||||
console.log('client connected')
|
||||
client.write(buf)
|
||||
})
|
||||
|
||||
client.on('data', function (data) {
|
||||
console.log('Received response: %d bytes', data.byteLength)
|
||||
if (response == null) {
|
||||
if (data.byteLength > 1) {
|
||||
const plen = data.readUInt16BE(0)
|
||||
expectedLength = plen
|
||||
if (plen < 12) {
|
||||
throw new Error('below DNS minimum packet length')
|
||||
}
|
||||
response = Buffer.from(data)
|
||||
}
|
||||
} else {
|
||||
response = Buffer.concat([response, data])
|
||||
}
|
||||
|
||||
if (response.byteLength >= expectedLength) {
|
||||
console.log(dnsPacket.streamDecode(response))
|
||||
client.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
client.on('end', () => {
|
||||
console.log('Connection ended')
|
||||
})
|
@ -1,28 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const dnsPacket = require('..')
|
||||
const dgram = require('dgram')
|
||||
|
||||
const socket = dgram.createSocket('udp4')
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
const buf = dnsPacket.encode({
|
||||
type: 'query',
|
||||
id: getRandomInt(1, 65534),
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'google.com'
|
||||
}]
|
||||
})
|
||||
|
||||
socket.on('message', function (message, rinfo) {
|
||||
console.log(rinfo)
|
||||
console.log(dnsPacket.decode(message)) // prints out a response from google dns
|
||||
socket.close()
|
||||
})
|
||||
|
||||
socket.send(buf, 0, buf.length, 53, '8.8.8.8')
|
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
* Traditional DNS header OPCODEs (4-bits) defined by IANA in
|
||||
* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5
|
||||
*/
|
||||
|
||||
exports.toString = function (opcode) {
|
||||
switch (opcode) {
|
||||
case 0: return 'QUERY'
|
||||
case 1: return 'IQUERY'
|
||||
case 2: return 'STATUS'
|
||||
case 3: return 'OPCODE_3'
|
||||
case 4: return 'NOTIFY'
|
||||
case 5: return 'UPDATE'
|
||||
case 6: return 'OPCODE_6'
|
||||
case 7: return 'OPCODE_7'
|
||||
case 8: return 'OPCODE_8'
|
||||
case 9: return 'OPCODE_9'
|
||||
case 10: return 'OPCODE_10'
|
||||
case 11: return 'OPCODE_11'
|
||||
case 12: return 'OPCODE_12'
|
||||
case 13: return 'OPCODE_13'
|
||||
case 14: return 'OPCODE_14'
|
||||
case 15: return 'OPCODE_15'
|
||||
}
|
||||
return 'OPCODE_' + opcode
|
||||
}
|
||||
|
||||
exports.toOpcode = function (code) {
|
||||
switch (code.toUpperCase()) {
|
||||
case 'QUERY': return 0
|
||||
case 'IQUERY': return 1
|
||||
case 'STATUS': return 2
|
||||
case 'OPCODE_3': return 3
|
||||
case 'NOTIFY': return 4
|
||||
case 'UPDATE': return 5
|
||||
case 'OPCODE_6': return 6
|
||||
case 'OPCODE_7': return 7
|
||||
case 'OPCODE_8': return 8
|
||||
case 'OPCODE_9': return 9
|
||||
case 'OPCODE_10': return 10
|
||||
case 'OPCODE_11': return 11
|
||||
case 'OPCODE_12': return 12
|
||||
case 'OPCODE_13': return 13
|
||||
case 'OPCODE_14': return 14
|
||||
case 'OPCODE_15': return 15
|
||||
}
|
||||
return 0
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
exports.toString = function (type) {
|
||||
switch (type) {
|
||||
// list at
|
||||
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11
|
||||
case 1: return 'LLQ'
|
||||
case 2: return 'UL'
|
||||
case 3: return 'NSID'
|
||||
case 5: return 'DAU'
|
||||
case 6: return 'DHU'
|
||||
case 7: return 'N3U'
|
||||
case 8: return 'CLIENT_SUBNET'
|
||||
case 9: return 'EXPIRE'
|
||||
case 10: return 'COOKIE'
|
||||
case 11: return 'TCP_KEEPALIVE'
|
||||
case 12: return 'PADDING'
|
||||
case 13: return 'CHAIN'
|
||||
case 14: return 'KEY_TAG'
|
||||
case 26946: return 'DEVICEID'
|
||||
}
|
||||
if (type < 0) {
|
||||
return null
|
||||
}
|
||||
return `OPTION_${type}`
|
||||
}
|
||||
|
||||
exports.toCode = function (name) {
|
||||
if (typeof name === 'number') {
|
||||
return name
|
||||
}
|
||||
if (!name) {
|
||||
return -1
|
||||
}
|
||||
switch (name.toUpperCase()) {
|
||||
case 'OPTION_0': return 0
|
||||
case 'LLQ': return 1
|
||||
case 'UL': return 2
|
||||
case 'NSID': return 3
|
||||
case 'OPTION_4': return 4
|
||||
case 'DAU': return 5
|
||||
case 'DHU': return 6
|
||||
case 'N3U': return 7
|
||||
case 'CLIENT_SUBNET': return 8
|
||||
case 'EXPIRE': return 9
|
||||
case 'COOKIE': return 10
|
||||
case 'TCP_KEEPALIVE': return 11
|
||||
case 'PADDING': return 12
|
||||
case 'CHAIN': return 13
|
||||
case 'KEY_TAG': return 14
|
||||
case 'DEVICEID': return 26946
|
||||
case 'OPTION_65535': return 65535
|
||||
}
|
||||
const m = name.match(/_(\d+)$/)
|
||||
if (m) {
|
||||
return parseInt(m[1], 10)
|
||||
}
|
||||
return -1
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "dns-packet",
|
||||
"version": "5.2.1",
|
||||
"description": "An abstract-encoding compliant module for encoding / decoding DNS packets",
|
||||
"author": "Mathias Buus",
|
||||
"license": "MIT",
|
||||
"repository": "mafintosh/dns-packet",
|
||||
"homepage": "https://github.com/mafintosh/dns-packet",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf coverage .nyc_output/",
|
||||
"lint": "eslint --color *.js examples/*.js",
|
||||
"pretest": "npm run lint",
|
||||
"test": "tape test.js",
|
||||
"coverage": "nyc -r html npm test"
|
||||
},
|
||||
"dependencies": {
|
||||
"ip": "^1.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^5.14.1",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.16.0",
|
||||
"eslint-plugin-node": "^8.0.1",
|
||||
"eslint-plugin-promise": "^4.0.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"nyc": "^13.3.0",
|
||||
"tape": "^4.10.1"
|
||||
},
|
||||
"keywords": [
|
||||
"dns",
|
||||
"packet",
|
||||
"encodings",
|
||||
"encoding",
|
||||
"encoder",
|
||||
"abstract-encoding"
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"types.js",
|
||||
"rcodes.js",
|
||||
"opcodes.js",
|
||||
"classes.js",
|
||||
"optioncodes.js"
|
||||
]
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
* Traditional DNS header RCODEs (4-bits) defined by IANA in
|
||||
* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
||||
*/
|
||||
|
||||
exports.toString = function (rcode) {
|
||||
switch (rcode) {
|
||||
case 0: return 'NOERROR'
|
||||
case 1: return 'FORMERR'
|
||||
case 2: return 'SERVFAIL'
|
||||
case 3: return 'NXDOMAIN'
|
||||
case 4: return 'NOTIMP'
|
||||
case 5: return 'REFUSED'
|
||||
case 6: return 'YXDOMAIN'
|
||||
case 7: return 'YXRRSET'
|
||||
case 8: return 'NXRRSET'
|
||||
case 9: return 'NOTAUTH'
|
||||
case 10: return 'NOTZONE'
|
||||
case 11: return 'RCODE_11'
|
||||
case 12: return 'RCODE_12'
|
||||
case 13: return 'RCODE_13'
|
||||
case 14: return 'RCODE_14'
|
||||
case 15: return 'RCODE_15'
|
||||
}
|
||||
return 'RCODE_' + rcode
|
||||
}
|
||||
|
||||
exports.toRcode = function (code) {
|
||||
switch (code.toUpperCase()) {
|
||||
case 'NOERROR': return 0
|
||||
case 'FORMERR': return 1
|
||||
case 'SERVFAIL': return 2
|
||||
case 'NXDOMAIN': return 3
|
||||
case 'NOTIMP': return 4
|
||||
case 'REFUSED': return 5
|
||||
case 'YXDOMAIN': return 6
|
||||
case 'YXRRSET': return 7
|
||||
case 'NXRRSET': return 8
|
||||
case 'NOTAUTH': return 9
|
||||
case 'NOTZONE': return 10
|
||||
case 'RCODE_11': return 11
|
||||
case 'RCODE_12': return 12
|
||||
case 'RCODE_13': return 13
|
||||
case 'RCODE_14': return 14
|
||||
case 'RCODE_15': return 15
|
||||
}
|
||||
return 0
|
||||
}
|
@ -1,613 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const tape = require('tape')
|
||||
const packet = require('./')
|
||||
const rcodes = require('./rcodes')
|
||||
const opcodes = require('./opcodes')
|
||||
const optioncodes = require('./optioncodes')
|
||||
|
||||
tape('unknown', function (t) {
|
||||
testEncoder(t, packet.unknown, Buffer.from('hello world'))
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('txt', function (t) {
|
||||
testEncoder(t, packet.txt, [])
|
||||
testEncoder(t, packet.txt, ['hello world'])
|
||||
testEncoder(t, packet.txt, ['hello', 'world'])
|
||||
testEncoder(t, packet.txt, [Buffer.from([0, 1, 2, 3, 4, 5])])
|
||||
testEncoder(t, packet.txt, ['a', 'b', Buffer.from([0, 1, 2, 3, 4, 5])])
|
||||
testEncoder(t, packet.txt, ['', Buffer.allocUnsafe(0)])
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('txt-scalar-string', function (t) {
|
||||
const buf = packet.txt.encode('hi')
|
||||
const val = packet.txt.decode(buf)
|
||||
t.ok(val.length === 1, 'array length')
|
||||
t.ok(val[0].toString() === 'hi', 'data')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('txt-scalar-buffer', function (t) {
|
||||
const data = Buffer.from([0, 1, 2, 3, 4, 5])
|
||||
const buf = packet.txt.encode(data)
|
||||
const val = packet.txt.decode(buf)
|
||||
t.ok(val.length === 1, 'array length')
|
||||
t.ok(val[0].equals(data), 'data')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('txt-invalid-data', function (t) {
|
||||
t.throws(function () { packet.txt.encode(null) }, 'null')
|
||||
t.throws(function () { packet.txt.encode(undefined) }, 'undefined')
|
||||
t.throws(function () { packet.txt.encode(10) }, 'number')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('null', function (t) {
|
||||
testEncoder(t, packet.null, Buffer.from([0, 1, 2, 3, 4, 5]))
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('hinfo', function (t) {
|
||||
testEncoder(t, packet.hinfo, { cpu: 'intel', os: 'best one' })
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('ptr', function (t) {
|
||||
testEncoder(t, packet.ptr, 'hello.world.com')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('cname', function (t) {
|
||||
testEncoder(t, packet.cname, 'hello.cname.world.com')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('dname', function (t) {
|
||||
testEncoder(t, packet.dname, 'hello.dname.world.com')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('srv', function (t) {
|
||||
testEncoder(t, packet.srv, { port: 9999, target: 'hello.world.com' })
|
||||
testEncoder(t, packet.srv, { port: 9999, target: 'hello.world.com', priority: 42, weight: 10 })
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('caa', function (t) {
|
||||
testEncoder(t, packet.caa, { flags: 128, tag: 'issue', value: 'letsencrypt.org', issuerCritical: true })
|
||||
testEncoder(t, packet.caa, { tag: 'issue', value: 'letsencrypt.org', issuerCritical: true })
|
||||
testEncoder(t, packet.caa, { tag: 'issue', value: 'letsencrypt.org' })
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('mx', function (t) {
|
||||
testEncoder(t, packet.mx, { preference: 10, exchange: 'mx.hello.world.com' })
|
||||
testEncoder(t, packet.mx, { exchange: 'mx.hello.world.com' })
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('ns', function (t) {
|
||||
testEncoder(t, packet.ns, 'ns.world.com')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('soa', function (t) {
|
||||
testEncoder(t, packet.soa, {
|
||||
mname: 'hello.world.com',
|
||||
rname: 'root.hello.world.com',
|
||||
serial: 2018010400,
|
||||
refresh: 14400,
|
||||
retry: 3600,
|
||||
expire: 604800,
|
||||
minimum: 3600
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('a', function (t) {
|
||||
testEncoder(t, packet.a, '127.0.0.1')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('aaaa', function (t) {
|
||||
testEncoder(t, packet.aaaa, 'fe80::1')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('query', function (t) {
|
||||
testEncoder(t, packet, {
|
||||
type: 'query',
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'hello.a.com'
|
||||
}, {
|
||||
type: 'SRV',
|
||||
name: 'hello.srv.com'
|
||||
}]
|
||||
})
|
||||
|
||||
testEncoder(t, packet, {
|
||||
type: 'query',
|
||||
id: 42,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
class: 'IN',
|
||||
name: 'hello.a.com'
|
||||
}, {
|
||||
type: 'SRV',
|
||||
name: 'hello.srv.com'
|
||||
}]
|
||||
})
|
||||
|
||||
testEncoder(t, packet, {
|
||||
type: 'query',
|
||||
id: 42,
|
||||
questions: [{
|
||||
type: 'A',
|
||||
class: 'CH',
|
||||
name: 'hello.a.com'
|
||||
}, {
|
||||
type: 'SRV',
|
||||
name: 'hello.srv.com'
|
||||
}]
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('response', function (t) {
|
||||
testEncoder(t, packet, {
|
||||
type: 'response',
|
||||
answers: [{
|
||||
type: 'A',
|
||||
class: 'IN',
|
||||
flush: true,
|
||||
name: 'hello.a.com',
|
||||
data: '127.0.0.1'
|
||||
}]
|
||||
})
|
||||
|
||||
testEncoder(t, packet, {
|
||||
type: 'response',
|
||||
flags: packet.TRUNCATED_RESPONSE,
|
||||
answers: [{
|
||||
type: 'A',
|
||||
class: 'IN',
|
||||
name: 'hello.a.com',
|
||||
data: '127.0.0.1'
|
||||
}, {
|
||||
type: 'SRV',
|
||||
class: 'IN',
|
||||
name: 'hello.srv.com',
|
||||
data: {
|
||||
port: 9090,
|
||||
target: 'hello.target.com'
|
||||
}
|
||||
}, {
|
||||
type: 'CNAME',
|
||||
class: 'IN',
|
||||
name: 'hello.cname.com',
|
||||
data: 'hello.other.domain.com'
|
||||
}]
|
||||
})
|
||||
|
||||
testEncoder(t, packet, {
|
||||
type: 'response',
|
||||
id: 100,
|
||||
flags: 0,
|
||||
additionals: [{
|
||||
type: 'AAAA',
|
||||
name: 'hello.a.com',
|
||||
data: 'fe80::1'
|
||||
}, {
|
||||
type: 'PTR',
|
||||
name: 'hello.ptr.com',
|
||||
data: 'hello.other.ptr.com'
|
||||
}, {
|
||||
type: 'SRV',
|
||||
name: 'hello.srv.com',
|
||||
ttl: 42,
|
||||
data: {
|
||||
port: 9090,
|
||||
target: 'hello.target.com'
|
||||
}
|
||||
}],
|
||||
answers: [{
|
||||
type: 'NULL',
|
||||
name: 'hello.null.com',
|
||||
data: Buffer.from([1, 2, 3, 4, 5])
|
||||
}]
|
||||
})
|
||||
|
||||
testEncoder(t, packet, {
|
||||
type: 'response',
|
||||
answers: [{
|
||||
type: 'TXT',
|
||||
name: 'emptytxt.com',
|
||||
data: ''
|
||||
}]
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('rcode', function (t) {
|
||||
const errors = ['NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'YXRRSET', 'NXRRSET', 'NOTAUTH', 'NOTZONE', 'RCODE_11', 'RCODE_12', 'RCODE_13', 'RCODE_14', 'RCODE_15']
|
||||
for (const i in errors) {
|
||||
const code = rcodes.toRcode(errors[i])
|
||||
t.ok(errors[i] === rcodes.toString(code), 'rcode conversion from/to string matches: ' + rcodes.toString(code))
|
||||
}
|
||||
|
||||
const ops = ['QUERY', 'IQUERY', 'STATUS', 'OPCODE_3', 'NOTIFY', 'UPDATE', 'OPCODE_6', 'OPCODE_7', 'OPCODE_8', 'OPCODE_9', 'OPCODE_10', 'OPCODE_11', 'OPCODE_12', 'OPCODE_13', 'OPCODE_14', 'OPCODE_15']
|
||||
for (const j in ops) {
|
||||
const ocode = opcodes.toOpcode(ops[j])
|
||||
t.ok(ops[j] === opcodes.toString(ocode), 'opcode conversion from/to string matches: ' + opcodes.toString(ocode))
|
||||
}
|
||||
|
||||
const buf = packet.encode({
|
||||
type: 'response',
|
||||
id: 45632,
|
||||
flags: 0x8480,
|
||||
answers: [{
|
||||
type: 'A',
|
||||
name: 'hello.example.net',
|
||||
data: '127.0.0.1'
|
||||
}]
|
||||
})
|
||||
const val = packet.decode(buf)
|
||||
t.ok(val.type === 'response', 'decode type')
|
||||
t.ok(val.opcode === 'QUERY', 'decode opcode')
|
||||
t.ok(val.flag_qr === true, 'decode flag_qr')
|
||||
t.ok(val.flag_aa === true, 'decode flag_aa')
|
||||
t.ok(val.flag_tc === false, 'decode flag_tc')
|
||||
t.ok(val.flag_rd === false, 'decode flag_rd')
|
||||
t.ok(val.flag_ra === true, 'decode flag_ra')
|
||||
t.ok(val.flag_z === false, 'decode flag_z')
|
||||
t.ok(val.flag_ad === false, 'decode flag_ad')
|
||||
t.ok(val.flag_cd === false, 'decode flag_cd')
|
||||
t.ok(val.rcode === 'NOERROR', 'decode rcode')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('name_encoding', function (t) {
|
||||
let data = 'foo.example.com'
|
||||
const buf = Buffer.allocUnsafe(255)
|
||||
let offset = 0
|
||||
packet.name.encode(data, buf, offset)
|
||||
t.ok(packet.name.encode.bytes === 17, 'name encoding length matches')
|
||||
let dd = packet.name.decode(buf, offset)
|
||||
t.ok(data === dd, 'encode/decode matches')
|
||||
offset += packet.name.encode.bytes
|
||||
|
||||
data = 'com'
|
||||
packet.name.encode(data, buf, offset)
|
||||
t.ok(packet.name.encode.bytes === 5, 'name encoding length matches')
|
||||
dd = packet.name.decode(buf, offset)
|
||||
t.ok(data === dd, 'encode/decode matches')
|
||||
offset += packet.name.encode.bytes
|
||||
|
||||
data = 'example.com.'
|
||||
packet.name.encode(data, buf, offset)
|
||||
t.ok(packet.name.encode.bytes === 13, 'name encoding length matches')
|
||||
dd = packet.name.decode(buf, offset)
|
||||
t.ok(data.slice(0, -1) === dd, 'encode/decode matches')
|
||||
offset += packet.name.encode.bytes
|
||||
|
||||
data = '.'
|
||||
packet.name.encode(data, buf, offset)
|
||||
t.ok(packet.name.encode.bytes === 1, 'name encoding length matches')
|
||||
dd = packet.name.decode(buf, offset)
|
||||
t.ok(data === dd, 'encode/decode matches')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('stream', function (t) {
|
||||
const val = {
|
||||
type: 'query',
|
||||
id: 45632,
|
||||
flags: 0x8480,
|
||||
answers: [{
|
||||
type: 'A',
|
||||
name: 'test2.example.net',
|
||||
data: '198.51.100.1'
|
||||
}]
|
||||
}
|
||||
const buf = packet.streamEncode(val)
|
||||
const val2 = packet.streamDecode(buf)
|
||||
|
||||
t.same(buf.length, packet.streamEncode.bytes, 'streamEncode.bytes was set correctly')
|
||||
t.ok(compare(t, val2.type, val.type), 'streamDecoded type match')
|
||||
t.ok(compare(t, val2.id, val.id), 'streamDecoded id match')
|
||||
t.ok(parseInt(val2.flags) === parseInt(val.flags & 0x7FFF), 'streamDecoded flags match')
|
||||
const answer = val.answers[0]
|
||||
const answer2 = val2.answers[0]
|
||||
t.ok(compare(t, answer.type, answer2.type), 'streamDecoded RR type match')
|
||||
t.ok(compare(t, answer.name, answer2.name), 'streamDecoded RR name match')
|
||||
t.ok(compare(t, answer.data, answer2.data), 'streamDecoded RR rdata match')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('opt', function (t) {
|
||||
const val = {
|
||||
type: 'query',
|
||||
questions: [{
|
||||
type: 'A',
|
||||
name: 'hello.a.com'
|
||||
}],
|
||||
additionals: [{
|
||||
type: 'OPT',
|
||||
name: '.',
|
||||
udpPayloadSize: 1024
|
||||
}]
|
||||
}
|
||||
testEncoder(t, packet, val)
|
||||
let buf = packet.encode(val)
|
||||
let val2 = packet.decode(buf)
|
||||
const additional1 = val.additionals[0]
|
||||
let additional2 = val2.additionals[0]
|
||||
t.ok(compare(t, additional1.name, additional2.name), 'name matches')
|
||||
t.ok(compare(t, additional1.udpPayloadSize, additional2.udpPayloadSize), 'udp payload size matches')
|
||||
t.ok(compare(t, 0, additional2.flags), 'flags match')
|
||||
additional1.flags = packet.DNSSEC_OK
|
||||
additional1.extendedRcode = 0x80
|
||||
additional1.options = [ {
|
||||
code: 'CLIENT_SUBNET', // edns-client-subnet, see RFC 7871
|
||||
ip: 'fe80::',
|
||||
sourcePrefixLength: 64
|
||||
}, {
|
||||
code: 8, // still ECS
|
||||
ip: '5.6.0.0',
|
||||
sourcePrefixLength: 16,
|
||||
scopePrefixLength: 16
|
||||
}, {
|
||||
code: 'padding',
|
||||
length: 31
|
||||
}, {
|
||||
code: 'TCP_KEEPALIVE'
|
||||
}, {
|
||||
code: 'tcp_keepalive',
|
||||
timeout: 150
|
||||
}, {
|
||||
code: 'KEY_TAG',
|
||||
tags: [1, 82, 987]
|
||||
}]
|
||||
buf = packet.encode(val)
|
||||
val2 = packet.decode(buf)
|
||||
additional2 = val2.additionals[0]
|
||||
t.ok(compare(t, 1 << 15, additional2.flags), 'DO bit set in flags')
|
||||
t.ok(compare(t, true, additional2.flag_do), 'DO bit set')
|
||||
t.ok(compare(t, additional1.extendedRcode, additional2.extendedRcode), 'extended rcode matches')
|
||||
t.ok(compare(t, 8, additional2.options[0].code))
|
||||
t.ok(compare(t, 'fe80::', additional2.options[0].ip))
|
||||
t.ok(compare(t, 64, additional2.options[0].sourcePrefixLength))
|
||||
t.ok(compare(t, '5.6.0.0', additional2.options[1].ip))
|
||||
t.ok(compare(t, 16, additional2.options[1].sourcePrefixLength))
|
||||
t.ok(compare(t, 16, additional2.options[1].scopePrefixLength))
|
||||
t.ok(compare(t, additional1.options[2].length, additional2.options[2].data.length))
|
||||
t.ok(compare(t, additional1.options[3].timeout, undefined))
|
||||
t.ok(compare(t, additional1.options[4].timeout, additional2.options[4].timeout))
|
||||
t.ok(compare(t, additional1.options[5].tags, additional2.options[5].tags))
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('dnskey', function (t) {
|
||||
testEncoder(t, packet.dnskey, {
|
||||
flags: packet.dnskey.SECURE_ENTRYPOINT | packet.dnskey.ZONE_KEY,
|
||||
algorithm: 1,
|
||||
key: Buffer.from([0, 1, 2, 3, 4, 5])
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('rrsig', function (t) {
|
||||
const testRRSIG = {
|
||||
typeCovered: 'A',
|
||||
algorithm: 1,
|
||||
labels: 2,
|
||||
originalTTL: 3600,
|
||||
expiration: 1234,
|
||||
inception: 1233,
|
||||
keyTag: 2345,
|
||||
signersName: 'foo.com',
|
||||
signature: Buffer.from([0, 1, 2, 3, 4, 5])
|
||||
}
|
||||
testEncoder(t, packet.rrsig, testRRSIG)
|
||||
|
||||
// Check the signature length is correct with extra junk at the end
|
||||
const buf = Buffer.allocUnsafe(packet.rrsig.encodingLength(testRRSIG) + 4)
|
||||
packet.rrsig.encode(testRRSIG, buf)
|
||||
const val2 = packet.rrsig.decode(buf)
|
||||
t.ok(compare(t, testRRSIG, val2))
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('rrp', function (t) {
|
||||
testEncoder(t, packet.rp, {
|
||||
mbox: 'foo.bar.com',
|
||||
txt: 'baz.bar.com'
|
||||
})
|
||||
testEncoder(t, packet.rp, {
|
||||
mbox: 'foo.bar.com'
|
||||
})
|
||||
testEncoder(t, packet.rp, {
|
||||
txt: 'baz.bar.com'
|
||||
})
|
||||
testEncoder(t, packet.rp, {})
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('nsec', function (t) {
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['A', 'DNSKEY', 'CAA', 'DLV']
|
||||
})
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['TXT'] // 16
|
||||
})
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['TKEY'] // 249
|
||||
})
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['RRSIG', 'NSEC']
|
||||
})
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['TXT', 'RRSIG']
|
||||
})
|
||||
testEncoder(t, packet.nsec, {
|
||||
nextDomain: 'foo.com',
|
||||
rrtypes: ['TXT', 'NSEC']
|
||||
})
|
||||
|
||||
// Test with the sample NSEC from https://tools.ietf.org/html/rfc4034#section-4.3
|
||||
var sampleNSEC = Buffer.from('003704686f7374076578616d706c6503636f6d00' +
|
||||
'0006400100000003041b000000000000000000000000000000000000000000000' +
|
||||
'000000020', 'hex')
|
||||
var decoded = packet.nsec.decode(sampleNSEC)
|
||||
t.ok(compare(t, decoded, {
|
||||
nextDomain: 'host.example.com',
|
||||
rrtypes: ['A', 'MX', 'RRSIG', 'NSEC', 'UNKNOWN_1234']
|
||||
}))
|
||||
var reencoded = packet.nsec.encode(decoded)
|
||||
t.same(sampleNSEC.length, reencoded.length)
|
||||
t.same(sampleNSEC, reencoded)
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('nsec3', function (t) {
|
||||
testEncoder(t, packet.nsec3, {
|
||||
algorithm: 1,
|
||||
flags: 0,
|
||||
iterations: 257,
|
||||
salt: Buffer.from([42, 42, 42]),
|
||||
nextDomain: Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
||||
rrtypes: ['A', 'DNSKEY', 'CAA', 'DLV']
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('ds', function (t) {
|
||||
testEncoder(t, packet.ds, {
|
||||
keyTag: 1234,
|
||||
algorithm: 1,
|
||||
digestType: 1,
|
||||
digest: Buffer.from([0, 1, 2, 3, 4, 5])
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('unpack', function (t) {
|
||||
const buf = Buffer.from([
|
||||
0x00, 0x79,
|
||||
0xde, 0xad, 0x85, 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
0x00, 0x02, 0x00, 0x02, 0x02, 0x6f, 0x6a, 0x05,
|
||||
0x62, 0x61, 0x6e, 0x67, 0x6a, 0x03, 0x63, 0x6f,
|
||||
0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10,
|
||||
0x00, 0x04, 0x81, 0xfa, 0x0b, 0xaa, 0xc0, 0x0f,
|
||||
0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10,
|
||||
0x00, 0x05, 0x02, 0x63, 0x6a, 0xc0, 0x0f, 0xc0,
|
||||
0x0f, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e,
|
||||
0x10, 0x00, 0x02, 0xc0, 0x0c, 0xc0, 0x3a, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00,
|
||||
0x04, 0x45, 0x4d, 0x9b, 0x9c, 0xc0, 0x0c, 0x00,
|
||||
0x1c, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00,
|
||||
0x10, 0x20, 0x01, 0x04, 0x18, 0x00, 0x00, 0x50,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf9
|
||||
])
|
||||
const val = packet.streamDecode(buf)
|
||||
const answer = val.answers[0]
|
||||
const authority = val.authorities[1]
|
||||
t.ok(val.rcode === 'NOERROR', 'decode rcode')
|
||||
t.ok(compare(t, answer.type, 'A'), 'streamDecoded RR type match')
|
||||
t.ok(compare(t, answer.name, 'oj.bangj.com'), 'streamDecoded RR name match')
|
||||
t.ok(compare(t, answer.data, '129.250.11.170'), 'streamDecoded RR rdata match')
|
||||
t.ok(compare(t, authority.type, 'NS'), 'streamDecoded RR type match')
|
||||
t.ok(compare(t, authority.name, 'bangj.com'), 'streamDecoded RR name match')
|
||||
t.ok(compare(t, authority.data, 'oj.bangj.com'), 'streamDecoded RR rdata match')
|
||||
t.end()
|
||||
})
|
||||
|
||||
tape('optioncodes', function (t) {
|
||||
const opts = [
|
||||
[0, 'OPTION_0'],
|
||||
[1, 'LLQ'],
|
||||
[2, 'UL'],
|
||||
[3, 'NSID'],
|
||||
[4, 'OPTION_4'],
|
||||
[5, 'DAU'],
|
||||
[6, 'DHU'],
|
||||
[7, 'N3U'],
|
||||
[8, 'CLIENT_SUBNET'],
|
||||
[9, 'EXPIRE'],
|
||||
[10, 'COOKIE'],
|
||||
[11, 'TCP_KEEPALIVE'],
|
||||
[12, 'PADDING'],
|
||||
[13, 'CHAIN'],
|
||||
[14, 'KEY_TAG'],
|
||||
[26946, 'DEVICEID'],
|
||||
[65535, 'OPTION_65535'],
|
||||
[64000, 'OPTION_64000'],
|
||||
[65002, 'OPTION_65002'],
|
||||
[-1, null]
|
||||
]
|
||||
for (const [code, str] of opts) {
|
||||
const s = optioncodes.toString(code)
|
||||
t.ok(compare(t, s, str), `${code} => ${str}`)
|
||||
t.ok(compare(t, optioncodes.toCode(s), code), `${str} => ${code}`)
|
||||
}
|
||||
t.ok(compare(t, optioncodes.toCode('INVALIDINVALID'), -1))
|
||||
t.end()
|
||||
})
|
||||
|
||||
function testEncoder (t, rpacket, val) {
|
||||
const buf = rpacket.encode(val)
|
||||
const val2 = rpacket.decode(buf)
|
||||
|
||||
t.same(buf.length, rpacket.encode.bytes, 'encode.bytes was set correctly')
|
||||
t.same(buf.length, rpacket.encodingLength(val), 'encoding length matches')
|
||||
t.ok(compare(t, val, val2), 'decoded object match')
|
||||
|
||||
const buf2 = rpacket.encode(val2)
|
||||
const val3 = rpacket.decode(buf2)
|
||||
|
||||
t.same(buf2.length, rpacket.encode.bytes, 'encode.bytes was set correctly on re-encode')
|
||||
t.same(buf2.length, rpacket.encodingLength(val), 'encoding length matches on re-encode')
|
||||
|
||||
t.ok(compare(t, val, val3), 'decoded object match on re-encode')
|
||||
t.ok(compare(t, val2, val3), 're-encoded decoded object match on re-encode')
|
||||
|
||||
const bigger = Buffer.allocUnsafe(buf2.length + 10)
|
||||
|
||||
const buf3 = rpacket.encode(val, bigger, 10)
|
||||
const val4 = rpacket.decode(buf3, 10)
|
||||
|
||||
t.ok(buf3 === bigger, 'echoes buffer on external buffer')
|
||||
t.same(rpacket.encode.bytes, buf.length, 'encode.bytes is the same on external buffer')
|
||||
t.ok(compare(t, val, val4), 'decoded object match on external buffer')
|
||||
}
|
||||
|
||||
function compare (t, a, b) {
|
||||
if (Buffer.isBuffer(a)) return a.toString('hex') === b.toString('hex')
|
||||
if (typeof a === 'object' && a && b) {
|
||||
const keys = Object.keys(a)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (!compare(t, a[keys[i]], b[keys[i]])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(b) && !Array.isArray(a)) {
|
||||
// TXT always decode as array
|
||||
return a.toString() === b[0].toString()
|
||||
} else {
|
||||
return a === b
|
||||
}
|
||||
return true
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
exports.toString = function (type) {
|
||||
switch (type) {
|
||||
case 1: return 'A'
|
||||
case 10: return 'NULL'
|
||||
case 28: return 'AAAA'
|
||||
case 18: return 'AFSDB'
|
||||
case 42: return 'APL'
|
||||
case 257: return 'CAA'
|
||||
case 60: return 'CDNSKEY'
|
||||
case 59: return 'CDS'
|
||||
case 37: return 'CERT'
|
||||
case 5: return 'CNAME'
|
||||
case 49: return 'DHCID'
|
||||
case 32769: return 'DLV'
|
||||
case 39: return 'DNAME'
|
||||
case 48: return 'DNSKEY'
|
||||
case 43: return 'DS'
|
||||
case 55: return 'HIP'
|
||||
case 13: return 'HINFO'
|
||||
case 45: return 'IPSECKEY'
|
||||
case 25: return 'KEY'
|
||||
case 36: return 'KX'
|
||||
case 29: return 'LOC'
|
||||
case 15: return 'MX'
|
||||
case 35: return 'NAPTR'
|
||||
case 2: return 'NS'
|
||||
case 47: return 'NSEC'
|
||||
case 50: return 'NSEC3'
|
||||
case 51: return 'NSEC3PARAM'
|
||||
case 12: return 'PTR'
|
||||
case 46: return 'RRSIG'
|
||||
case 17: return 'RP'
|
||||
case 24: return 'SIG'
|
||||
case 6: return 'SOA'
|
||||
case 99: return 'SPF'
|
||||
case 33: return 'SRV'
|
||||
case 44: return 'SSHFP'
|
||||
case 32768: return 'TA'
|
||||
case 249: return 'TKEY'
|
||||
case 52: return 'TLSA'
|
||||
case 250: return 'TSIG'
|
||||
case 16: return 'TXT'
|
||||
case 252: return 'AXFR'
|
||||
case 251: return 'IXFR'
|
||||
case 41: return 'OPT'
|
||||
case 255: return 'ANY'
|
||||
}
|
||||
return 'UNKNOWN_' + type
|
||||
}
|
||||
|
||||
exports.toType = function (name) {
|
||||
switch (name.toUpperCase()) {
|
||||
case 'A': return 1
|
||||
case 'NULL': return 10
|
||||
case 'AAAA': return 28
|
||||
case 'AFSDB': return 18
|
||||
case 'APL': return 42
|
||||
case 'CAA': return 257
|
||||
case 'CDNSKEY': return 60
|
||||
case 'CDS': return 59
|
||||
case 'CERT': return 37
|
||||
case 'CNAME': return 5
|
||||
case 'DHCID': return 49
|
||||
case 'DLV': return 32769
|
||||
case 'DNAME': return 39
|
||||
case 'DNSKEY': return 48
|
||||
case 'DS': return 43
|
||||
case 'HIP': return 55
|
||||
case 'HINFO': return 13
|
||||
case 'IPSECKEY': return 45
|
||||
case 'KEY': return 25
|
||||
case 'KX': return 36
|
||||
case 'LOC': return 29
|
||||
case 'MX': return 15
|
||||
case 'NAPTR': return 35
|
||||
case 'NS': return 2
|
||||
case 'NSEC': return 47
|
||||
case 'NSEC3': return 50
|
||||
case 'NSEC3PARAM': return 51
|
||||
case 'PTR': return 12
|
||||
case 'RRSIG': return 46
|
||||
case 'RP': return 17
|
||||
case 'SIG': return 24
|
||||
case 'SOA': return 6
|
||||
case 'SPF': return 99
|
||||
case 'SRV': return 33
|
||||
case 'SSHFP': return 44
|
||||
case 'TA': return 32768
|
||||
case 'TKEY': return 249
|
||||
case 'TLSA': return 52
|
||||
case 'TSIG': return 250
|
||||
case 'TXT': return 16
|
||||
case 'AXFR': return 252
|
||||
case 'IXFR': return 251
|
||||
case 'OPT': return 41
|
||||
case 'ANY': return 255
|
||||
case '*': return 255
|
||||
}
|
||||
if (name.toUpperCase().startsWith('UNKNOWN_')) return parseInt(name.slice(8))
|
||||
return 0
|
||||
}
|
@ -13,8 +13,6 @@ var http2 = require(node_http2_root);
|
||||
var fs = require('fs');
|
||||
var url = require('url');
|
||||
var crypto = require('crypto');
|
||||
const dnsPacket = require('../dns-packet');
|
||||
const ip = require('../node-ip');
|
||||
|
||||
// Hook into the decompression code to log the decompressed name-value pairs
|
||||
var compression_module = node_http2_root + "/lib/protocol/compressor";
|
||||
@ -552,97 +550,6 @@ function handleRequest(req, res) {
|
||||
return;
|
||||
|
||||
}
|
||||
else if (u.pathname == "/doh") {
|
||||
ns_confirm = 0; // back to first reply for dns-confirm
|
||||
cname_confirm = 0; // back to first reply for dns-cname
|
||||
|
||||
let params = new url.URL(`http://localhost${req.url}`).searchParams;
|
||||
let responseIP = params.get("responseIP");
|
||||
if (!responseIP) {
|
||||
responseIP = "5.5.5.5";
|
||||
}
|
||||
|
||||
if (params.get("auth")) {
|
||||
// There's a Set-Cookie: header in the response for "/dns" , which this
|
||||
// request subsequently would include if the http channel wasn't
|
||||
// anonymous. Thus, if there's a cookie in this request, we know Firefox
|
||||
// mishaved. If there's not, we're fine.
|
||||
if (req.headers['cookie']) {
|
||||
res.writeHead(403);
|
||||
res.end("cookie for me, not for you");
|
||||
return;
|
||||
}
|
||||
if (req.headers['authorization'] != "user:password") {
|
||||
res.writeHead(401);
|
||||
res.end("bad boy!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.get("push")) {
|
||||
// push.example.com has AAAA entry 2018::2018
|
||||
var pcontent= new Buffer("0000010000010001000000000470757368076578616D706C6503636F6D00001C0001C00C001C000100000037001020180000000000000000000000002018", "hex");
|
||||
push = res.push({
|
||||
hostname: 'foo.example.com:' + serverPort,
|
||||
port: serverPort,
|
||||
path: '/dns-pushed-response?dns=AAAAAAABAAAAAAAABHB1c2gHZXhhbXBsZQNjb20AABwAAQ',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept' : 'application/dns-message'
|
||||
}
|
||||
});
|
||||
push.writeHead(200, {
|
||||
'content-type': 'application/dns-message',
|
||||
'pushed' : 'yes',
|
||||
'content-length' : pcontent.length,
|
||||
'X-Connection-Http2': 'yes'
|
||||
});
|
||||
push.end(pcontent);
|
||||
}
|
||||
|
||||
let payload = new Buffer("");
|
||||
|
||||
function emitResponse(response, requestPayload) {
|
||||
let packet = dnsPacket.decode(requestPayload);
|
||||
|
||||
let buf = dnsPacket.encode({
|
||||
type: 'query',
|
||||
id: packet.id,
|
||||
flags: dnsPacket.RECURSION_DESIRED,
|
||||
questions: packet.questions,
|
||||
answers: [{
|
||||
name: packet.questions[0].name,
|
||||
ttl: 55,
|
||||
type: ip.isV4Format(responseIP) ? "A" : "AAAA",
|
||||
flush: false,
|
||||
data: responseIP,
|
||||
}],
|
||||
});
|
||||
|
||||
response.setHeader('Content-Length', buf.length);
|
||||
response.setHeader('Set-Cookie', 'trackyou=yes; path=/; max-age=100000;');
|
||||
response.setHeader('Content-Type', 'application/dns-message');
|
||||
response.writeHead(200);
|
||||
response.write(buf);
|
||||
response.end("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.get("dns")) {
|
||||
payload = Buffer.from(params.get("dns"), 'base64');
|
||||
emitResponse(res, payload);
|
||||
return;
|
||||
}
|
||||
|
||||
req.on('data', function receiveData(chunk) {
|
||||
payload = Buffer.concat([payload, chunk]);
|
||||
});
|
||||
req.on('end', function finishedData() {
|
||||
emitResponse(res, payload);
|
||||
return;
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-cname-a") {
|
||||
// test23 asks for cname-a.example.com
|
||||
// this responds with a CNAME to here.example.com *and* an A record
|
||||
@ -696,6 +603,57 @@ function handleRequest(req, res) {
|
||||
res.end("");
|
||||
return;
|
||||
|
||||
}
|
||||
// for use with test_trr.js, test8b
|
||||
else if (u.path === "/dns-ecs?dns=AAABAAABAAAAAAABA2VjcwdleGFtcGxlA2NvbQAAAQABAAApEAAAAAAAAAgACAAEAAEAAA") {
|
||||
// the query string asks for an A entry for ecs.example.com
|
||||
// ecs.example.com has A entry 5.5.5.5
|
||||
var content= new Buffer("00000100000100010000000003656373076578616D706C6503636F6D0000010001C00C0001000100000037000405050505", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.path === "/dns-get?dns=AAABAAABAAAAAAAAA2dldAdleGFtcGxlA2NvbQAAAQAB") {
|
||||
// the query string asks for an A entry for get.example.com
|
||||
// get.example.com has A entry 1.2.3.4
|
||||
var content= new Buffer("00000100000100010000000003676574076578616D706C6503636F6D0000010001C00C0001000100000037000401020304", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
ns_confirm = 0; // back to first reply for dns-confirm
|
||||
cname_confirm = 0; // back to first reply for dns-cname
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns") {
|
||||
// bar.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("00000100000100010000000003626172076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
// pass back a cookie here, check it in /dns-auth
|
||||
res.setHeader('Set-Cookie', 'trackyou=yes; path=/; max-age=100000;');
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-ip") {
|
||||
// bar.example.com has A entry 192.192.192.192
|
||||
var content= new Buffer("00000100000100010000000003626172076578616D706C6503636F6D0000010001C00C00010001000000370004C0C0C0C0", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
// pass back a cookie here, check it in /dns-auth
|
||||
res.setHeader('Set-Cookie', 'trackyou=yes; path=/; max-age=100000;');
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-ns") {
|
||||
// confirm.example.com has NS entry ns.example.com
|
||||
@ -736,6 +694,82 @@ function handleRequest(req, res) {
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-aaaa") {
|
||||
// aaaa.example.com has AAAA entry 2020:2020::2020
|
||||
var content= new Buffer("0000010000010001000000000461616161076578616D706C6503636F6D00001C0001C00C001C000100000037001020202020000000000000000000002020", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-rfc1918") {
|
||||
// rfc1918.example.com has A entry 192.168.0.1
|
||||
var content= new Buffer("0000010000010001000000000772666331393138076578616D706C6503636F6D0000010001C00C00010001000000370004C0A80001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-push") {
|
||||
// first.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("000001000001000100000000056669727374076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
// push.example.com has AAAA entry 2018::2018
|
||||
var pcontent= new Buffer("0000010000010001000000000470757368076578616D706C6503636F6D00001C0001C00C001C000100000037001020180000000000000000000000002018", "hex");
|
||||
push = res.push({
|
||||
hostname: 'foo.example.com:' + serverPort,
|
||||
port: serverPort,
|
||||
path: '/dns-pushed-response?dns=AAAAAAABAAAAAAAABHB1c2gHZXhhbXBsZQNjb20AABwAAQ',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept' : 'application/dns-message'
|
||||
}
|
||||
});
|
||||
push.writeHead(200, {
|
||||
'content-type': 'application/dns-message',
|
||||
'pushed' : 'yes',
|
||||
'content-length' : pcontent.length,
|
||||
'X-Connection-Http2': 'yes'
|
||||
});
|
||||
push.end(pcontent);
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-auth") {
|
||||
// There's a Set-Cookie: header in the response for "/dns" , which this
|
||||
// request subsequently would include if the http channel wasn't
|
||||
// anonymous. Thus, if there's a cookie in this request, we know Firefox
|
||||
// mishaved. If there's not, we're fine.
|
||||
if (req.headers['cookie']) {
|
||||
res.writeHead(403);
|
||||
res.end("cookie for me, not for you");
|
||||
return;
|
||||
}
|
||||
if (req.headers['authorization'] != "user:password") {
|
||||
res.writeHead(401);
|
||||
res.end("bad boy!");
|
||||
return;
|
||||
}
|
||||
// bar.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("00000100000100010000000003626172076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-message');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
|
||||
// for use with test_esni_dns_fetch.js
|
||||
else if (u.pathname === "/esni-dns") {
|
||||
content = new Buffer("0000" +
|
||||
|
2
testing/xpcshell/node-ip/.gitignore
vendored
2
testing/xpcshell/node-ip/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
node_modules/
|
||||
npm-debug.log
|
@ -1,46 +0,0 @@
|
||||
{
|
||||
"disallowKeywordsOnNewLine": [ "else" ],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowMultipleVarDecl": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowQuotedKeysInObjects": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
||||
"disallowSpaceBeforePostfixUnaryOperators": true,
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"disallowYodaConditions": true,
|
||||
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireOperatorBeforeLineBreak": true,
|
||||
"requireSpaceAfterBinaryOperators": true,
|
||||
"requireSpaceAfterKeywords": [ "if", "for", "while", "else", "try", "catch" ],
|
||||
"requireSpaceAfterLineComment": true,
|
||||
"requireSpaceBeforeBinaryOperators": true,
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpaceBeforeKeywords": [ "else", "catch" ],
|
||||
"requireSpaceBeforeObjectValues": true,
|
||||
"requireSpaceBetweenArguments": true,
|
||||
"requireSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"requireSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"requireSpacesInFunctionExpression": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"requireSpacesInConditionalExpression": true,
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireSpacesInsideArrayBrackets": "all",
|
||||
"requireSpacesInsideObjectBrackets": "all",
|
||||
"requireDotNotation": true,
|
||||
|
||||
"maximumLineLength": 80,
|
||||
"validateIndentation": 2,
|
||||
"validateLineBreaks": "LF",
|
||||
"validateParameterSeparator": ", ",
|
||||
"validateQuoteMarks": "'"
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
{
|
||||
// JSHint Default Configuration File (as on JSHint website)
|
||||
// See http://jshint.com/docs/ for more details
|
||||
|
||||
"maxerr" : 50, // {int} Maximum error before stopping
|
||||
|
||||
// Enforcing
|
||||
"bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.)
|
||||
"camelcase" : false, // true: Identifiers must be in camelCase
|
||||
"curly" : false, // true: Require {} for every new block or scope
|
||||
"eqeqeq" : true, // true: Require triple equals (===) for comparison
|
||||
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
|
||||
"freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
|
||||
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
|
||||
"indent" : 2, // {int} Number of spaces to use for indentation
|
||||
"latedef" : true, // true: Require variables/functions to be defined before being used
|
||||
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
|
||||
"noempty" : false, // true: Prohibit use of empty blocks
|
||||
"nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
|
||||
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
|
||||
"plusplus" : false, // true: Prohibit use of `++` & `--`
|
||||
"quotmark" : "single", // Quotation mark consistency:
|
||||
// false : do nothing (default)
|
||||
// true : ensure whatever is used is consistent
|
||||
// "single" : require single quotes
|
||||
// "double" : require double quotes
|
||||
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
|
||||
"unused" : true, // true: Require all defined variables be used
|
||||
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
|
||||
"maxparams" : false, // {int} Max number of formal params allowed per function
|
||||
"maxdepth" : 3, // {int} Max depth of nested blocks (within functions)
|
||||
"maxstatements" : false, // {int} Max number statements per function
|
||||
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
|
||||
"maxlen" : false, // {int} Max number of characters per line
|
||||
|
||||
// Relaxing
|
||||
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
|
||||
"boss" : false, // true: Tolerate assignments where comparisons would be expected
|
||||
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
|
||||
"eqnull" : false, // true: Tolerate use of `== null`
|
||||
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
|
||||
"esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
|
||||
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
|
||||
// (ex: `for each`, multiple try/catch, function expression…)
|
||||
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
|
||||
"expr" : false, // true: Tolerate `ExpressionStatement` as Programs
|
||||
"funcscope" : false, // true: Tolerate defining variables inside control statements
|
||||
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
|
||||
"iterator" : false, // true: Tolerate using the `__iterator__` property
|
||||
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
|
||||
"laxbreak" : false, // true: Tolerate possibly unsafe line breakings
|
||||
"laxcomma" : false, // true: Tolerate comma-first style coding
|
||||
"loopfunc" : false, // true: Tolerate functions being defined in loops
|
||||
"multistr" : false, // true: Tolerate multi-line strings
|
||||
"noyield" : false, // true: Tolerate generator functions with no yield statement in them.
|
||||
"notypeof" : false, // true: Tolerate invalid typeof operator values
|
||||
"proto" : false, // true: Tolerate using the `__proto__` property
|
||||
"scripturl" : false, // true: Tolerate script-targeted URLs
|
||||
"shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
|
||||
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
|
||||
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
|
||||
"validthis" : false, // true: Tolerate using this in a non-constructor function
|
||||
|
||||
// Environments
|
||||
"browser" : true, // Web Browser (window, document, etc)
|
||||
"browserify" : true, // Browserify (node.js code in the browser)
|
||||
"couch" : false, // CouchDB
|
||||
"devel" : true, // Development/debugging (alert, confirm, etc)
|
||||
"dojo" : false, // Dojo Toolkit
|
||||
"jasmine" : false, // Jasmine
|
||||
"jquery" : false, // jQuery
|
||||
"mocha" : true, // Mocha
|
||||
"mootools" : false, // MooTools
|
||||
"node" : true, // Node.js
|
||||
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
|
||||
"prototypejs" : false, // Prototype and Scriptaculous
|
||||
"qunit" : false, // QUnit
|
||||
"rhino" : false, // Rhino
|
||||
"shelljs" : false, // ShellJS
|
||||
"worker" : false, // Web Workers
|
||||
"wsh" : false, // Windows Scripting Host
|
||||
"yui" : false, // Yahoo User Interface
|
||||
|
||||
// Custom Globals
|
||||
"globals" : {
|
||||
"module": true
|
||||
} // additional predefined global variables
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "4"
|
||||
- "6"
|
||||
|
||||
before_install:
|
||||
- travis_retry npm install -g npm@2.14.5
|
||||
- travis_retry npm install
|
||||
|
||||
script:
|
||||
- npm test
|
@ -1,90 +0,0 @@
|
||||
# IP
|
||||
[![](https://badge.fury.io/js/ip.svg)](https://www.npmjs.com/package/ip)
|
||||
|
||||
IP address utilities for node.js
|
||||
|
||||
## Installation
|
||||
|
||||
### npm
|
||||
```shell
|
||||
npm install ip
|
||||
```
|
||||
|
||||
### git
|
||||
|
||||
```shell
|
||||
git clone https://github.com/indutny/node-ip.git
|
||||
```
|
||||
|
||||
## Usage
|
||||
Get your ip address, compare ip addresses, validate ip addresses, etc.
|
||||
|
||||
```js
|
||||
var ip = require('ip');
|
||||
|
||||
ip.address() // my ip address
|
||||
ip.isEqual('::1', '::0:1'); // true
|
||||
ip.toBuffer('127.0.0.1') // Buffer([127, 0, 0, 1])
|
||||
ip.toString(new Buffer([127, 0, 0, 1])) // 127.0.0.1
|
||||
ip.fromPrefixLen(24) // 255.255.255.0
|
||||
ip.mask('192.168.1.134', '255.255.255.0') // 192.168.1.0
|
||||
ip.cidr('192.168.1.134/26') // 192.168.1.128
|
||||
ip.not('255.255.255.0') // 0.0.0.255
|
||||
ip.or('192.168.1.134', '0.0.0.255') // 192.168.1.255
|
||||
ip.isPrivate('127.0.0.1') // true
|
||||
ip.isV4Format('127.0.0.1'); // true
|
||||
ip.isV6Format('::ffff:127.0.0.1'); // true
|
||||
|
||||
// operate on buffers in-place
|
||||
var buf = new Buffer(128);
|
||||
var offset = 64;
|
||||
ip.toBuffer('127.0.0.1', buf, offset); // [127, 0, 0, 1] at offset 64
|
||||
ip.toString(buf, offset, 4); // '127.0.0.1'
|
||||
|
||||
// subnet information
|
||||
ip.subnet('192.168.1.134', '255.255.255.192')
|
||||
// { networkAddress: '192.168.1.128',
|
||||
// firstAddress: '192.168.1.129',
|
||||
// lastAddress: '192.168.1.190',
|
||||
// broadcastAddress: '192.168.1.191',
|
||||
// subnetMask: '255.255.255.192',
|
||||
// subnetMaskLength: 26,
|
||||
// numHosts: 62,
|
||||
// length: 64,
|
||||
// contains: function(addr){...} }
|
||||
ip.cidrSubnet('192.168.1.134/26')
|
||||
// Same as previous.
|
||||
|
||||
// range checking
|
||||
ip.cidrSubnet('192.168.1.134/26').contains('192.168.1.190') // true
|
||||
|
||||
|
||||
// ipv4 long conversion
|
||||
ip.toLong('127.0.0.1'); // 2130706433
|
||||
ip.fromLong(2130706433); // '127.0.0.1'
|
||||
```
|
||||
|
||||
### License
|
||||
|
||||
This software is licensed under the MIT License.
|
||||
|
||||
Copyright Fedor Indutny, 2012.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,416 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var ip = exports;
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var os = require('os');
|
||||
|
||||
ip.toBuffer = function(ip, buff, offset) {
|
||||
offset = ~~offset;
|
||||
|
||||
var result;
|
||||
|
||||
if (this.isV4Format(ip)) {
|
||||
result = buff || new Buffer(offset + 4);
|
||||
ip.split(/\./g).map(function(byte) {
|
||||
result[offset++] = parseInt(byte, 10) & 0xff;
|
||||
});
|
||||
} else if (this.isV6Format(ip)) {
|
||||
var sections = ip.split(':', 8);
|
||||
|
||||
var i;
|
||||
for (i = 0; i < sections.length; i++) {
|
||||
var isv4 = this.isV4Format(sections[i]);
|
||||
var v4Buffer;
|
||||
|
||||
if (isv4) {
|
||||
v4Buffer = this.toBuffer(sections[i]);
|
||||
sections[i] = v4Buffer.slice(0, 2).toString('hex');
|
||||
}
|
||||
|
||||
if (v4Buffer && ++i < 8) {
|
||||
sections.splice(i, 0, v4Buffer.slice(2, 4).toString('hex'));
|
||||
}
|
||||
}
|
||||
|
||||
if (sections[0] === '') {
|
||||
while (sections.length < 8) sections.unshift('0');
|
||||
} else if (sections[sections.length - 1] === '') {
|
||||
while (sections.length < 8) sections.push('0');
|
||||
} else if (sections.length < 8) {
|
||||
for (i = 0; i < sections.length && sections[i] !== ''; i++);
|
||||
var argv = [ i, 1 ];
|
||||
for (i = 9 - sections.length; i > 0; i--) {
|
||||
argv.push('0');
|
||||
}
|
||||
sections.splice.apply(sections, argv);
|
||||
}
|
||||
|
||||
result = buff || new Buffer(offset + 16);
|
||||
for (i = 0; i < sections.length; i++) {
|
||||
var word = parseInt(sections[i], 16);
|
||||
result[offset++] = (word >> 8) & 0xff;
|
||||
result[offset++] = word & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
throw Error('Invalid ip address: ' + ip);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ip.toString = function(buff, offset, length) {
|
||||
offset = ~~offset;
|
||||
length = length || (buff.length - offset);
|
||||
|
||||
var result = [];
|
||||
if (length === 4) {
|
||||
// IPv4
|
||||
for (var i = 0; i < length; i++) {
|
||||
result.push(buff[offset + i]);
|
||||
}
|
||||
result = result.join('.');
|
||||
} else if (length === 16) {
|
||||
// IPv6
|
||||
for (var i = 0; i < length; i += 2) {
|
||||
result.push(buff.readUInt16BE(offset + i).toString(16));
|
||||
}
|
||||
result = result.join(':');
|
||||
result = result.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');
|
||||
result = result.replace(/:{3,4}/, '::');
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/;
|
||||
var ipv6Regex =
|
||||
/^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;
|
||||
|
||||
ip.isV4Format = function(ip) {
|
||||
return ipv4Regex.test(ip);
|
||||
};
|
||||
|
||||
ip.isV6Format = function(ip) {
|
||||
return ipv6Regex.test(ip);
|
||||
};
|
||||
function _normalizeFamily(family) {
|
||||
return family ? family.toLowerCase() : 'ipv4';
|
||||
}
|
||||
|
||||
ip.fromPrefixLen = function(prefixlen, family) {
|
||||
if (prefixlen > 32) {
|
||||
family = 'ipv6';
|
||||
} else {
|
||||
family = _normalizeFamily(family);
|
||||
}
|
||||
|
||||
var len = 4;
|
||||
if (family === 'ipv6') {
|
||||
len = 16;
|
||||
}
|
||||
var buff = new Buffer(len);
|
||||
|
||||
for (var i = 0, n = buff.length; i < n; ++i) {
|
||||
var bits = 8;
|
||||
if (prefixlen < 8) {
|
||||
bits = prefixlen;
|
||||
}
|
||||
prefixlen -= bits;
|
||||
|
||||
buff[i] = ~(0xff >> bits) & 0xff;
|
||||
}
|
||||
|
||||
return ip.toString(buff);
|
||||
};
|
||||
|
||||
ip.mask = function(addr, mask) {
|
||||
addr = ip.toBuffer(addr);
|
||||
mask = ip.toBuffer(mask);
|
||||
|
||||
var result = new Buffer(Math.max(addr.length, mask.length));
|
||||
|
||||
var i = 0;
|
||||
// Same protocol - do bitwise and
|
||||
if (addr.length === mask.length) {
|
||||
for (i = 0; i < addr.length; i++) {
|
||||
result[i] = addr[i] & mask[i];
|
||||
}
|
||||
} else if (mask.length === 4) {
|
||||
// IPv6 address and IPv4 mask
|
||||
// (Mask low bits)
|
||||
for (i = 0; i < mask.length; i++) {
|
||||
result[i] = addr[addr.length - 4 + i] & mask[i];
|
||||
}
|
||||
} else {
|
||||
// IPv6 mask and IPv4 addr
|
||||
for (var i = 0; i < result.length - 6; i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
|
||||
// ::ffff:ipv4
|
||||
result[10] = 0xff;
|
||||
result[11] = 0xff;
|
||||
for (i = 0; i < addr.length; i++) {
|
||||
result[i + 12] = addr[i] & mask[i + 12];
|
||||
}
|
||||
i = i + 12;
|
||||
}
|
||||
for (; i < result.length; i++)
|
||||
result[i] = 0;
|
||||
|
||||
return ip.toString(result);
|
||||
};
|
||||
|
||||
ip.cidr = function(cidrString) {
|
||||
var cidrParts = cidrString.split('/');
|
||||
|
||||
var addr = cidrParts[0];
|
||||
if (cidrParts.length !== 2)
|
||||
throw new Error('invalid CIDR subnet: ' + addr);
|
||||
|
||||
var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
|
||||
|
||||
return ip.mask(addr, mask);
|
||||
};
|
||||
|
||||
ip.subnet = function(addr, mask) {
|
||||
var networkAddress = ip.toLong(ip.mask(addr, mask));
|
||||
|
||||
// Calculate the mask's length.
|
||||
var maskBuffer = ip.toBuffer(mask);
|
||||
var maskLength = 0;
|
||||
|
||||
for (var i = 0; i < maskBuffer.length; i++) {
|
||||
if (maskBuffer[i] === 0xff) {
|
||||
maskLength += 8;
|
||||
} else {
|
||||
var octet = maskBuffer[i] & 0xff;
|
||||
while (octet) {
|
||||
octet = (octet << 1) & 0xff;
|
||||
maskLength++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var numberOfAddresses = Math.pow(2, 32 - maskLength);
|
||||
|
||||
return {
|
||||
networkAddress: ip.fromLong(networkAddress),
|
||||
firstAddress: numberOfAddresses <= 2 ?
|
||||
ip.fromLong(networkAddress) :
|
||||
ip.fromLong(networkAddress + 1),
|
||||
lastAddress: numberOfAddresses <= 2 ?
|
||||
ip.fromLong(networkAddress + numberOfAddresses - 1) :
|
||||
ip.fromLong(networkAddress + numberOfAddresses - 2),
|
||||
broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1),
|
||||
subnetMask: mask,
|
||||
subnetMaskLength: maskLength,
|
||||
numHosts: numberOfAddresses <= 2 ?
|
||||
numberOfAddresses : numberOfAddresses - 2,
|
||||
length: numberOfAddresses,
|
||||
contains: function(other) {
|
||||
return networkAddress === ip.toLong(ip.mask(other, mask));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ip.cidrSubnet = function(cidrString) {
|
||||
var cidrParts = cidrString.split('/');
|
||||
|
||||
var addr = cidrParts[0];
|
||||
if (cidrParts.length !== 2)
|
||||
throw new Error('invalid CIDR subnet: ' + addr);
|
||||
|
||||
var mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));
|
||||
|
||||
return ip.subnet(addr, mask);
|
||||
};
|
||||
|
||||
ip.not = function(addr) {
|
||||
var buff = ip.toBuffer(addr);
|
||||
for (var i = 0; i < buff.length; i++) {
|
||||
buff[i] = 0xff ^ buff[i];
|
||||
}
|
||||
return ip.toString(buff);
|
||||
};
|
||||
|
||||
ip.or = function(a, b) {
|
||||
a = ip.toBuffer(a);
|
||||
b = ip.toBuffer(b);
|
||||
|
||||
// same protocol
|
||||
if (a.length === b.length) {
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
a[i] |= b[i];
|
||||
}
|
||||
return ip.toString(a);
|
||||
|
||||
// mixed protocols
|
||||
} else {
|
||||
var buff = a;
|
||||
var other = b;
|
||||
if (b.length > a.length) {
|
||||
buff = b;
|
||||
other = a;
|
||||
}
|
||||
|
||||
var offset = buff.length - other.length;
|
||||
for (var i = offset; i < buff.length; ++i) {
|
||||
buff[i] |= other[i - offset];
|
||||
}
|
||||
|
||||
return ip.toString(buff);
|
||||
}
|
||||
};
|
||||
|
||||
ip.isEqual = function(a, b) {
|
||||
a = ip.toBuffer(a);
|
||||
b = ip.toBuffer(b);
|
||||
|
||||
// Same protocol
|
||||
if (a.length === b.length) {
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Swap
|
||||
if (b.length === 4) {
|
||||
var t = b;
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
|
||||
// a - IPv4, b - IPv6
|
||||
for (var i = 0; i < 10; i++) {
|
||||
if (b[i] !== 0) return false;
|
||||
}
|
||||
|
||||
var word = b.readUInt16BE(10);
|
||||
if (word !== 0 && word !== 0xffff) return false;
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if (a[i] !== b[i + 12]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
ip.isPrivate = function(addr) {
|
||||
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i
|
||||
.test(addr) ||
|
||||
/^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
|
||||
/^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i
|
||||
.test(addr) ||
|
||||
/^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
|
||||
/^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
|
||||
/^f[cd][0-9a-f]{2}:/i.test(addr) ||
|
||||
/^fe80:/i.test(addr) ||
|
||||
/^::1$/.test(addr) ||
|
||||
/^::$/.test(addr);
|
||||
};
|
||||
|
||||
ip.isPublic = function(addr) {
|
||||
return !ip.isPrivate(addr);
|
||||
};
|
||||
|
||||
ip.isLoopback = function(addr) {
|
||||
return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/
|
||||
.test(addr) ||
|
||||
/^fe80::1$/.test(addr) ||
|
||||
/^::1$/.test(addr) ||
|
||||
/^::$/.test(addr);
|
||||
};
|
||||
|
||||
ip.loopback = function(family) {
|
||||
//
|
||||
// Default to `ipv4`
|
||||
//
|
||||
family = _normalizeFamily(family);
|
||||
|
||||
if (family !== 'ipv4' && family !== 'ipv6') {
|
||||
throw new Error('family must be ipv4 or ipv6');
|
||||
}
|
||||
|
||||
return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';
|
||||
};
|
||||
|
||||
//
|
||||
// ### function address (name, family)
|
||||
// #### @name {string|'public'|'private'} **Optional** Name or security
|
||||
// of the network interface.
|
||||
// #### @family {ipv4|ipv6} **Optional** IP family of the address (defaults
|
||||
// to ipv4).
|
||||
//
|
||||
// Returns the address for the network interface on the current system with
|
||||
// the specified `name`:
|
||||
// * String: First `family` address of the interface.
|
||||
// If not found see `undefined`.
|
||||
// * 'public': the first public ip address of family.
|
||||
// * 'private': the first private ip address of family.
|
||||
// * undefined: First address with `ipv4` or loopback address `127.0.0.1`.
|
||||
//
|
||||
ip.address = function(name, family) {
|
||||
var interfaces = os.networkInterfaces();
|
||||
var all;
|
||||
|
||||
//
|
||||
// Default to `ipv4`
|
||||
//
|
||||
family = _normalizeFamily(family);
|
||||
|
||||
//
|
||||
// If a specific network interface has been named,
|
||||
// return the address.
|
||||
//
|
||||
if (name && name !== 'private' && name !== 'public') {
|
||||
var res = interfaces[name].filter(function(details) {
|
||||
var itemFamily = details.family.toLowerCase();
|
||||
return itemFamily === family;
|
||||
});
|
||||
if (res.length === 0)
|
||||
return undefined;
|
||||
return res[0].address;
|
||||
}
|
||||
|
||||
var all = Object.keys(interfaces).map(function (nic) {
|
||||
//
|
||||
// Note: name will only be `public` or `private`
|
||||
// when this is called.
|
||||
//
|
||||
var addresses = interfaces[nic].filter(function (details) {
|
||||
details.family = details.family.toLowerCase();
|
||||
if (details.family !== family || ip.isLoopback(details.address)) {
|
||||
return false;
|
||||
} else if (!name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return name === 'public' ? ip.isPrivate(details.address) :
|
||||
ip.isPublic(details.address);
|
||||
});
|
||||
|
||||
return addresses.length ? addresses[0].address : undefined;
|
||||
}).filter(Boolean);
|
||||
|
||||
return !all.length ? ip.loopback(family) : all[0];
|
||||
};
|
||||
|
||||
ip.toLong = function(ip) {
|
||||
var ipl = 0;
|
||||
ip.split('.').forEach(function(octet) {
|
||||
ipl <<= 8;
|
||||
ipl += parseInt(octet);
|
||||
});
|
||||
return(ipl >>> 0);
|
||||
};
|
||||
|
||||
ip.fromLong = function(ipl) {
|
||||
return ((ipl >>> 24) + '.' +
|
||||
(ipl >> 16 & 255) + '.' +
|
||||
(ipl >> 8 & 255) + '.' +
|
||||
(ipl & 255) );
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "ip",
|
||||
"version": "1.1.5",
|
||||
"author": "Fedor Indutny <fedor@indutny.com>",
|
||||
"homepage": "https://github.com/indutny/node-ip",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/indutny/node-ip.git"
|
||||
},
|
||||
"main": "lib/ip",
|
||||
"devDependencies": {
|
||||
"jscs": "^2.1.1",
|
||||
"jshint": "^2.8.0",
|
||||
"mocha": "~1.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jscs lib/*.js test/*.js && jshint lib/*.js && mocha --reporter spec test/*-test.js",
|
||||
"fix": "jscs lib/*.js test/*.js --fix"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
@ -1,407 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var ip = require('..');
|
||||
var assert = require('assert');
|
||||
var net = require('net');
|
||||
var os = require('os');
|
||||
|
||||
describe('IP library for node.js', function() {
|
||||
describe('toBuffer()/toString() methods', function() {
|
||||
it('should convert to buffer IPv4 address', function() {
|
||||
var buf = ip.toBuffer('127.0.0.1');
|
||||
assert.equal(buf.toString('hex'), '7f000001');
|
||||
assert.equal(ip.toString(buf), '127.0.0.1');
|
||||
});
|
||||
|
||||
it('should convert to buffer IPv4 address in-place', function() {
|
||||
var buf = new Buffer(128);
|
||||
var offset = 64;
|
||||
ip.toBuffer('127.0.0.1', buf, offset);
|
||||
assert.equal(buf.toString('hex', offset, offset + 4), '7f000001');
|
||||
assert.equal(ip.toString(buf, offset, 4), '127.0.0.1');
|
||||
});
|
||||
|
||||
it('should convert to buffer IPv6 address', function() {
|
||||
var buf = ip.toBuffer('::1');
|
||||
assert(/(00){15,15}01/.test(buf.toString('hex')));
|
||||
assert.equal(ip.toString(buf), '::1');
|
||||
assert.equal(ip.toString(ip.toBuffer('1::')), '1::');
|
||||
assert.equal(ip.toString(ip.toBuffer('abcd::dcba')), 'abcd::dcba');
|
||||
});
|
||||
|
||||
it('should convert to buffer IPv6 address in-place', function() {
|
||||
var buf = new Buffer(128);
|
||||
var offset = 64;
|
||||
ip.toBuffer('::1', buf, offset);
|
||||
assert(/(00){15,15}01/.test(buf.toString('hex', offset, offset + 16)));
|
||||
assert.equal(ip.toString(buf, offset, 16), '::1');
|
||||
assert.equal(ip.toString(ip.toBuffer('1::', buf, offset),
|
||||
offset, 16), '1::');
|
||||
assert.equal(ip.toString(ip.toBuffer('abcd::dcba', buf, offset),
|
||||
offset, 16), 'abcd::dcba');
|
||||
});
|
||||
|
||||
it('should convert to buffer IPv6 mapped IPv4 address', function() {
|
||||
var buf = ip.toBuffer('::ffff:127.0.0.1');
|
||||
assert.equal(buf.toString('hex'), '00000000000000000000ffff7f000001');
|
||||
assert.equal(ip.toString(buf), '::ffff:7f00:1');
|
||||
|
||||
buf = ip.toBuffer('ffff::127.0.0.1');
|
||||
assert.equal(buf.toString('hex'), 'ffff000000000000000000007f000001');
|
||||
assert.equal(ip.toString(buf), 'ffff::7f00:1');
|
||||
|
||||
buf = ip.toBuffer('0:0:0:0:0:ffff:127.0.0.1');
|
||||
assert.equal(buf.toString('hex'), '00000000000000000000ffff7f000001');
|
||||
assert.equal(ip.toString(buf), '::ffff:7f00:1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromPrefixLen() method', function() {
|
||||
it('should create IPv4 mask', function() {
|
||||
assert.equal(ip.fromPrefixLen(24), '255.255.255.0');
|
||||
});
|
||||
it('should create IPv6 mask', function() {
|
||||
assert.equal(ip.fromPrefixLen(64), 'ffff:ffff:ffff:ffff::');
|
||||
});
|
||||
it('should create IPv6 mask explicitly', function() {
|
||||
assert.equal(ip.fromPrefixLen(24, 'IPV6'), 'ffff:ff00::');
|
||||
});
|
||||
});
|
||||
|
||||
describe('not() method', function() {
|
||||
it('should reverse bits in address', function() {
|
||||
assert.equal(ip.not('255.255.255.0'), '0.0.0.255');
|
||||
});
|
||||
});
|
||||
|
||||
describe('or() method', function() {
|
||||
it('should or bits in ipv4 addresses', function() {
|
||||
assert.equal(ip.or('0.0.0.255', '192.168.1.10'), '192.168.1.255');
|
||||
});
|
||||
it('should or bits in ipv6 addresses', function() {
|
||||
assert.equal(ip.or('::ff', '::abcd:dcba:abcd:dcba'),
|
||||
'::abcd:dcba:abcd:dcff');
|
||||
});
|
||||
it('should or bits in mixed addresses', function() {
|
||||
assert.equal(ip.or('0.0.0.255', '::abcd:dcba:abcd:dcba'),
|
||||
'::abcd:dcba:abcd:dcff');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mask() method', function() {
|
||||
it('should mask bits in address', function() {
|
||||
assert.equal(ip.mask('192.168.1.134', '255.255.255.0'), '192.168.1.0');
|
||||
assert.equal(ip.mask('192.168.1.134', '::ffff:ff00'), '::ffff:c0a8:100');
|
||||
});
|
||||
|
||||
it('should not leak data', function() {
|
||||
for (var i = 0; i < 10; i++)
|
||||
assert.equal(ip.mask('::1', '0.0.0.0'), '::');
|
||||
});
|
||||
});
|
||||
|
||||
describe('subnet() method', function() {
|
||||
// Test cases calculated with http://www.subnet-calculator.com/
|
||||
var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.192');
|
||||
|
||||
it('should compute ipv4 network address', function() {
|
||||
assert.equal(ipv4Subnet.networkAddress, '192.168.1.128');
|
||||
});
|
||||
|
||||
it('should compute ipv4 network\'s first address', function() {
|
||||
assert.equal(ipv4Subnet.firstAddress, '192.168.1.129');
|
||||
});
|
||||
|
||||
it('should compute ipv4 network\'s last address', function() {
|
||||
assert.equal(ipv4Subnet.lastAddress, '192.168.1.190');
|
||||
});
|
||||
|
||||
it('should compute ipv4 broadcast address', function() {
|
||||
assert.equal(ipv4Subnet.broadcastAddress, '192.168.1.191');
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet number of addresses', function() {
|
||||
assert.equal(ipv4Subnet.length, 64);
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet number of addressable hosts', function() {
|
||||
assert.equal(ipv4Subnet.numHosts, 62);
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet mask', function() {
|
||||
assert.equal(ipv4Subnet.subnetMask, '255.255.255.192');
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet mask\'s length', function() {
|
||||
assert.equal(ipv4Subnet.subnetMaskLength, 26);
|
||||
});
|
||||
|
||||
it('should know whether a subnet contains an address', function() {
|
||||
assert.equal(ipv4Subnet.contains('192.168.1.180'), true);
|
||||
});
|
||||
|
||||
it('should know whether a subnet does not contain an address', function() {
|
||||
assert.equal(ipv4Subnet.contains('192.168.1.195'), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('subnet() method with mask length 32', function() {
|
||||
// Test cases calculated with http://www.subnet-calculator.com/
|
||||
var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.255');
|
||||
it('should compute ipv4 network\'s first address', function() {
|
||||
assert.equal(ipv4Subnet.firstAddress, '192.168.1.134');
|
||||
});
|
||||
|
||||
it('should compute ipv4 network\'s last address', function() {
|
||||
assert.equal(ipv4Subnet.lastAddress, '192.168.1.134');
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet number of addressable hosts', function() {
|
||||
assert.equal(ipv4Subnet.numHosts, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('subnet() method with mask length 31', function() {
|
||||
// Test cases calculated with http://www.subnet-calculator.com/
|
||||
var ipv4Subnet = ip.subnet('192.168.1.134', '255.255.255.254');
|
||||
it('should compute ipv4 network\'s first address', function() {
|
||||
assert.equal(ipv4Subnet.firstAddress, '192.168.1.134');
|
||||
});
|
||||
|
||||
it('should compute ipv4 network\'s last address', function() {
|
||||
assert.equal(ipv4Subnet.lastAddress, '192.168.1.135');
|
||||
});
|
||||
|
||||
it('should compute ipv4 subnet number of addressable hosts', function() {
|
||||
assert.equal(ipv4Subnet.numHosts, 2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cidrSubnet() method', function() {
|
||||
// Test cases calculated with http://www.subnet-calculator.com/
|
||||
var ipv4Subnet = ip.cidrSubnet('192.168.1.134/26');
|
||||
|
||||
it('should compute an ipv4 network address', function() {
|
||||
assert.equal(ipv4Subnet.networkAddress, '192.168.1.128');
|
||||
});
|
||||
|
||||
it('should compute an ipv4 network\'s first address', function() {
|
||||
assert.equal(ipv4Subnet.firstAddress, '192.168.1.129');
|
||||
});
|
||||
|
||||
it('should compute an ipv4 network\'s last address', function() {
|
||||
assert.equal(ipv4Subnet.lastAddress, '192.168.1.190');
|
||||
});
|
||||
|
||||
it('should compute an ipv4 broadcast address', function() {
|
||||
assert.equal(ipv4Subnet.broadcastAddress, '192.168.1.191');
|
||||
});
|
||||
|
||||
it('should compute an ipv4 subnet number of addresses', function() {
|
||||
assert.equal(ipv4Subnet.length, 64);
|
||||
});
|
||||
|
||||
it('should compute an ipv4 subnet number of addressable hosts', function() {
|
||||
assert.equal(ipv4Subnet.numHosts, 62);
|
||||
});
|
||||
|
||||
it('should compute an ipv4 subnet mask', function() {
|
||||
assert.equal(ipv4Subnet.subnetMask, '255.255.255.192');
|
||||
});
|
||||
|
||||
it('should compute an ipv4 subnet mask\'s length', function() {
|
||||
assert.equal(ipv4Subnet.subnetMaskLength, 26);
|
||||
});
|
||||
|
||||
it('should know whether a subnet contains an address', function() {
|
||||
assert.equal(ipv4Subnet.contains('192.168.1.180'), true);
|
||||
});
|
||||
|
||||
it('should know whether a subnet contains an address', function() {
|
||||
assert.equal(ipv4Subnet.contains('192.168.1.195'), false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('cidr() method', function() {
|
||||
it('should mask address in CIDR notation', function() {
|
||||
assert.equal(ip.cidr('192.168.1.134/26'), '192.168.1.128');
|
||||
assert.equal(ip.cidr('2607:f0d0:1002:51::4/56'), '2607:f0d0:1002::');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEqual() method', function() {
|
||||
it('should check if addresses are equal', function() {
|
||||
assert(ip.isEqual('127.0.0.1', '::7f00:1'));
|
||||
assert(!ip.isEqual('127.0.0.1', '::7f00:2'));
|
||||
assert(ip.isEqual('127.0.0.1', '::ffff:7f00:1'));
|
||||
assert(!ip.isEqual('127.0.0.1', '::ffaf:7f00:1'));
|
||||
assert(ip.isEqual('::ffff:127.0.0.1', '::ffff:127.0.0.1'));
|
||||
assert(ip.isEqual('::ffff:127.0.0.1', '127.0.0.1'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('isPrivate() method', function() {
|
||||
it('should check if an address is localhost', function() {
|
||||
assert.equal(ip.isPrivate('127.0.0.1'), true);
|
||||
});
|
||||
|
||||
it('should check if an address is from a 192.168.x.x network', function() {
|
||||
assert.equal(ip.isPrivate('192.168.0.123'), true);
|
||||
assert.equal(ip.isPrivate('192.168.122.123'), true);
|
||||
assert.equal(ip.isPrivate('192.162.1.2'), false);
|
||||
});
|
||||
|
||||
it('should check if an address is from a 172.16.x.x network', function() {
|
||||
assert.equal(ip.isPrivate('172.16.0.5'), true);
|
||||
assert.equal(ip.isPrivate('172.16.123.254'), true);
|
||||
assert.equal(ip.isPrivate('171.16.0.5'), false);
|
||||
assert.equal(ip.isPrivate('172.25.232.15'), true);
|
||||
assert.equal(ip.isPrivate('172.15.0.5'), false);
|
||||
assert.equal(ip.isPrivate('172.32.0.5'), false);
|
||||
});
|
||||
|
||||
it('should check if an address is from a 169.254.x.x network', function() {
|
||||
assert.equal(ip.isPrivate('169.254.2.3'), true);
|
||||
assert.equal(ip.isPrivate('169.254.221.9'), true);
|
||||
assert.equal(ip.isPrivate('168.254.2.3'), false);
|
||||
});
|
||||
|
||||
it('should check if an address is from a 10.x.x.x network', function() {
|
||||
assert.equal(ip.isPrivate('10.0.2.3'), true);
|
||||
assert.equal(ip.isPrivate('10.1.23.45'), true);
|
||||
assert.equal(ip.isPrivate('12.1.2.3'), false);
|
||||
});
|
||||
|
||||
it('should check if an address is from a private IPv6 network', function() {
|
||||
assert.equal(ip.isPrivate('fd12:3456:789a:1::1'), true);
|
||||
assert.equal(ip.isPrivate('fe80::f2de:f1ff:fe3f:307e'), true);
|
||||
assert.equal(ip.isPrivate('::ffff:10.100.1.42'), true);
|
||||
assert.equal(ip.isPrivate('::FFFF:172.16.200.1'), true);
|
||||
assert.equal(ip.isPrivate('::ffff:192.168.0.1'), true);
|
||||
});
|
||||
|
||||
it('should check if an address is from the internet', function() {
|
||||
assert.equal(ip.isPrivate('165.225.132.33'), false); // joyent.com
|
||||
});
|
||||
|
||||
it('should check if an address is a loopback IPv6 address', function() {
|
||||
assert.equal(ip.isPrivate('::'), true);
|
||||
assert.equal(ip.isPrivate('::1'), true);
|
||||
assert.equal(ip.isPrivate('fe80::1'), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loopback() method', function() {
|
||||
describe('undefined', function() {
|
||||
it('should respond with 127.0.0.1', function() {
|
||||
assert.equal(ip.loopback(), '127.0.0.1')
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv4', function() {
|
||||
it('should respond with 127.0.0.1', function() {
|
||||
assert.equal(ip.loopback('ipv4'), '127.0.0.1')
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv6', function() {
|
||||
it('should respond with fe80::1', function() {
|
||||
assert.equal(ip.loopback('ipv6'), 'fe80::1')
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLoopback() method', function() {
|
||||
describe('127.0.0.1', function() {
|
||||
it('should respond with true', function() {
|
||||
assert.ok(ip.isLoopback('127.0.0.1'))
|
||||
});
|
||||
});
|
||||
|
||||
describe('127.8.8.8', function () {
|
||||
it('should respond with true', function () {
|
||||
assert.ok(ip.isLoopback('127.8.8.8'))
|
||||
});
|
||||
});
|
||||
|
||||
describe('8.8.8.8', function () {
|
||||
it('should respond with false', function () {
|
||||
assert.equal(ip.isLoopback('8.8.8.8'), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fe80::1', function() {
|
||||
it('should respond with true', function() {
|
||||
assert.ok(ip.isLoopback('fe80::1'))
|
||||
});
|
||||
});
|
||||
|
||||
describe('::1', function() {
|
||||
it('should respond with true', function() {
|
||||
assert.ok(ip.isLoopback('::1'))
|
||||
});
|
||||
});
|
||||
|
||||
describe('::', function() {
|
||||
it('should respond with true', function() {
|
||||
assert.ok(ip.isLoopback('::'))
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('address() method', function() {
|
||||
describe('undefined', function() {
|
||||
it('should respond with a private ip', function() {
|
||||
assert.ok(ip.isPrivate(ip.address()));
|
||||
});
|
||||
});
|
||||
|
||||
describe('private', function() {
|
||||
[ undefined, 'ipv4', 'ipv6' ].forEach(function(family) {
|
||||
describe(family, function() {
|
||||
it('should respond with a private ip', function() {
|
||||
assert.ok(ip.isPrivate(ip.address('private', family)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var interfaces = os.networkInterfaces();
|
||||
|
||||
Object.keys(interfaces).forEach(function(nic) {
|
||||
describe(nic, function() {
|
||||
[ undefined, 'ipv4' ].forEach(function(family) {
|
||||
describe(family, function() {
|
||||
it('should respond with an ipv4 address', function() {
|
||||
var addr = ip.address(nic, family);
|
||||
assert.ok(!addr || net.isIPv4(addr));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv6', function() {
|
||||
it('should respond with an ipv6 address', function() {
|
||||
var addr = ip.address(nic, 'ipv6');
|
||||
assert.ok(!addr || net.isIPv6(addr));
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toLong() method', function() {
|
||||
it('should respond with a int', function() {
|
||||
assert.equal(ip.toLong('127.0.0.1'), 2130706433);
|
||||
assert.equal(ip.toLong('255.255.255.255'), 4294967295);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromLong() method', function() {
|
||||
it('should repond with ipv4 address', function() {
|
||||
assert.equal(ip.fromLong(2130706433), '127.0.0.1');
|
||||
assert.equal(ip.fromLong(4294967295), '255.255.255.255');
|
||||
});
|
||||
})
|
||||
});
|
@ -105,8 +105,6 @@ testing/talos/talos/tests/kraken/
|
||||
testing/talos/talos/tests/v8_7/
|
||||
testing/web-platform/tests/resources/webidl2/
|
||||
testing/web-platform/tests/tools/third_party/
|
||||
testing/xpcshell/node-ip/
|
||||
testing/xpcshell/dns-packet/
|
||||
third_party/
|
||||
toolkit/components/jsoncpp/
|
||||
toolkit/components/protobuf/
|
||||
|
Loading…
Reference in New Issue
Block a user