diff options
Diffstat (limited to 'netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm')
-rw-r--r-- | netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm b/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm new file mode 100644 index 000000000..f0539fccb --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm @@ -0,0 +1,297 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DNSPacket']; + +const { utils: Cu } = Components; + +Cu.import('resource://gre/modules/Services.jsm'); + +Cu.import('resource://gre/modules/DataReader.jsm'); +Cu.import('resource://gre/modules/DataWriter.jsm'); +Cu.import('resource://gre/modules/DNSRecord.jsm'); +Cu.import('resource://gre/modules/DNSResourceRecord.jsm'); + +const DEBUG = true; + +function debug(msg) { + Services.console.logStringMessage('DNSPacket: ' + msg); +} + +let DNS_PACKET_SECTION_TYPES = [ + 'QD', // Question + 'AN', // Answer + 'NS', // Authority + 'AR' // Additional +]; + +/** + * DNS Packet Structure + * ************************************************* + * + * Header + * ====== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * |<==================== ID =====================>| + * |QR|<== OP ===>|AA|TC|RD|RA|UN|AD|CD|<== RC ===>| + * |<================== QDCOUNT ==================>| + * |<================== ANCOUNT ==================>| + * |<================== NSCOUNT ==================>| + * |<================== ARCOUNT ==================>| + * ------------------------------------------------- + * + * ID: 2-Bytes + * FLAGS: 2-Bytes + * - QR: 1-Bit + * - OP: 4-Bits + * - AA: 1-Bit + * - TC: 1-Bit + * - RD: 1-Bit + * - RA: 1-Bit + * - UN: 1-Bit + * - AD: 1-Bit + * - CD: 1-Bit + * - RC: 4-Bits + * QDCOUNT: 2-Bytes + * ANCOUNT: 2-Bytes + * NSCOUNT: 2-Bytes + * ARCOUNT: 2-Bytes + * + * + * Data + * ==== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * |<???=============== QD[...] ===============???>| + * |<???=============== AN[...] ===============???>| + * |<???=============== NS[...] ===============???>| + * |<???=============== AR[...] ===============???>| + * ------------------------------------------------- + * + * QD: ??-Bytes + * AN: ??-Bytes + * NS: ??-Bytes + * AR: ??-Bytes + * + * + * Question Record + * =============== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * |<???================ NAME =================???>| + * |<=================== TYPE ====================>| + * |<=================== CLASS ===================>| + * ------------------------------------------------- + * + * NAME: ??-Bytes + * TYPE: 2-Bytes + * CLASS: 2-Bytes + * + * + * Resource Record + * =============== + * + * 00 4-Bytes 31 + * ------------------------------------------------- + * |00|02|04|06|08|10|12|14|16|18|20|22|24|26|28|30| + * ------------------------------------------------- + * |<???================ NAME =================???>| + * |<======= TYPE ========>|<======= CLASS =======>| + * |<==================== TTL ====================>| + * |<====== DATALEN ======>|<???==== DATA =====???>| + * ------------------------------------------------- + * + * NAME: ??-Bytes + * TYPE: 2-Bytes + * CLASS: 2-Bytes + * DATALEN: 2-Bytes + * DATA: ??-Bytes (Specified By DATALEN) + */ +class DNSPacket { + constructor() { + this._flags = _valueToFlags(0x0000); + this._records = {}; + + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + this._records[sectionType] = []; + }); + } + + static parse(data) { + let reader = new DataReader(data); + if (reader.getValue(2) !== 0x0000) { + throw new Error('Packet must start with 0x0000'); + } + + let packet = new DNSPacket(); + packet._flags = _valueToFlags(reader.getValue(2)); + + let recordCounts = {}; + + // Parse the record counts. + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + recordCounts[sectionType] = reader.getValue(2); + }); + + // Parse the actual records. + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + let recordCount = recordCounts[sectionType]; + for (let i = 0; i < recordCount; i++) { + if (sectionType === 'QD') { + packet.addRecord(sectionType, + DNSRecord.parseFromPacketReader(reader)); + } + + else { + packet.addRecord(sectionType, + DNSResourceRecord.parseFromPacketReader(reader)); + } + } + }); + + if (!reader.eof) { + DEBUG && debug('Did not complete parsing packet data'); + } + + return packet; + } + + getFlag(flag) { + return this._flags[flag]; + } + + setFlag(flag, value) { + this._flags[flag] = value; + } + + addRecord(sectionType, record) { + this._records[sectionType].push(record); + } + + getRecords(sectionTypes, recordType) { + let records = []; + + sectionTypes.forEach((sectionType) => { + records = records.concat(this._records[sectionType]); + }); + + if (!recordType) { + return records; + } + + return records.filter(r => r.recordType === recordType); + } + + serialize() { + let writer = new DataWriter(); + + // Write leading 0x0000 (2 bytes) + writer.putValue(0x0000, 2); + + // Write `flags` (2 bytes) + writer.putValue(_flagsToValue(this._flags), 2); + + // Write lengths of record sections (2 bytes each) + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + writer.putValue(this._records[sectionType].length, 2); + }); + + // Write records + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + this._records[sectionType].forEach((record) => { + writer.putBytes(record.serialize()); + }); + }); + + return writer.data; + } + + toJSON() { + return JSON.stringify(this.toJSONObject()); + } + + toJSONObject() { + let result = {flags: this._flags}; + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + result[sectionType] = []; + + let records = this._records[sectionType]; + records.forEach((record) => { + result[sectionType].push(record.toJSONObject()); + }); + }); + + return result; + } +} + +/** + * @private + */ +function _valueToFlags(value) { + return { + QR: (value & 0x8000) >> 15, + OP: (value & 0x7800) >> 11, + AA: (value & 0x0400) >> 10, + TC: (value & 0x0200) >> 9, + RD: (value & 0x0100) >> 8, + RA: (value & 0x0080) >> 7, + UN: (value & 0x0040) >> 6, + AD: (value & 0x0020) >> 5, + CD: (value & 0x0010) >> 4, + RC: (value & 0x000f) >> 0 + }; +} + +/** + * @private + */ +function _flagsToValue(flags) { + let value = 0x0000; + + value += flags.QR & 0x01; + + value <<= 4; + value += flags.OP & 0x0f; + + value <<= 1; + value += flags.AA & 0x01; + + value <<= 1; + value += flags.TC & 0x01; + + value <<= 1; + value += flags.RD & 0x01; + + value <<= 1; + value += flags.RA & 0x01; + + value <<= 1; + value += flags.UN & 0x01; + + value <<= 1; + value += flags.AD & 0x01; + + value <<= 1; + value += flags.CD & 0x01; + + value <<= 4; + value += flags.RC & 0x0f; + + return value; +} |