import { DNSPacket , PacketType } from "../coder/DNSPacket" ; import { Question } from "../coder/Question" ; import { ResourceRecord } from "../coder/ResourceRecord" ; export type RecordAddMethod = ( ... records : ResourceRecord [ ] ) => boolean ; export class QueryResponse { private readonly dnsPacket : DNSPacket ; readonly knownAnswers ? : Map < string , ResourceRecord > ; private sharedAnswer = false ; constructor ( knownAnswers ? ) { this . dnsPacket = new DNSPacket ( { type : PacketType . RESPONSE } ) ; this . knownAnswers = knownAnswers ; } public asPacket ( ) { return this . dnsPacket ; } public asString ( udpPayloadSize ? ) { return this . dnsPacket . asLoggingString ( udpPayloadSize ) ; } public containsSharedAnswer ( ) { return this . sharedAnswer ; } public addAnswer ( ... records ) { let addedAny = false ; for ( const record of records ) { if ( this . isKnownAnswer ( record ) ) { continue ; } const added = this . dnsPacket . addAnswers ( record ) ; if ( added ) { addedAny = true ; if ( ! record . flushFlag ) { this . sharedAnswer = true ; } } } return addedAny ; } public addAdditional ( ... records ) { let addedAny = false ; for ( const record of records ) { if ( this . isKnownAnswer ( record ) ) { continue ; } if ( this . dnsPacket . answers . has ( record . asString ( ) ) ) { continue ; } const added = this . dnsPacket . addAdditionals ( record ) ; if ( added ) { addedAny = true ; } } return addedAny ; } public markLegacyUnicastResponse ( id , questions ? ) { 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 ) ; } public markTruncated ( ) { this . dnsPacket . flags . truncation = true ; } public hasAnswers ( ) { return this . dnsPacket . answers . size > 0 ; } private isKnownAnswer ( record ) { if ( ! this . knownAnswers ) { return false ; } const knownAnswer = this . knownAnswers . get ( record . asString ( ) ) ; return knownAnswer !== undefined && knownAnswer . ttl > record . ttl / 2 ; } public 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 ) ) { currentPacket . combineWith ( nextPacket ) ; responses . splice ( i + 1 , 1 ) ; current . sharedAnswer = current . sharedAnswer || next . sharedAnswer ; i -- ; } } } }