Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix EDNS, fix EDNS cookies, add EDE (Extended DNS Error codes) #37

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,9 @@ const eflagsByVal = {
*/

const options = {
// Reference:
// https://www.iana.org/assignments/dns-parameters/
// dns-parameters.xhtml#dns-parameters-11
RESERVED: 0, // None
LLQ: 1, // Long Lived Queries
UL: 2, // Update Lease Draft
Expand All @@ -446,10 +449,17 @@ const options = {
PADDING: 12, // Padding
CHAIN: 13, // Chain
KEYTAG: 14, // EDNS Key Tag
EDE: 15, // Extended DNS Errors (RFC 8914)
// EDNS-Client-Tag: 16
// EDNS-Server-Tag: 17

// 15-26945 are unassigned
// 18-20291 are unassigned

// DEVICEID: 26946,
// Umbrella Ident: 20292

// 20293-26945 are unassigned

// DEVICEID: 26946

// 26947-65000 are unassigned

Expand Down Expand Up @@ -484,6 +494,7 @@ const optionsByVal = {
[options.PADDING]: 'PADDING',
[options.CHAIN]: 'CHAIN',
[options.KEYTAG]: 'KEYTAG',
[options.EDE]: 'EDE',
// [options.DEVICEID]: 'DEVICEID',
[options.LOCAL]: 'LOCAL'
};
Expand Down
9 changes: 8 additions & 1 deletion lib/internal/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,8 @@ const EXPIRESchema = [
];

const COOKIESchema = [
['cookie', HEXEND]
['clientCookie', HEXEND],
['serverCookie', HEXEND]
];

const TCPKEEPALIVESchema = [
Expand All @@ -540,6 +541,11 @@ const KEYTAGSchema = [
['tags', TAGS]
];

const EDESchema = [
['infoCode', U16],
['extraText', CHAR]
];

const LOCALSchema = [
['data', HEXEND]
];
Expand Down Expand Up @@ -660,6 +666,7 @@ const opts = {
[options.PADDING]: PADDINGSchema,
[options.CHAIN]: CHAINSchema,
[options.KEYTAG]: KEYTAGSchema,
[options.EDE]: EDESchema,
[options.LOCAL]: LOCALSchema,
[options.LOCALSTART]: LOCALSchema,
[options.LOCALEND]: LOCALSchema
Expand Down
2 changes: 1 addition & 1 deletion lib/resolver/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ class DNSResolver extends EventEmitter {
// servers get mad at this, most
// notably alidns' servers.
if (this.rd)
req.edns.setCookie(util.cookie());
req.edns.setClientCookie(util.cookie());
}

if (this.rd)
Expand Down
43 changes: 23 additions & 20 deletions lib/server/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ const dnssec = require('../dnssec');
const DNSError = require('../error');
const {Server} = require('../internal/net');
const wire = require('../wire');
const util = require('../util');

const {
codes,
options,
types,
MAX_EDNS_SIZE,
MAX_UDP_SIZE,
MAX_MSG_SIZE
} = constants;

const {
Message
Message,
Question
} = wire;

/**
Expand Down Expand Up @@ -179,14 +180,12 @@ class DNSServer extends EventEmitter {
if (this.edns && req.isEDNS()) {
res.setEDNS(this.ednsSize, ds);

if (this.ra) {
// Echo cookies if we're recursive.
for (const opt of req.edns.options) {
if (opt.code === options.COOKIE) {
res.edns.options.push(opt);
break;
}
}
// Echo client cookie if present
// and add server cookie
const cookie = req.edns.getCookie();
if (cookie) {
res.edns.setClientCookie(cookie.clientCookie);
res.edns.addServerCookie(util.cookie());
}
} else {
res.unsetEDNS();
Expand Down Expand Up @@ -298,16 +297,20 @@ class DNSServer extends EventEmitter {
} catch (e) {
this.emit('error', e);

if (msg.length < 2)
return;

res = new Message();
res.id = bio.readU16BE(msg, 0);
res.ra = this.ra;
res.qr = true;
res.code = codes.FORMERR;

this.send(null, res, rinfo);
// Try to at least echo the msg id and the (first) question
// in the error response
try {
res = new Message();
res.id = bio.readU16BE(msg, 0);
res.ra = this.ra;
res.qr = true;
res.code = codes.FORMERR;
res.question = [Question.decode(msg.slice(12))];

this.send(null, res, rinfo);
} catch (e) {
// ...otherwise just ignore
}

return;
}
Expand Down
96 changes: 88 additions & 8 deletions lib/wire.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,6 @@ class Message extends Struct {
assert((size & 0xffff) === size);
assert(typeof dnssec === 'boolean');

this.edns.reset();
this.edns.enabled = true;
this.edns.size = size;
this.edns.dnssec = dnssec;
Expand Down Expand Up @@ -1506,20 +1505,30 @@ class EDNS extends Struct {
return this.set(option.code, option);
}

setCookie(cookie) {
setClientCookie(cookie) {
assert(Buffer.isBuffer(cookie));
const option = new COOKIEOption();
option.cookie = cookie;
option.clientCookie = cookie;
return this.add(option);
}

addServerCookie(cookie) {
assert(Buffer.isBuffer(cookie));
const opt = this.getCookie();

if (!opt)
return;

opt.serverCookie = cookie;
}

getCookie() {
const opt = this.get(options.COOKIE);

if (!opt)
return null;

return opt.cookie;
return opt;
}

hasCookie() {
Expand All @@ -1535,6 +1544,20 @@ class EDNS extends Struct {
return opt.cookie;
}

setEDE(infoCode, extraText) {
assert((infoCode & 0xffff) === infoCode);

const option = new EDEOption();
option.infoCode = infoCode;

if (extraText != null) {
assert(typeof extraText === 'string');
option.extraText = extraText;
}

return this.add(option);
}

getDataSize(map) {
let size = 0;
for (const opt of this.options)
Expand Down Expand Up @@ -5836,26 +5859,44 @@ class EXPIREOption extends OptionData {
class COOKIEOption extends OptionData {
constructor() {
super();
this.cookie = DUMMY;
this.clientCookie = DUMMY8;
this.serverCookie = DUMMY;
}

get code() {
return options.COOKIE;
}

getSize() {
return this.cookie.length;
return this.clientCookie.length + this.serverCookie.length;
}

write(bw) {
bw.writeBytes(this.cookie);
bw.writeBytes(this.clientCookie);
bw.writeBytes(this.serverCookie);
return this;
}

read(br) {
this.cookie = br.readBytes(br.left());
this.clientCookie = br.readBytes(8);
if (br.left()) {
assert(br.left() >= 8);
this.serverCookie = br.readBytes(br.left());
}

return this;
}

setServerCookie(data) {
if (!data) {
this.serverCookie = DUMMY;
} else {
assert(Buffer.isBuffer(data));
assert(data.length >= 8);
assert(data.length <= 32);
this.serverCookie = data;
}
}
}

/**
Expand Down Expand Up @@ -5993,6 +6034,40 @@ class KEYTAGOption extends OptionData {
}
}

/**
* EDE Option
* EDNS Extended DNS Errors Option
* @see https://www.rfc-editor.org/rfc/rfc8914.html
*/

class EDEOption extends OptionData {
constructor() {
super();
this.infoCode = 0; // default "other"
this.extraText = '';
}

get code() {
return options.EDE;
}

getSize() {
return 2 + sizeString(this.extraText);
}

write(bw) {
bw.writeU16BE(this.infoCode);
writeStringBW(bw, this.extraText);
return this;
}

read(br) {
this.infoCode = br.readU16BE();
this.extraText = readStringBR(br);
return this;
}
}

/**
* LOCAL Option
* EDNS Local Option
Expand Down Expand Up @@ -6389,6 +6464,7 @@ opts = {
PADDING: PADDINGOption,
CHAIN: CHAINOption,
KEYTAG: KEYTAGOption,
EDE: EDEOption,
LOCAL: LOCALOption,
LOCALSTART: LOCALOption,
LOCALEND: LOCALOption
Expand All @@ -6414,6 +6490,7 @@ optsByVal = {
[options.PADDING]: PADDINGOption,
[options.CHAIN]: CHAINOption,
[options.KEYTAG]: KEYTAGOption,
[options.EDE]: EDEOption,
[options.LOCAL]: LOCALOption,
[options.LOCALSTART]: LOCALOption,
[options.LOCALEND]: LOCALOption
Expand Down Expand Up @@ -6628,6 +6705,8 @@ function readOption(code, br) {
return CHAINOption.read(br);
case options.KEYTAG:
return KEYTAGOption.read(br);
case options.EDE:
return EDEOption.read(br);
default:
if (code >= options.LOCALSTART && code <= options.LOCALEND)
return LOCALOption.read(br);
Expand Down Expand Up @@ -6979,6 +7058,7 @@ exports.TCPKEEPALIVEOption = TCPKEEPALIVEOption;
exports.PADDINGOption = PADDINGOption;
exports.CHAINOption = CHAINOption;
exports.KEYTAGOption = KEYTAGOption;
exports.EDEOption = EDEOption;
exports.LOCALOption = LOCALOption;

exports.AP = AP;
Expand Down
Loading