dns: use an authoritative server.

This commit is contained in:
Christopher Jeffrey 2018-02-18 05:12:44 -08:00
parent 040b17d11a
commit a7ff40d6ce
No known key found for this signature in database
GPG key ID: 8962AB9DE6666BBD
12 changed files with 82040 additions and 502 deletions

80876
etc/root.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -514,10 +514,25 @@ class ChainDB {
const genesis = this.network.genesisBlock;
const block = Block.fromRaw(genesis, 'hex');
const entry = ChainEntry.fromBlock(block);
const view = new CoinView();
this.logger.info('Writing genesis block to ChainDB.');
return this.save(entry, block, new CoinView());
for (let i = 0; i < block.txs.length; i++) {
const tx = block.txs[i];
if (i > 0)
assert(await view.spendInputs(this, tx));
view.addTX(tx, 0);
}
for (let i = 1; i < block.txs.length; i++) {
const tx = block.txs[i];
await this.cdb.connect(tx, view, 0);
}
return this.save(entry, block, view);
}
/**

View file

@ -399,8 +399,9 @@ class NameDB {
return false;
// Cannot claim a non-reserved name.
if (!rules.isReserved(name, height, network))
return false;
// XXX UPDATE TLD LIST
// if (!rules.isReserved(name, height, network))
// return false;
auction.setClaimed(true);
auction.setWinner(tx.outpoint(i), output.value);

View file

@ -1,27 +1,34 @@
'use strict';
const assert = require('assert');
const EventEmitter = require('events');
const bns = require('bns');
const bio = require('bufio');
const {HSKRecord, ICANN, HSK} = require('./record');
const {HSKResource} = require('./record');
const key = require('./key');
const {
Cache,
DNSServer,
RecursiveResolver,
dnssec,
wire,
util
} = bns;
const {
Message,
Question,
Record,
Option,
ARecord,
AAAARecord,
NSRecord,
SOARecord,
TXTRecord,
UNKNOWNRecord,
types
NAMEPROOFRecord,
TRIEROOTOption,
types,
options,
codes
} = wire;
/**
@ -32,67 +39,23 @@ const {
class HandshakeServer extends DNSServer {
constructor(hsk, options) {
super(options);
this.resolver = new HandshakeResolver(hsk, options);
this.resolver.on('log', (...a) => this.emit('log', ...a));
this.resolver.on('error', e => this.emit('error', e));
this.ra = true;
}
}
/**
* HandshakeResolver
* @extends DNSResolver
*/
class HandshakeResolver extends RecursiveResolver {
constructor(hsk, options) {
super(options);
this.cache = new Cache();
this.hsk = hsk;
this.ra = false;
}
async hook(qs, auth) {
if (auth.zone !== '.')
return [null, null];
let {name, type} = qs;
assert(util.isFQDN(name));
const labels = util.split(name);
// Acutal root zone.
if (labels.length === 0)
return [null, null];
// Handshake root zone.
const zone = util.label(name, labels, -1);
if (zone !== HSK)
return [null, null];
// Slice off HSK, so as not
// to confuse the resolver.
// i.e. Don't make it hit
// us repeatedly.
name = name.substring(0, labels.pop());
if (name === '')
name = '.';
const cache = this.cache.hit(qs, auth.zone);
if (cache)
return [cache, null];
async resolve(req, rinfo) {
const [qs] = req.question;
// Our root zone.
if (name === '.') {
if (qs.name === '.') {
const res = new Message();
res.qr = true;
res.ad = true;
res.aa = true;
switch (type) {
switch (qs.type) {
case types.NS:
res.answer.push(this.toNS());
res.additional.push(this.toNSIPA());
@ -101,66 +64,82 @@ class HandshakeResolver extends RecursiveResolver {
case types.SOA:
res.answer.push(this.toSOA());
break;
case types.DNSKEY:
res.answer.push(key.pub);
break;
default:
res.authority.push(this.toSOA());
break;
}
this.cache.insert(qs, auth.zone, res, true);
if (req.isDNSSEC())
dnssec.signMessage(res, '.', key.pub, key.priv);
return [res, null];
return res;
}
// Slice off the naked TLD.
const tld = util.label(name, labels, -1);
const data = await this.hsk.getDataByName(tld);
const labels = util.split(qs.name);
const tld = util.from(qs.name, labels, -1);
const name = util.label(qs.name, labels, -1);
const data = await this.hsk.getDataByName(name);
const root = await this.getRoot(req);
// Send the root back to them.
const opt = new Option();
opt.code = options.TRIEROOT;
opt.option = new TRIEROOTOption();
opt.option.root = root;
// Should return root zone SOA record.
if (!data) {
const res = new Message();
res.code = codes.NXDOMAIN;
res.qr = true;
res.ad = true;
res.aa = true;
res.authority.push(this.toSOA());
if (type === types.TXT) {
res.answer.push(await this.prove(tld, 900, null));
res.answer.push(await this.hdr(tld, 900, null));
} else {
res.additional.push(await this.prove(tld, 900, null));
res.additional.push(await this.hdr(tld, 900, null));
if (req.isEDNS0()) {
const proof = await this.prove(root, name, 900, null);
res.additional.push(proof);
if (req.isDNSSEC()) {
dnssec.signMessage(res, '.', key.pub, key.priv);
dnssec.signMessage(res, tld, key.pub, key.priv);
}
res.setOption(opt);
}
this.cache.insert(qs, auth.zone, res, true);
return [res, null];
return res;
}
// Our fake resolution.
const rec = HSKRecord.fromRaw(data);
const res = rec.toDNS(name, type);
// Our resolution.
const rec = HSKResource.fromRaw(data);
const res = rec.toDNS(qs.name, qs.type);
if (res.aa) {
if (type === types.TXT) {
res.answer.push(await this.prove(tld, rec.ttl, data));
res.answer.push(await this.hdr(tld, 900, null));
} else {
res.additional.push(await this.prove(tld, rec.ttl, data));
res.additional.push(await this.hdr(tld, 900, null));
}
this.cache.insert(qs, auth.zone, res, true);
return [res, null];
if (req.isEDNS0()) {
const proof = await this.prove(root, name, rec.ttl, data);
res.additional.push(proof);
if (req.isDNSSEC())
dnssec.signMessage(res, tld, key.pub, key.priv);
res.setOption(opt);
}
if (rec.compat && rec.ns.length > 0)
return [res, name];
this.cache.insert(qs, auth.zone, res, true);
return [res, null];
return res;
}
toSOA() {
const rr = new Record();
const rd = new SOARecord();
rr.name = `${HSK}.`;
rr.name = '.';
rr.type = types.SOA;
rr.ttl = 900;
rr.data = rd;
@ -177,7 +156,7 @@ class HandshakeResolver extends RecursiveResolver {
toNS() {
const rr = new Record();
const rd = new NSRecord();
rr.name = `${HSK}.`;
rr.name = '.';
rr.type = types.NS;
rr.ttl = 900;
rr.data = rd;
@ -207,183 +186,52 @@ class HandshakeResolver extends RecursiveResolver {
return rr;
}
async prove(tld, ttl, data) {
const [hash, nodes] = await this.hsk.getProof(tld);
const bw = bio.write();
async prove(root, tld, ttl, data) {
const [, nodes] = await this.hsk.proveName(root, tld);
const rr = new Record();
const rd = new TXTRecord();
const rd = new NAMEPROOFRecord();
rr.name = `${tld}.${HSK}.`;
rr.type = types.TXT;
rr.name = `${tld}.`;
rr.type = types.NAMEPROOF;
rr.ttl = ttl;
rr.data = rd;
bw.writeHash(hash);
bw.writeVarint(nodes.length);
for (const node of nodes)
bw.writeVarBytes(node);
rd.exists = data ? true : false;
rd.nodes = nodes;
if (data)
bw.writeVarBytes(data);
const raw = bw.render();
const b64 = raw.toString('base64');
rd.txt.push('hsk:proof');
for (let i = 0; i < b64.length; i += 255) {
const chunk = b64.slice(i, i + 255);
rd.txt.push(chunk);
}
rd.data = data;
return rr;
}
async hdr(tld, ttl, hash) {
let header = await this.hsk.getTip();
async getRoot(req) {
const opt = getRoot(req);
if (hash)
header = await this.hsk.getEntry(hash);
if (opt)
return opt;
const rr = new Record();
const rd = new TXTRecord();
const tip = await this.hsk.getTip();
assert(tip);
rr.name = `${tld}.${HSK}.`;
rr.type = types.TXT;
rr.ttl = ttl;
rr.data = rd;
const txt = [];
let b64 = '';
if (header)
b64 = header.toRaw().toString('base64');
rd.txt.push('hsk:header');
for (let i = 0; i < b64.length; i += 255) {
const chunk = b64.slice(i, i + 255);
rd.txt.push(chunk);
}
return rr;
}
async resolve(qs, ns) {
const name = qs.name;
const labels = util.split(name);
const zone = util.label(name, labels, -1);
if (zone === ICANN) {
qs = qs.clone();
qs.name = util.to(name, labels, -1);
}
const rc = await this._resolve(qs, ns);
const res = rc.toAnswer();
if (rc.rewritten || zone === ICANN) {
const domain = util.to(name, labels, -1);
return convert(res, domain, zone);
}
return res;
return Buffer.from(tip.trieRoot, 'hex');
}
}
function append(name, domain, zone) {
if (zone === ICANN) {
if (!util.isSubdomain(zone, name))
name += `${zone}.`;
return name;
}
if (util.isSubdomain(domain, name))
name += `${zone}.`;
return name;
}
function getRoot(req) {
const edns = req.getEDNS0();
function convert(res, domain, zone) {
const msg = res;
if (!edns)
return null;
for (const qs of msg.question)
qs.name = append(qs.name, domain, zone);
const options = edns.data.options;
for (const section of msg.sections()) {
for (const rr of section) {
const x = rr.data;
rr.name = append(rr.name, domain, zone);
// DNSSEC standard
switch (rr.type) {
case types.NS:
x.ns = append(x.ns, domain, zone);
break;
case types.MD:
x.md = append(x.md, domain, zone);
break;
case types.MF:
x.mf = append(x.mf, domain, zone);
break;
case types.CNAME:
x.target = append(x.target, domain, zone);
break;
case types.SOA:
x.ns = append(x.ns, domain, zone);
x.mbox = append(x.mbox, domain, zone);
break;
case types.MB:
x.mb = append(x.mb, domain, zone);
break;
case types.MG:
x.mg = append(x.mg, domain, zone);
break;
case types.MR:
x.mr = append(x.mr, domain, zone);
break;
case types.PTR:
x.ptr = append(x.ptr, domain, zone);
break;
case types.MINFO:
x.rmail = append(x.rmail, domain, zone);
x.email = append(x.email, domain, zone);
break;
case types.MX:
x.mx = append(x.mx, domain, zone);
break;
case types.RP:
x.mbox = append(x.mbox, domain, zone);
break;
case types.AFSDB:
x.hostname = append(x.hostname, domain, zone);
break;
case types.SIG:
case types.RRSIG:
x.signerName = append(x.signerName, domain, zone);
break;
case types.PX:
x.map822 = append(x.map822, domain, zone);
x.mapx400 = append(x.mapx400, domain, zone);
break;
case types.NAPTR:
x.replacement = append(x.replacement, domain, zone);
break;
case types.KX:
x.exchanger = append(x.exchanger, domain, zone);
break;
case types.SRV:
x.target = append(x.target, domain, zone);
break;
case types.DNAME:
x.target = append(x.target, domain, zone);
break;
}
}
for (const opt of options) {
if (opt.code === wire.options.TRIEROOT)
return opt.option.root;
}
return msg;
return null;
}
exports.HandshakeServer = HandshakeServer;
exports.HandshakeResolver = HandshakeResolver;

52
lib/covenants/key.js Normal file
View file

@ -0,0 +1,52 @@
'use strict';
const {Record} = require('bns').wire;
exports.priv = Buffer.from(''
+ 'MIIEpQIBAAKCAQEAsF965ZdEncXuSbwxhD0BV3LnhUkRPw85Ws+LTokucKfBaR6G'
+ 'GOV2qc/CyfBI3ZBmM0TpJthzSKVZWeddeVxcjMAZ+qUIw4U7NkPGXALiDVUQItx/'
+ 'ZgcBtiV2hmFfVpArQodMUxveKzMLzj8VbWpGTu2myzyCTQ1MIKddoee85S4QbfjM'
+ 'bM1nR00ML6bBqUhOpOKxfi+V4ycjjeafINV4XCIbacD7bp2AJuNrn2qAzixP5xge'
+ 'oTS1WQAUWbfOjLRzG+/Dr/cMx0eLuYf1Vs7OsFZittzdBoMv3xBS0KSUkwM0Y1ST'
+ 'TrHf9xyOqaUCIwD7ksiFHiZUPoq77S9hDvSIbwIDAQABAoIBAATpU8HK+ZUvKtiQ'
+ 'zgwxqrTltT7H7xwDb4Rw3R89wLZQZZloyTEuSqSl7XW0JENPPxlUZO24/1TZjehs'
+ 'AfVcNhORUefh6qGPNzvmnUJ4rhTS9pUR8NZFga2x02AgnAgMEbhTjjOORhyL2ltO'
+ '9GjMmdKe2ZM1RyegJCuQnZHhoyf6mYXB2r7dA09OnwZdBEa/O1DhBuAmTVre+OZk'
+ '10Rex4wTGhxzfWUASxfQfhC5cr9cR1R+Km6kOf9RX3BEDNArpQHV2d1x9FyekOzw'
+ 'BH1zuhgheSdzuAGR7rXQvLIMCSZ/0LvdSrUJiY0Zh1tkvhdUW4hZqs+Gz4Ul7QF1'
+ 'JGcSZXkCgYEA6Tl8llu5jiN0U2+XPFvfGrXPqSvhS3RHvlo94eRzNRZ0cQskLHIt'
+ '3jLHrCBI2VykGF35aVSqTbumv4cnsFlmQZVl/OmMLI44ugnWy005o3ySOqF3FsA0'
+ 'l8SQD0vIJk1UTTu9obAqV72Kbt9sx6fSeuR6xckSNlYgcWDljtHeUasCgYEAwZi6'
+ 'bBydJvJ61PKNrXQyEP15d4i1CnGh2OBfbGiQSMNpvzFcKfR79qn2K+XhV6eIrmE2'
+ 'bM3rzjgE66rv6fzQn5LDDN7ZuCoPBfAV9hH3/Dr7GqC1GvWoeG/deWobPuzBGxnW'
+ '1B2VVjKvqG18DZVZlgsjFN9NM6f3hogPNNI56E0CgYEAkwXcVmToaoRLNrXoHvLD'
+ 'iHEIwdqZohlhiMwWqqp7PgIz0Xd2jFZGOAbG/Ok1Q2E1SO8k5ZOr8GjVS3QGPxN8'
+ 'dOebbX5FEWlutUiykWLTbQ6AmFllW4A7J1mQfzQErrCc7js05hLJ/pnMBOzwBET1'
+ 'WOdjxf9lbb+JoC+3RvtiLRUCgYEApYEG5oPzyacEYWZWvpGWd7XqkMkbVKleXsU6'
+ 'brhZmQsOLThqfSeYjoAwhsjIw6HjFIjg+VV1oN99PWfuIJBUXgcenrMpV+sE2uOs'
+ 'Mqib41Mc9l+rVDftZcDkivauAjZuw9dsM/xyfbVpPEkVA5vJcZ9lx2M7YczXrHhG'
+ '37ZVcQUCgYEAqgVrQ5CfInj9MZSxTUVWjwL9imrgRQEX77y6hlCkblUH3ubpk91m'
+ 'HdX400I6Xo5nIp9IZobGPLGTyUHojmFAeFAHNSltduMwRb41dyjXNwG2s5v5uY9T'
+ 'E2dDJc22xqmzRb9nc2e8xZhFmRcweHWOK+isiqK/6quK77WfO9JHykU=',
'base64'
);
// . 172800 IN DS 28834 8 2 305fadd310e0e468faa92d65d3d0c0fe1ff740f86f2b203bd46986bdf25582d5
exports.pub = Record.fromJSON({
name: '.',
ttl: 172800,
class: 'INET',
type: 'DNSKEY',
data: {
flags: 257,
protocol: 3,
algorithm: 8,
publicKey: ''
+ 'AwEAAQCwX3rll0Sdxe5JvDGEPQFXcueFSRE/Dzlaz4tOiS5wp8FpHoYY5Xap'
+ 'z8LJ8EjdkGYzROkm2HNIpVlZ5115XFyMwBn6pQjDhTs2Q8ZcAuINVRAi3H9m'
+ 'BwG2JXaGYV9WkCtCh0xTG94rMwvOPxVtakZO7abLPIJNDUwgp12h57zlLhBt'
+ '+MxszWdHTQwvpsGpSE6k4rF+L5XjJyON5p8g1XhcIhtpwPtunYAm42ufaoDO'
+ 'LE/nGB6hNLVZABRZt86MtHMb78Ov9wzHR4u5h/VWzs6wVmK23N0Ggy/fEFLQ'
+ 'pJSTAzRjVJNOsd/3HI6ppQIjAPuSyIUeJlQ+irvtL2EO9Ihv'
}
});

View file

@ -4,6 +4,7 @@ const assert = require('assert');
const bns = require('bns');
const {IP, onion, base32} = require('binet');
const {bech32} = require('bstring');
const {Struct} = require('bufio');
const compress = require('./compress');
const {
@ -14,7 +15,6 @@ const {
const {
Message,
Record,
RecordData,
ARecord,
AAAARecord,
NSRecord,
@ -29,6 +29,8 @@ const {
TLSARecord,
SSHFPRecord,
OPENPGPKEYRecord,
URIRecord,
RPRecord,
types
} = wire;
@ -48,38 +50,29 @@ const {
const DUMMY = Buffer.alloc(0);
const ICANN = 'i';
const HSK = 'h';
const ICANNP = `.${ICANN}`;
const ICANNS = `${ICANN}.`;
const HSKP = `.${HSK}`;
const HSKS = `${HSK}.`;
const rtypes = {
INET4: 1, // A
INET6: 2, // AAAA
ONION: 3, // TXT (appended to A/AAA responses)
ONIONNG: 5, // TXT (appended to A/AAA responses)
INAME: 6, // N/A
HNAME: 7, // N/A
CANONICAL: 8, // CNAME
DELEGATE: 9, // DNAME
NS: 10, // NS
SERVICE: 11, // SRV
URL: 12, // TXT
EMAIL: 13, // TXT
TEXT: 14, // TXT
LOCATION: 15, // LOC
MAGNET: 16, // TXT
DS: 17, // DS
TLS: 18, // TLSA
SSH: 19, // SSHFP
PGP: 20, // OPENPGPKEY (XXX)
ADDR: 21 // TXT
ONIONNG: 4, // TXT (appended to A/AAA responses)
NAME: 5, // CNAME
CANONICAL: 6, // CNAME
DELEGATE: 7, // DNAME
NS: 8, // NS
SERVICE: 9, // SRV
URL: 10, // URI
EMAIL: 11, // RP
TEXT: 12, // TXT
LOCATION: 13, // LOC
MAGNET: 14, // TXT
DS: 15, // DS
TLS: 16, // TLSA
SSH: 17, // SSHFP
PGP: 18, // OPENPGPKEY (XXX)
ADDR: 19 // TXT
};
class Extra extends RecordData {
class Extra extends Struct {
constructor() {
super();
this.type = 0;
@ -132,7 +125,7 @@ class Extra extends RecordData {
}
}
class Addr extends RecordData {
class Addr extends Struct {
constructor(currency, address) {
super();
this.currency = currency || '';
@ -327,11 +320,11 @@ class Addr extends RecordData {
}
}
class SSH extends RecordData {
class SSH extends Struct {
constructor() {
super();
this.algorithm = 0;
this.type = 0;
this.keyType = 0;
this.fingerprint = DUMMY;
}
@ -344,7 +337,7 @@ class SSH extends RecordData {
toWriter(bw) {
bw.writeU8(this.algorithm);
bw.writeU8(this.type);
bw.writeU8(this.keyType);
bw.writeU8(this.fingerprint.length);
bw.writeBytes(this.fingerprint);
return bw;
@ -352,7 +345,7 @@ class SSH extends RecordData {
fromReader(br) {
this.algorithm = br.readU8();
this.type = br.readU8();
this.keyType = br.readU8();
this.fingerprint = br.readBytes(br.readU8());
return this;
}
@ -360,7 +353,7 @@ class SSH extends RecordData {
toJSON() {
return {
algorithm: this.algorithm,
type: this.type,
keyType: this.keyType,
fingerprint: this.fingerprint.toString('hex')
};
}
@ -368,11 +361,11 @@ class SSH extends RecordData {
fromJSON(json) {
assert(json && typeof json === 'object');
assert((json.algorithm & 0xff) === json.algorithm);
assert((json.type & 0xff) === json.type);
assert((json.keyType & 0xff) === json.keyType);
assert(typeof json.fingerprint === 'string');
assert((json.fingerprint >>> 1) <= 255);
this.algorithm = json.algorithm;
this.type = json.type;
this.keyType = json.keyType;
this.fingerprint = Buffer.from(json.fingerprint, 'hex');
return this;
}
@ -392,7 +385,7 @@ class PGP extends SSH {
}
}
class TLS extends RecordData {
class TLS extends Struct {
constructor() {
super();
this.protocol = '';
@ -471,7 +464,7 @@ class TLS extends RecordData {
}
}
class DS extends RecordData {
class DS extends Struct {
constructor() {
super();
this.keyTag = 0;
@ -497,7 +490,7 @@ class DS extends RecordData {
}
fromReader(br) {
this.keyTag = br.readU16BE();
this.keyTag = br.readU16();
this.algorithm = br.readU8();
this.digestType = br.readU8();
this.digest = br.readBytes(br.readU8());
@ -536,7 +529,7 @@ class DS extends RecordData {
}
}
class Magnet extends RecordData {
class Magnet extends Struct {
constructor(nid, nin) {
super();
this.nid = nid || '';
@ -623,7 +616,7 @@ class Magnet extends RecordData {
}
}
class Service extends RecordData {
class Service extends Struct {
constructor() {
super();
this.service = '';
@ -728,7 +721,7 @@ class Service extends RecordData {
}
}
class Location extends RecordData {
class Location extends Struct {
constructor() {
super();
this.version = 0;
@ -833,8 +826,7 @@ class Location extends RecordData {
function compressTarget(type, target, c) {
switch (type) {
case rtypes.INAME:
case rtypes.HNAME: {
case rtypes.NAME: {
c.add(target);
break;
}
@ -857,8 +849,7 @@ function sizeTarget(type, target, c) {
case rtypes.ONIONNG:
size += 33;
break;
case rtypes.INAME:
case rtypes.HNAME: {
case rtypes.NAME: {
size += c.size(target);
break;
}
@ -891,8 +882,7 @@ function writeTarget(type, target, bw, c) {
bw.writeBytes(key);
break;
}
case rtypes.INAME:
case rtypes.HNAME: {
case rtypes.NAME: {
c.write(bw, target);
break;
}
@ -913,14 +903,9 @@ function readTarget(type, br, d) {
return onion.encodeLegacy(br.readBytes(10));
case rtypes.ONIONNG:
return onion.encodeNG(br.readBytes(33), null);
case rtypes.INAME: {
case rtypes.NAME: {
const name = d.read(br);
assert(verifyICANN(name));
return name;
}
case rtypes.HNAME: {
const name = d.read(br);
assert(verifyHSK(name));
assert(verifyName(name));
return name;
}
default:
@ -928,15 +913,7 @@ function readTarget(type, br, d) {
}
}
function verifyICANN(name) {
return verifyName(name, false);
}
function verifyHSK(name) {
return verifyName(name, true);
}
function verifyName(name, hsk) {
function verifyName(name) {
if (name.length === 0)
return false;
@ -963,7 +940,7 @@ function verifyName(name, hsk) {
}
// - and _
if (ch === 0x2d || (hsk && ch === 0x5f)) {
if (ch === 0x2d || ch === 0x5f) {
if (i === 0 || i === name.length - 1)
return false; // Bad dash.
@ -976,16 +953,10 @@ function verifyName(name, hsk) {
return false; // Unexpected character.
}
if (util.endsWith(name, HSKP))
return false;
if (util.endsWith(name, ICANNP))
return false;
return true;
}
class Target extends RecordData {
class Target extends Struct {
constructor(type, target) {
super();
this.type = rtypes.INET4;
@ -1015,10 +986,8 @@ class Target extends RecordData {
}
toString() {
if (this.isHSK())
return `${this.target}.${HSK}`;
if (this.isICANN())
return `${this.target}.${ICANN}`;
if (this.isName())
return `${this.target}.`;
return this.target;
}
@ -1060,23 +1029,11 @@ class Target extends RecordData {
return this;
}
let name = util.trimFQDN(str);
const name = util.trimFQDN(str);
assert(verifyName(name));
if (util.endsWith(name, HSKP)) {
name = name.slice(0, -HSKP.length);
assert(verifyHSK(name));
this.type = rtypes.HNAME;
this.target = name;
} else if (util.endsWith(name, ICANNP)) {
name = name.slice(0, -ICANNP.length);
assert(verifyICANN(name));
this.type = rtypes.INAME;
this.target = name;
} else {
assert(verifyICANN(name));
this.type = rtypes.INAME;
this.target = name;
}
this.type = rtypes.NAME;
this.target = name;
return this;
}
@ -1113,7 +1070,7 @@ class Target extends RecordData {
return `_${hash}.${name}`;
}
return `_${hash}.${HSK}`;
return `_${hash}.`;
}
isINET4() {
@ -1132,20 +1089,12 @@ class Target extends RecordData {
return this.type === rtypes.ONIONNG;
}
isHSK() {
return this.type === rtypes.HNAME;
}
isICANN() {
return this.type === rtypes.INAME;
}
isINET() {
return this.type <= rtypes.INET6;
}
isName() {
return this.type > rtypes.ONIONNG;
return this.type === rtypes.NAME;
}
isTor() {
@ -1153,12 +1102,7 @@ class Target extends RecordData {
}
toDNS() {
if (this.isHSK()) {
assert(!util.isFQDN(this.target));
return `${this.target}.${HSK}.`;
}
if (this.isICANN()) {
if (this.isName()) {
assert(!util.isFQDN(this.target));
return `${this.target}.`;
}
@ -1187,7 +1131,7 @@ class Target extends RecordData {
}
}
class HSKRecord extends RecordData {
class HSKResource extends Struct {
constructor() {
super();
this.version = 0;
@ -1449,8 +1393,7 @@ class HSKRecord extends RecordData {
this.hosts.push(new Target(type, target));
break;
}
case rtypes.INAME:
case rtypes.HNAME: {
case rtypes.NAME: {
assert(!this.canonical);
const target = readTarget(type, br, d);
this.canonical = new Target(type, target);
@ -1689,7 +1632,7 @@ class HSKRecord extends RecordData {
toSOA(name) {
assert(util.isFQDN(name));
const tld = util.from(name, -2);
const tld = util.from(name, -1);
const rr = new Record();
const rd = new SOARecord();
@ -1908,7 +1851,7 @@ class HSKRecord extends RecordData {
rr.data = rd;
rd.algorithm = ssh.algorithm;
rd.type = ssh.type;
rd.keyType = ssh.keyType;
rd.fingerprint = ssh.fingerprint;
answer.push(rr);
@ -1938,6 +1881,49 @@ class HSKRecord extends RecordData {
return answer;
}
toURI(name) {
const answer = [];
for (const url of this.url) {
const rr = new Record();
const rd = new URIRecord();
rr.name = name;
rr.type = types.URI;
rr.ttl = this.ttl;
rr.data = rd;
rd.priority = 0;
rd.weight = 0;
rd.target = url;
answer.push(rr);
}
return answer;
}
toRP(name) {
const answer = [];
for (const email of this.email) {
const rr = new Record();
const rd = new RPRecord();
rr.name = name;
rr.type = types.RP;
rr.ttl = this.ttl;
rr.data = rd;
rd.mbox = email;
rd.txt = '.';
answer.push(rr);
}
return answer;
}
hasTor() {
for (const host of this.hosts) {
if (host.isTor())
@ -1965,40 +1951,6 @@ class HSKRecord extends RecordData {
return rr;
}
toURLTXT(name) {
const rr = new Record();
const rd = new TXTRecord();
rr.name = name;
rr.type = types.TXT;
rr.ttl = this.ttl;
rr.data = rd;
rd.txt.push('hsk:url');
for (const url of this.url)
rd.txt.push(url);
return rr;
}
toEmailTXT(name) {
const rr = new Record();
const rd = new TXTRecord();
rr.name = name;
rr.type = types.TXT;
rr.ttl = this.ttl;
rr.data = rd;
rd.txt.push('hsk:email');
for (const email of this.email)
rd.txt.push(email);
return rr;
}
toMagnetTXT(name) {
const rr = new Record();
const rd = new TXTRecord();
@ -2054,12 +2006,6 @@ class HSKRecord extends RecordData {
if (this.text.length > 0)
answer.push(this.toTextTXT(name));
if (this.url.length > 0)
answer.push(this.toURLTXT(name));
if (this.email.length > 0)
answer.push(this.toEmailTXT(name));
if (this.magnet.length > 0)
answer.push(this.toMagnetTXT(name));
@ -2078,13 +2024,34 @@ class HSKRecord extends RecordData {
assert(util.isFQDN(name));
name += `${HSK}.`;
if (this.compat) {
const records = wire.fromZone(bns.hints);
for (const rr of records) {
switch (rr.type) {
case types.NS:
rr.data.ns = rr.data.ns.toLowerCase();
res.authority.push(rr);
break;
case types.A:
case types.AAAA:
rr.name = rr.name.toLowerCase();
res.additional.push(rr);
break;
case types.DS:
res.authority.push(rr);
break;
}
}
return res;
}
const labels = util.split(name);
// Referral.
if (labels.length > 2) {
const tld = util.from(name, labels, -2);
if (labels.length > 1) {
const tld = util.from(name, labels, -1);
if (this.ns.length > 0) {
res.authority = this.toNS(tld, naked);
@ -2099,8 +2066,6 @@ class HSKRecord extends RecordData {
res.authority = this.toSOA(tld);
}
res.setEDNS0(4096, true);
return res;
}
@ -2161,6 +2126,12 @@ class HSKRecord extends RecordData {
case types.OPENPGPKEY:
res.answer = this.toOPENPGPKEY(name);
break;
case types.URI:
res.answer = this.toURI(name);
break;
case types.RP:
res.answer = this.toRP(name);
break;
}
if (res.answer.length === 0
@ -2179,15 +2150,21 @@ class HSKRecord extends RecordData {
// think it's standard recursive resolver
// behavior to pay attention to them.
}
res.setEDNS0(4096, true);
return res;
}
// Nothing. Return the SOA.
res.authority = this.toSOA(name);
}
if (this.ns.length > 0) {
res.authority = this.toNS(name, naked);
res.additional = this.toNSIP(name, naked);
res.setEDNS0(4096, true);
// Always push on DS records for a referral.
for (const rr of this.toDS(name))
res.authority.push(rr);
} else {
// Nothing. Return the SOA.
res.authority = this.toSOA(name);
}
}
return res;
}
@ -2435,10 +2412,4 @@ class HSKRecord extends RecordData {
}
}
exports.ICANN = ICANN;
exports.HSK = HSK;
exports.ICANNP = ICANNP;
exports.ICANNS = ICANNS;
exports.HSKP = HSKP;
exports.HSKS = HSKS;
exports.HSKRecord = HSKRecord;
exports.HSKResource = HSKResource;

File diff suppressed because it is too large Load diff

View file

@ -23,8 +23,8 @@ const blacklist = new Set([
'bit', // Namecoin
'eth', // ENS
'example', // ICANN reserved
'h', // Handshake compat
'i', // ICANN compat
// 'h', // Handshake compat
// 'i', // ICANN compat
'invalid', // ICANN reserved
'local', // mDNS
'localhost', // ICANN reserved
@ -185,8 +185,8 @@ exports.isReserved = function isReserved(name, height, network) {
assert((height >>> 0) === height);
assert(network);
if (network.type !== 'main')
return false;
// if (network.type !== 'main')
// return false;
if (height >= exports.CLAIM_PERIOD)
return false;

View file

@ -244,7 +244,7 @@ class FullNode extends Node {
await this.openPlugins();
await this.http.open();
await this.dns.open(53, '127.0.0.1');
await this.dns.open(5368, '127.0.0.1');
await this.handleOpen();
this.logger.info('Node is loaded.');

File diff suppressed because one or more lines are too long

View file

@ -11,6 +11,7 @@
*/
const BN = require('bn.js');
const genesis = require('./genesis.json');
const network = exports;
@ -96,12 +97,12 @@ main.halvingInterval = 875000;
main.genesis = {
version: 0,
hash: '278c36df6a34966988b0c35c369124cc65bd909fdadedfd57390d2228cdb7f6b',
hash: '9b5d0da7b31f9a909cff699c47c5ac503e4440a3e524ec0c0ac45157961c148f',
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
merkleRoot:
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
witnessRoot:
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
trieRoot:
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
time: 1514765688,
@ -116,22 +117,7 @@ main.genesis = {
* @const {String}
*/
main.genesisBlock = ''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
+ '4c111314787d495a00000000ffff7f2000000000000000000000000000000000'
+ '2a00000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000100000000010000000000000000000000000000000000'
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
main.genesisBlock = genesis.main;
/**
* POW-related constants.
@ -429,12 +415,12 @@ testnet.halvingInterval = 875000;
testnet.genesis = {
version: 0,
hash: 'a126bf34683dfe1b17646b2d3472d4ebbb20a4b246014f788e8bb6a0badfd7d8',
hash: '600b659a56c45c7687d3e8e7646ed8224d209ee145fe010cc580f9cb260bd8d8',
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
merkleRoot:
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
witnessRoot:
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
trieRoot:
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
time: 1514765689,
@ -444,19 +430,7 @@ testnet.genesis = {
height: 0
};
testnet.genesisBlock = ''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
+ '4c111314797d495a00000000ffff7f2000000000000000000000000000000000'
+ '1200000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000100000000010000000000000000000000000000000000'
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
testnet.genesisBlock = genesis.testnet;
testnet.pow = {};
testnet.pow.limit = new BN(
@ -563,12 +537,12 @@ regtest.halvingInterval = 150;
regtest.genesis = {
version: 0,
hash: 'efad42980aeca59254a17f8ea40df2f5dc43db6a020c5e60a4e620e953aa6d99',
hash: '4acfcebc924ccf90ec37933bf24982814f5a8014d799d828dd25c631adb786d3',
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
merkleRoot:
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
witnessRoot:
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
trieRoot:
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
time: 1514765690,
@ -578,19 +552,7 @@ regtest.genesis = {
height: 0
};
regtest.genesisBlock = ''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
+ '4c1113147a7d495a00000000ffff7f2000000000000000000000000000000000'
+ '1200000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000100000000010000000000000000000000000000000000'
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
regtest.genesisBlock = genesis.regtest;
regtest.pow = {};
regtest.pow.limit = new BN(
@ -698,12 +660,12 @@ simnet.halvingInterval = 875000;
simnet.genesis = {
version: 0,
hash: 'b185fff116006d8099bc50fa072f2beed6c077be0ec9160d2f5a6401a2dfdeb6',
hash: '4f3f5a9029753f50bd793b34cffbd5563cc74004fef97e7e3851adac302cc6ab',
prevBlock: '0000000000000000000000000000000000000000000000000000000000000000',
merkleRoot:
'268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a7ab722aa',
'c3256dc16ad7ac7207b8e678f851a1185dd9a1bc4fefc85cce9740ae093da524',
witnessRoot:
'6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be90d230836',
'21717349c294000324461cb0eb0527c543909ff0b2c9bd09f59cdfedc0909500',
trieRoot:
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
time: 1514765691,
@ -713,19 +675,7 @@ simnet.genesis = {
height: 0
};
simnet.genesisBlock = ''
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '00000000268372f68cc865c35d9af886886bc301969cfe5901f357759d03e33a'
+ '7ab722aa6c91741305d5863ca4fb95cad7f8c41bb06d82e6e3a1515e12b40be9'
+ '0d23083603170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf'
+ '4c1113147b7d495a00000000ffff7f2000000000000000000000000000000000'
+ '1200000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000000000000000000000000000000000000000000000000'
+ '0000000000000000000100000000010000000000000000000000000000000000'
+ '000000000000000000000000000000ffffffff013830312f4e6f762f32303137'
+ '2045464620746f204943414e4e3a20446f6e2774205069636b20557020746865'
+ '2043656e736f7227732050656effffffff0100b4c404000000000014197a438a'
+ '75ceee7e58a03ebab3eabf9afd8080c2000000000000';
simnet.genesisBlock = genesis.simnet;
simnet.pow = {};
simnet.pow.limit = new BN(

View file

@ -1,11 +1,18 @@
'use strict';
const assert = require('assert');
const fs = require('bfile');
const Path = require('path');
const consensus = require('../lib/protocol/consensus');
const TX = require('../lib/primitives/tx');
const Block = require('../lib/primitives/block');
const Address = require('../lib/primitives/address');
const Witness = require('../lib/script/witness');
const Input = require('../lib/primitives/input');
const Output = require('../lib/primitives/output');
const util = require('../lib/utils/util');
const rules = require('../lib/covenants/rules');
const {types} = rules;
const secp256k1 = require('bcrypto/lib/secp256k1');
const hash160 = require('bcrypto/lib/hash160');
@ -18,6 +25,10 @@ const keyHash = hash160.digest(key);
const ZERO_ROOT =
'03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314';
const {HSKResource} = require('../lib/covenants/record');
const root = require('../etc/root.json');
const names = Object.keys(root).sort();
function createGenesisBlock(options) {
let flags = options.flags;
let addr = options.address;
@ -70,9 +81,189 @@ function createGenesisBlock(options) {
block.txs.push(tx);
const claim = new TX({
version: 0,
inputs: [{
prevout: {
hash: tx.hash('hex'),
index: 0
},
witness: new Witness(),
sequence: 0xffffffff
}],
outputs: [{
value: consensus.BASE_REWARD,
address: addr
}],
locktime: 0
});
for (const name of names) {
const output = new Output();
output.value = 0;
output.address = addr;
output.covenant.type = types.CLAIM;
output.covenant.items.push(Buffer.from(name, 'ascii'));
claim.outputs.push(output);
}
claim.refresh();
const register = new TX({
version: 0,
inputs: [],
outputs: [],
locktime: 0
});
let i = 1;
for (const name of names) {
const res = HSKResource.fromJSON(root[name]);
const input = Input.fromOutpoint(claim.outpoint(i));
register.inputs.push(input);
const output = new Output();
output.value = 0;
output.address = addr;
output.covenant.type = types.REGISTER;
output.covenant.items.push(Buffer.from(name, 'ascii'));
output.covenant.items.push(res.toRaw());
register.outputs.push(output);
i += 1;
}
register.refresh();
block.txs.push(claim);
block.txs.push(register);
block.merkleRoot = block.createMerkleRoot('hex');
block.witnessRoot = block.createWitnessRoot('hex');
return block;
}
/*
const tlds = require('handshake-names/build/tld');
const record = Buffer.from('00008000', 'hex');
function createGenesisBlock(options) {
let flags = options.flags;
let addr = options.address;
let nonce = options.nonce;
let sol = options.solution;
if (!flags) {
flags = Buffer.from(
'01/Nov/2017 EFF to ICANN: Don\'t Pick Up the Censor\'s Pen',
'ascii');
}
if (!addr)
addr = Address.fromHash(keyHash, 0);
if (!nonce)
nonce = Buffer.alloc(16, 0x00);
if (!sol)
sol = new Uint32Array(2);
const tx = new TX({
version: 0,
inputs: [{
prevout: {
hash: consensus.NULL_HASH,
index: 0xffffffff
},
witness: new Witness([flags]),
sequence: 0xffffffff
}],
outputs: [{
value: consensus.BASE_REWARD,
address: addr
}],
locktime: 0
});
const block = new Block({
version: 0,
prevBlock: consensus.NULL_HASH,
merkleRoot: tx.hash('hex'),
witnessRoot: tx.witnessHash('hex'),
trieRoot: ZERO_ROOT,
time: options.time,
bits: options.bits,
nonce: nonce,
solution: sol
});
block.txs.push(tx);
const claim = new TX({
version: 0,
inputs: [{
prevout: {
hash: tx.hash('hex'),
index: 0
},
witness: new Witness(),
sequence: 0xffffffff
}],
outputs: [{
value: consensus.BASE_REWARD,
address: addr
}],
locktime: 0
});
for (const name of tlds) {
const output = new Output();
output.value = 0;
output.address = addr;
output.covenant.type = types.CLAIM;
output.covenant.items.push(Buffer.from(name, 'ascii'));
claim.outputs.push(output);
}
claim.refresh();
const register = new TX({
version: 0,
inputs: [],
outputs: [],
locktime: 0
});
let i = 1;
for (const name of tlds) {
const input = Input.fromOutpoint(claim.outpoint(i));
register.inputs.push(input);
const output = new Output();
output.value = 0;
output.address = addr;
output.covenant.type = types.REGISTER;
output.covenant.items.push(Buffer.from(name, 'ascii'));
output.covenant.items.push(record);
register.outputs.push(output);
i += 1;
}
register.refresh();
block.txs.push(claim);
block.txs.push(register);
block.merkleRoot = block.createMerkleRoot('hex');
block.witnessRoot = block.createWitnessRoot('hex');
return block;
}
*/
const main = createGenesisBlock({
time: 1514765688,
bits: 0x207fffff,
@ -116,33 +307,29 @@ function formatBlock(name, block) {
};`;
}
function formatRaw(name, block) {
const str = block.toRaw().toString('hex');
let out = `${name}.genesisBlock = ''\n`;
for (let i = 0; i < str.length; i += 64)
out += ` + '${str.slice(i, i + 64)}'\n`;
out = out.slice(0, -1) + ';';
return out;
function toHex(block) {
return block.toRaw().toString('hex');
}
function dump(name, block) {
const blk = formatBlock(name, block);
const raw = formatRaw(name, block);
console.log(blk);
console.log('');
console.log(raw);
console.log('');
}
console.log('');
dump('main', main);
dump('testnet', testnet);
dump('regtest', regtest);
dump('simnet', simnet);
console.log(JSON.stringify(testnet.toJSON(), null, 2));
const file = Path.resolve(__dirname, '..', 'lib', 'protocol', 'genesis.json');
fs.writeFileSync(file, JSON.stringify({
main: toHex(main),
testnet: toHex(testnet),
regtest: toHex(regtest),
simnet: toHex(simnet)
}, null, 2));