@homebridge/ciao
Version:
ciao is a RFC 6763 compliant dns-sd library, advertising on multicast dns (RFC 6762) implemented in plain Typescript/JavaScript
109 lines • 4.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryResponse = void 0;
const DNSPacket_1 = require("../coder/DNSPacket");
class QueryResponse {
constructor(knownAnswers) {
this.sharedAnswer = false;
this.dnsPacket = new DNSPacket_1.DNSPacket({ type: 1 /* PacketType.RESPONSE */ });
this.knownAnswers = knownAnswers;
}
asPacket() {
return this.dnsPacket;
}
asString(udpPayloadSize) {
return this.dnsPacket.asLoggingString(udpPayloadSize);
}
containsSharedAnswer() {
return this.sharedAnswer;
}
addAnswer(...records) {
let addedAny = false;
for (const record of records) {
if (this.isKnownAnswer(record)) {
// record is a known answer to the querier
continue;
}
const added = this.dnsPacket.addAnswers(record);
if (added) {
addedAny = true;
if (!record.flushFlag) {
this.sharedAnswer = true;
}
}
}
return addedAny;
}
addAdditional(...records) {
let addedAny = false;
for (const record of records) {
if (this.isKnownAnswer(record)) {
// check if the additional record is a known answer, otherwise there is no need to send it
continue;
}
if (this.dnsPacket.answers.has(record.asString())) {
continue; // if it is already in the answer section, don't include it in additionals
}
const added = this.dnsPacket.addAdditionals(record);
if (added) {
addedAny = true;
}
}
return addedAny;
}
markLegacyUnicastResponse(id, questions) {
// we are dealing with a legacy unicast dns query (RFC 6762 6.7.)
// * MUSTS: response via unicast, repeat query ID, repeat questions (actually it should just be one), clear cache flush bit
// * SHOULDS: ttls should not be greater than 10s as legacy resolvers don't take part in the cache coherency mechanism
this.dnsPacket.id = id;
if (questions) {
this.dnsPacket.addQuestions(...questions);
}
this.dnsPacket.answers.forEach(answers => {
answers.flushFlag = false;
answers.ttl = 10;
});
this.dnsPacket.additionals.forEach(answers => {
answers.flushFlag = false;
answers.ttl = 10;
});
this.dnsPacket.setLegacyUnicastEncoding(true); // legacy unicast also affects the encoder (must not use compression for the SRV record) so we need to tell him
}
markTruncated() {
this.dnsPacket.flags.truncation = true;
}
hasAnswers() {
// we may still have additionals, though there is no reason when answers is empty
// removeKnownAnswer may have removed all answers and only additionals are known.
return this.dnsPacket.answers.size > 0;
}
isKnownAnswer(record) {
if (!this.knownAnswers) {
return false;
}
const knownAnswer = this.knownAnswers.get(record.asString());
// we will still send the response if the known answer has half of the original ttl according to RFC 6762 7.1.
// so only if the ttl is more than half than the original ttl we consider it a valid known answer
return knownAnswer !== undefined && knownAnswer.ttl > record.ttl / 2;
}
static combineResponses(responses, udpPayloadSize) {
for (let i = 0; i < responses.length - 1; i++) {
const current = responses[i];
const currentPacket = current.dnsPacket;
const next = responses[i + 1];
const nextPacket = next.dnsPacket;
if (currentPacket.canBeCombinedWith(nextPacket, udpPayloadSize)) {
// combine the packet with next one
currentPacket.combineWith(nextPacket);
// remove next from the array
responses.splice(i + 1, 1);
// we won't combine the known answer section, with current implementation they will always be the same
current.sharedAnswer = current.sharedAnswer || next.sharedAnswer;
// decrement i, so we check again if the "current" packet can be combined with the packet after "next"
i--;
}
}
}
}
exports.QueryResponse = QueryResponse;
//# sourceMappingURL=QueryResponse.js.map