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:
Cosmin Sabou 2019-04-04 13:34:35 +03:00
parent b4eecfd1a6
commit 03a4c6187b
31 changed files with 553 additions and 4604 deletions

View File

@ -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

View File

@ -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++]();
}
}

View File

@ -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

View File

@ -1,9 +0,0 @@
root: true
parserOptions:
ecmaVersion: 2015
env:
node: true
extends: standard

View File

@ -1,4 +0,0 @@
node_modules/
.nyc_output/
coverage/
package-lock.json

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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')
})

View File

@ -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')
})

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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"
]
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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" +

View File

@ -1,2 +0,0 @@
node_modules/
npm-debug.log

View File

@ -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": "'"
}

View File

@ -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
}

View File

@ -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

View File

@ -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.

View File

@ -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) );
};

View File

@ -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"
}

View File

@ -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');
});
})
});

View File

@ -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/