Compare commits

..

No commits in common. "6dad6c5d567097afb9a4f945a09fb68a4d16acb8" and "9dac9184e7b64fe75c4f5ad03674149485e37166" have entirely different histories.

18 changed files with 514 additions and 1327 deletions

View File

@ -1,9 +0,0 @@
root = true
[*]
indent_style = space
indent_size = 3
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

2
lib/listener.d.ts vendored
View File

@ -2,6 +2,6 @@ import { Request } from "./request";
export default class Listener { export default class Listener {
private udp; private udp;
private tcp; private tcp;
constructor(type: "udp" | "tcp", onRequest: (request: Request) => any, host?: string); constructor(type: "udp" | "tcp", onRequest: (request: Request) => any, port: number, host?: string);
close(): void; close(): void;
} }

View File

@ -4,12 +4,12 @@ const net = require("net");
const dgram = require("dgram"); const dgram = require("dgram");
const request_1 = require("./request"); const request_1 = require("./request");
class Listener { class Listener {
constructor(type, onRequest, host = "0.0.0.0") { constructor(type, onRequest, port, host = "0.0.0.0") {
switch (type) { switch (type) {
case "udp": case "udp":
this.udp = dgram.createSocket("udp4"); this.udp = dgram.createSocket("udp4");
this.udp.on("listening", () => { this.udp.on("listening", () => {
console.log(`UDP Server Listening on 53`); console.log(`UDP Server Listening on ${port}`);
}); });
this.udp.on("message", (message, remote) => { this.udp.on("message", (message, remote) => {
let request = new request_1.Request(message, (data) => { let request = new request_1.Request(message, (data) => {
@ -18,7 +18,7 @@ class Listener {
}); });
onRequest(request); onRequest(request);
}); });
this.udp.bind(53, host); this.udp.bind(port, host);
break; break;
case "tcp": case "tcp":
console.log("Not correct implemented"); console.log("Not correct implemented");
@ -50,8 +50,7 @@ class Listener {
} }
}); });
}); });
this.tcp.listen(53, host); this.tcp.listen(port, host);
console.log(`TCP Server Listening on 53`);
break; break;
default: default:
throw new Error("Unknown socket type"); throw new Error("Unknown socket type");

View File

@ -1 +1 @@
{"version":3,"file":"listener.js","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"} {"version":3,"file":"listener.js","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":";;AAAA,2BAA0B;AAC1B,+BAA+B;AAC/B,uCAAoC;AAEpC;IAGG,YAAY,IAAmB,EAAE,SAAoC,EAAE,IAAY,EAAE,OAAe,SAAS;QAC1G,QAAQ,IAAI,EAAE;YACX,KAAK,KAAK;gBACP,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;gBACrC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;oBAC3B,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAA;gBACjD,CAAC,CAAC,CAAA;gBAEF,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBACxC,IAAI,OAAO,GAAG,IAAI,iBAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;wBACzC,wDAAwD;wBACxD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;oBACnD,CAAC,CAAC,CAAA;oBACF,SAAS,CAAC,OAAO,CAAC,CAAC;gBACtB,CAAC,CAAC,CAAA;gBAEF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBACzB,MAAM;YACT,KAAK,KAAK;gBACP,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAA;gBACtC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;oBACpC,IAAI,MAAc,CAAC;oBACnB,IAAI,GAAG,GAAW,CAAC,CAAC;oBACpB,IAAI,OAAO,GAAG,SAAS,CAAC;oBACxB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;wBACxB,IAAI,MAAM,GAAG,CAAC,CAAC;wBACf,IAAI,CAAC,OAAO,EAAE;4BACX,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;4BAC9B,IAAI,MAAM,GAAG,IAAI;gCAAE,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,wCAAwC;4BACpF,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;4BAC/B,MAAM,GAAG,CAAC,CAAC;yBACb;wBAED,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;wBAC7F,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,CAAA;wBAC9C,GAAG,IAAI,IAAI,CAAC;wBACZ,+CAA+C;wBAC/C,IAAI,GAAG,IAAI,MAAM,EAAE;4BAChB,IAAI,OAAO,GAAG,IAAI,iBAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gCACzC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;4BACtB,CAAC,CAAC,CAAA;4BACF,GAAG,GAAG,CAAC,CAAC;4BACR,OAAO,GAAG,SAAS,CAAC;4BACpB,MAAM,GAAG,CAAC,CAAC;4BACX,SAAS,CAAC,OAAO,CAAC,CAAC;yBACrB;oBACJ,CAAC,CAAC,CAAC;gBACN,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC5B,MAAM;YACT;gBACG,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;SAC3C;IACJ,CAAC;IAED,KAAK;QACF,IAAI,IAAI,CAAC,GAAG,EAAE;YACX,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;SACnB;aAAM;YACJ,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;SACnB;IACJ,CAAC;CACH;AAjED,2BAiEC"}

137
lib/request.d.ts vendored
View File

@ -1,49 +1,113 @@
/// <reference types="node" /> /// <reference types="node" />
import { IMessage, IMessageHeader, IMessageQuestion, MessageRecourceRecord, ErrorCodes } from "./types"; import { Message, MessageHeader, MessageQuestion, MessageRecourceRecord, ErrorCodes } from "./types";
export declare function parseHeader(data: Buffer): IMessageHeader; export declare enum QueryTypes {
export declare function parseQuestions(count: number, packet: Buffer): IMessageQuestion[]; /**
export declare function serializeName(name: string): Buffer; * IPv4 address
export declare class Request implements IMessage { */
A = 1,
/**
* Nameserver
*/
NS = 2,
/**
* Obsolete
*/
MD = 3,
/**
* Obsolete
*/
MF = 4,
/**
* Alias
*/
CNAME = 5,
/**
* Start of authority
*/
SOA = 6,
/**
* Experimental
*/
MB = 7,
/**
* Experimental
*/
MG = 8,
/**
* Experimental
*/
MR = 9,
/**
* Experimental
*/
NULL = 10,
/**
* Service description
*/
WKS = 11,
/**
* Reverse entry (inaddr.arpa)
*/
PTR = 12,
/**
* Host information
*/
HINFO = 13,
/**
* Mailbox / Mail-list information
*/
MINFO = 14,
/**
* Mail exchange
*/
MX = 15,
/**
* Text strings
*/
TXT = 16,
/**
* IPv6 address
*/
AAAA = 28,
/**
* SRV records
*/
SRV = 33,
/**
* Request to transfer entire zone
*/
AXFR = 252,
/**
* Request for mailbox related records
*/
MAILA = 254,
/**
* Request for mail agend RRs
*/
MAILB = 253,
/**
* Any class
*/
ANY = 255,
}
export declare function SerializeName(name: string): Buffer;
export declare class Request implements Message {
private sendCallback; private sendCallback;
private max_size;
private _header; private _header;
readonly header: Header; readonly header: MessageHeader;
private _questions; private _questions;
readonly questions: Question[]; readonly questions: MessageQuestion[];
answers: RecourceRecord[]; answers: RecourceRecord[];
authorities: RecourceRecord[]; authorities: RecourceRecord[];
additionals: RecourceRecord[]; additionals: RecourceRecord[];
constructor(packet: Buffer, sendCallback: (packet: Buffer) => any, max_size?: number); constructor(packet: Buffer, sendCallback: (packet: Buffer) => any);
error(error: ErrorCodes): void; error(error: ErrorCodes): void;
noRecursion(): void; noRecursion(): void;
send(): void; send(): void;
serialize(): Buffer; serialize(truncate?: boolean, rcode?: 0 | 1 | 2 | 3 | 4 | 5): Buffer;
} private serializeHeader();
export declare class Header implements IMessageHeader { private serializeQuestion(question);
ID: number; private serializeResourceRecord(record);
QR: 0 | 1;
OPCODE: number;
AA: 0 | 1;
TC: 0 | 1;
RD: 0 | 1;
RA: 0 | 1;
Z: 0 | 1;
AD: 0 | 1;
CD: 0 | 1;
RCODE: ErrorCodes;
QDCOUNT: number;
ANCOUNT: number;
NSCOUNT: number;
ARCOUNT: number;
constructor(header: IMessageHeader);
serialize(): Buffer;
}
export declare class Question implements IMessageQuestion {
QNAME: string;
QTYPE: number;
QCLASS: number;
constructor(question: IMessageQuestion);
serialize(): Buffer;
} }
export declare class RecourceRecord implements MessageRecourceRecord { export declare class RecourceRecord implements MessageRecourceRecord {
/** /**
@ -59,5 +123,4 @@ export declare class RecourceRecord implements MessageRecourceRecord {
TTL: number; TTL: number;
RDATA: Buffer; RDATA: Buffer;
readonly RDLENGTH: number; readonly RDLENGTH: number;
serialize(): Buffer;
} }

View File

@ -2,6 +2,98 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const binary_parser_1 = require("binary-parser"); const binary_parser_1 = require("binary-parser");
const types_1 = require("./types"); const types_1 = require("./types");
const MAX_LABEL_SIZE = 63;
var QueryTypes;
(function (QueryTypes) {
/**
* IPv4 address
*/
QueryTypes[QueryTypes["A"] = 1] = "A";
/**
* Nameserver
*/
QueryTypes[QueryTypes["NS"] = 2] = "NS";
/**
* Obsolete
*/
QueryTypes[QueryTypes["MD"] = 3] = "MD";
/**
* Obsolete
*/
QueryTypes[QueryTypes["MF"] = 4] = "MF";
/**
* Alias
*/
QueryTypes[QueryTypes["CNAME"] = 5] = "CNAME";
/**
* Start of authority
*/
QueryTypes[QueryTypes["SOA"] = 6] = "SOA";
/**
* Experimental
*/
QueryTypes[QueryTypes["MB"] = 7] = "MB";
/**
* Experimental
*/
QueryTypes[QueryTypes["MG"] = 8] = "MG";
/**
* Experimental
*/
QueryTypes[QueryTypes["MR"] = 9] = "MR";
/**
* Experimental
*/
QueryTypes[QueryTypes["NULL"] = 10] = "NULL";
/**
* Service description
*/
QueryTypes[QueryTypes["WKS"] = 11] = "WKS";
/**
* Reverse entry (inaddr.arpa)
*/
QueryTypes[QueryTypes["PTR"] = 12] = "PTR";
/**
* Host information
*/
QueryTypes[QueryTypes["HINFO"] = 13] = "HINFO";
/**
* Mailbox / Mail-list information
*/
QueryTypes[QueryTypes["MINFO"] = 14] = "MINFO";
/**
* Mail exchange
*/
QueryTypes[QueryTypes["MX"] = 15] = "MX";
/**
* Text strings
*/
QueryTypes[QueryTypes["TXT"] = 16] = "TXT";
/**
* IPv6 address
*/
QueryTypes[QueryTypes["AAAA"] = 28] = "AAAA";
/**
* SRV records
*/
QueryTypes[QueryTypes["SRV"] = 33] = "SRV";
/**
* Request to transfer entire zone
*/
QueryTypes[QueryTypes["AXFR"] = 252] = "AXFR";
/**
* Request for mailbox related records
*/
QueryTypes[QueryTypes["MAILA"] = 254] = "MAILA";
/**
* Request for mail agend RRs
*/
QueryTypes[QueryTypes["MAILB"] = 253] = "MAILB";
/**
* Any class
*/
QueryTypes[QueryTypes["ANY"] = 255] = "ANY";
})(QueryTypes = exports.QueryTypes || (exports.QueryTypes = {}));
const headerParser = new binary_parser_1.Parser() const headerParser = new binary_parser_1.Parser()
.endianess("big") .endianess("big")
.uint16("ID") .uint16("ID")
@ -19,15 +111,6 @@ const headerParser = new binary_parser_1.Parser()
.uint16("ANCOUNT") .uint16("ANCOUNT")
.uint16("NSCOUNT") .uint16("NSCOUNT")
.uint16("ARCOUNT"); .uint16("ARCOUNT");
function parseHeader(data) {
try {
return headerParser.parse(data);
}
catch (e) {
throw new Error("Header parsing failed" + e.message);
}
}
exports.parseHeader = parseHeader;
const labelParser = new binary_parser_1.Parser() const labelParser = new binary_parser_1.Parser()
.endianess("big") .endianess("big")
.uint8("dataLength") .uint8("dataLength")
@ -50,21 +133,14 @@ const questionParser = new binary_parser_1.Parser()
.uint16("QTYPE") .uint16("QTYPE")
.uint16("QCLASS"); .uint16("QCLASS");
function parseQuestions(count, packet) { function parseQuestions(count, packet) {
try { return new binary_parser_1.Parser()
return new binary_parser_1.Parser() .endianess("big")
.endianess("big") .array("questions", {
.array("questions", { type: questionParser,
type: questionParser, length: count
length: count }).parse(packet).questions;
}).parse(packet).questions;
}
catch (e) {
throw new Error("Question parsing failed" + e.message);
}
} }
exports.parseQuestions = parseQuestions; function SerializeName(name) {
const MAX_LABEL_SIZE = 63;
function serializeName(name) {
let length = 0; let length = 0;
let parts = name.split("."); let parts = name.split(".");
parts.forEach(e => { parts.forEach(e => {
@ -85,11 +161,10 @@ function serializeName(name) {
data.writeUInt8(0, offset); data.writeUInt8(0, offset);
return data; return data;
} }
exports.serializeName = serializeName; exports.SerializeName = SerializeName;
class Request { class Request {
constructor(packet, sendCallback, max_size = 512) { constructor(packet, sendCallback) {
this.sendCallback = sendCallback; this.sendCallback = sendCallback;
this.max_size = max_size;
this.answers = []; this.answers = [];
this.authorities = []; this.authorities = [];
this.additionals = []; this.additionals = [];
@ -97,17 +172,17 @@ class Request {
packet.copy(headerData, 0, 0, 12); packet.copy(headerData, 0, 0, 12);
let bodyData = Buffer.alloc(packet.length - 12); let bodyData = Buffer.alloc(packet.length - 12);
packet.copy(bodyData, 0, 12, packet.length); packet.copy(bodyData, 0, 12, packet.length);
this._header = new Header(parseHeader(headerData)); this._header = headerParser.parse(headerData);
this._header.AD = 0; this._header.AD = 0;
this._header.RCODE = types_1.ErrorCodes.NoError; this._header.RCODE = types_1.ErrorCodes.NoError;
this._header.RA = this._header.RD; this._header.RA = this._header.RD;
this._questions = parseQuestions(this._header.QDCOUNT, bodyData).map(e => new Question(e)); this._questions = parseQuestions(this._header.QDCOUNT, bodyData);
} }
get header() { get header() {
return Object.assign({}, this._header); return Object.assign({}, this._header);
} }
get questions() { get questions() {
return this._questions.map(e => Object.assign({}, e)); return this._questions.map(e => e);
} }
error(error) { error(error) {
if (this._header.RCODE === types_1.ErrorCodes.NoError) if (this._header.RCODE === types_1.ErrorCodes.NoError)
@ -119,43 +194,37 @@ class Request {
send() { send() {
this.sendCallback(this.serialize()); this.sendCallback(this.serialize());
} }
serialize() { serialize(truncate = false, rcode = 0) {
this._header.AA = 1; this._header.AA = 1;
this._header.ANCOUNT = this.answers.length; this._header.ANCOUNT = this.answers.length;
this._header.ARCOUNT = this.additionals.length; this._header.ARCOUNT = this.additionals.length;
this._header.NSCOUNT = this.authorities.length; this._header.NSCOUNT = this.authorities.length;
this._header.QR = 1; this._header.QR = 1;
let questions = this._questions.map(e => e.serialize()); this._header.RCODE = rcode;
let answers = this.answers.map(e => e.serialize()); let questions = this.questions.map(this.serializeQuestion, this);
let authority = this.authorities.map(e => e.serialize()); let answers = this.answers.map(this.serializeResourceRecord, this);
let additional = this.additionals.map(e => e.serialize()); let authority = this.authorities.map(this.serializeResourceRecord, this);
let length = 12; let additional = this.additionals.map(this.serializeResourceRecord, this);
questions.forEach(e => length += e.length); let questionsByteLength = 0;
answers.forEach(e => length += e.length); questions.forEach(e => questionsByteLength += e.length);
authority.forEach(e => length += e.length); let answersByteLength = 0;
additional.forEach(e => length += e.length); answers.forEach(e => answersByteLength += e.length);
// let questionsByteLength = 0; let authorityByteLength = 0;
// questions.forEach(e => questionsByteLength += e.length); authority.forEach(e => authorityByteLength += e.length);
// let answersByteLength = 0; let additionalByteLength = 0;
// answers.forEach(e => answersByteLength += e.length) additional.forEach(e => additionalByteLength += e.length);
// let authorityByteLength = 0; let length = 12 + questionsByteLength + answersByteLength + authorityByteLength + additionalByteLength; //Header is always 12 byte large
// authority.forEach(e => authorityByteLength += e.length) if (truncate && length > 512) {
// let additionalByteLength = 0;
// additional.forEach(e => additionalByteLength += e.length)
// let length = 12 + questionsByteLength + answersByteLength + authorityByteLength + additionalByteLength; //Header is always 12 byte large
if (length > this.max_size) {
this._header.TC = 1; this._header.TC = 1;
//Will ignore data, that exceeds length //Buffer will ignore data that exeeds the max buffer length
length = this.max_size; length = 512;
} }
let header = this._header.serialize(); let header = this.serializeHeader();
let data = Buffer.alloc(length); let data = Buffer.alloc(length);
let offset = 0; let offset = 0;
let append = (buffer) => { let append = (buffer) => {
if (offset <= length) { buffer.copy(data, offset, 0, buffer.length);
buffer.copy(data, offset, 0, buffer.length); offset += buffer.length;
offset += buffer.length;
}
}; };
append(header); append(header);
questions.forEach(append); questions.forEach(append);
@ -164,55 +233,57 @@ class Request {
additional.forEach(append); additional.forEach(append);
return data; return data;
} }
} serializeHeader() {
exports.Request = Request; let header = this.header;
class Header {
constructor(header) {
for (let k in header) {
this[k] = header[k];
}
}
serialize() {
let data = Buffer.alloc(12); let data = Buffer.alloc(12);
data.writeUInt16BE(this.ID, 0); data.writeUInt16BE(header.ID, 0);
var f = 0x0000; var f = 0x0000;
f = f | (this.QR << 15); f = f | (header.QR << 15);
f = f | (this.OPCODE << 11); f = f | (header.OPCODE << 11);
f = f | (this.AA << 10); f = f | (header.AA << 10);
f = f | (this.TC << 9); f = f | (header.TC << 9);
f = f | (this.RD << 8); f = f | (header.RD << 8);
f = f | (this.RA << 7); f = f | (header.RA << 7);
f = f | (this.Z << 6); f = f | (header.Z << 6);
f = f | (this.AD << 5); f = f | (header.AD << 5);
f = f | (this.CD << 4); f = f | (header.CD << 4);
f = f | this.RCODE; f = f | header.RCODE;
data.writeUInt16BE(f, 2); data.writeUInt16BE(f, 2);
data.writeUInt16BE(this.QDCOUNT, 4); data.writeUInt16BE(header.QDCOUNT, 4);
data.writeUInt16BE(this.ANCOUNT, 6); data.writeUInt16BE(header.ANCOUNT, 6);
data.writeUInt16BE(this.NSCOUNT, 8); data.writeUInt16BE(header.NSCOUNT, 8);
data.writeUInt16BE(this.ARCOUNT, 10); data.writeUInt16BE(header.ARCOUNT, 10);
return data; return data;
} }
} serializeQuestion(question) {
exports.Header = Header; let qname = SerializeName(question.QNAME);
class Question {
constructor(question) {
for (let k in question) {
this[k] = question[k];
}
}
serialize() {
let qname = serializeName(this.QNAME);
let data = Buffer.alloc(qname.length + 4); let data = Buffer.alloc(qname.length + 4);
qname.copy(data, 0, 0, qname.length); qname.copy(data, 0, 0, qname.length);
let offset = qname.length; let offset = qname.length;
data.writeUInt16BE(this.QTYPE, offset); data.writeUInt16BE(question.QTYPE, offset);
offset += 2; offset += 2;
data.writeUInt16BE(this.QCLASS, offset); data.writeUInt16BE(question.QCLASS, offset);
return data;
}
serializeResourceRecord(record) {
// TODO: Implement compression
let name = SerializeName(record.NAME);
let data = Buffer.alloc(name.length + 10 + record.RDLENGTH); // For TYPE, CLASS, TTL, RLENGTH
name.copy(data, 0, 0, name.length);
let offset = name.length;
data.writeUInt16BE(record.TYPE, offset);
offset += 2;
data.writeUInt16BE(record.CLASS, offset);
offset += 2;
data.writeUInt32BE(record.TTL, offset);
offset += 4;
data.writeUInt16BE(record.RDLENGTH, offset);
offset += 2;
record.RDATA.copy(data, offset, 0, record.RDLENGTH);
return data; return data;
} }
} }
exports.Question = Question; exports.Request = Request;
class RecourceRecord { class RecourceRecord {
set TYPE(value) { set TYPE(value) {
if (value < 0 || value > 65535) if (value < 0 || value > 65535)
@ -233,7 +304,6 @@ class RecourceRecord {
set TTL(value) { set TTL(value) {
if (value < 0 || value > 4294967295) if (value < 0 || value > 4294967295)
throw new TypeError("TTL Range: 0 - 4.294.967.295"); throw new TypeError("TTL Range: 0 - 4.294.967.295");
this._TTL = value;
} }
get TTL() { get TTL() {
return this._TTL; return this._TTL;
@ -241,23 +311,6 @@ class RecourceRecord {
get RDLENGTH() { get RDLENGTH() {
return this.RDATA.length; return this.RDATA.length;
} }
serialize() {
// TODO: Implement compression
let name = serializeName(this.NAME);
let data = Buffer.alloc(name.length + 10 + this.RDLENGTH); // For TYPE, CLASS, TTL, RLENGTH
name.copy(data, 0, 0, name.length);
let offset = name.length;
data.writeUInt16BE(this.TYPE, offset);
offset += 2;
data.writeUInt16BE(this.CLASS, offset);
offset += 2;
data.writeUInt32BE(this._TTL, offset);
offset += 4;
data.writeUInt16BE(this.RDLENGTH, offset);
offset += 2;
this.RDATA.copy(data, offset, 0, this.RDLENGTH);
return data;
}
} }
exports.RecourceRecord = RecourceRecord; exports.RecourceRecord = RecourceRecord;
//# sourceMappingURL=request.js.map //# sourceMappingURL=request.js.map

File diff suppressed because one or more lines are too long

1
lib/test.d.ts vendored
View File

@ -1 +0,0 @@
export {};

View File

@ -1,349 +1,6 @@
"use strict"; // const t = `71 15 01 00 00 01 00 00 00 00 00 00 02 64 63 08 73 65 72 76 69 63 65 73 0c 76 69 73 75 61 6c 73 74 75 64 69 6f 03 63 6f 6d 00 00 01 00 01`.split(" ").join("");
Object.defineProperty(exports, "__esModule", { value: true }); // // const tp = Buffer.from(t, "hex")
const chai_1 = require("chai"); // // // import Parse from "./index";
const request_1 = require("./request"); // // import * as util from "util";
const types_1 = require("./types"); // // console.log(util.inspect(Parse(tp), false, 20, true));
function fromHex(data) {
return Buffer.from(data.replace(/\s/g, ""), "hex");
}
describe("parser", function () {
describe("header", function () {
describe("header parser", function () {
let should_templ = {
ID: 0,
QR: 0,
OPCODE: 0,
AA: 0,
TC: 0,
RD: 0,
RA: 0,
Z: 0,
AD: 0,
CD: 0,
RCODE: 0,
QDCOUNT: 0,
ANCOUNT: 0,
ARCOUNT: 0,
NSCOUNT: 0
};
let tests = [
{
name: "Testing ID field",
data: "0001 0000 0000 0000 0000 0000",
fields: {
ID: 1
}
},
{
name: "Testing ID field with max value",
data: "FFFF 0000 0000 0000 0000 0000",
fields: {
ID: 65535
}
},
{
name: "Testing QR field",
data: "0000 8000 0000 0000 0000 0000",
fields: {
QR: 1
}
},
{
name: "Testing OPCODE field value 2",
data: "0000 1000 0000 0000 0000 0000",
fields: {
OPCODE: 2
}
},
{
name: "Testing OPCODE field value 1",
data: "0000 0800 0000 0000 0000 0000",
fields: {
OPCODE: 1
}
},
{
name: "Testing AA field",
data: "0000 0400 0000 0000 0000 0000",
fields: {
AA: 1
}
},
{
name: "Testing TC field",
data: "0000 0200 0000 0000 0000 0000",
fields: {
TC: 1
}
},
{
name: "Testing RD field",
data: "0000 0100 0000 0000 0000 0000",
fields: {
RD: 1
}
},
{
name: "Testing RCODE field",
data: "0000 0002 0000 0000 0000 0000",
fields: {
RCODE: 2
}
},
{
name: "Testing QDCOUNT field max value",
data: "0000 0000 FFFF 0000 0000 0000",
fields: {
QDCOUNT: 65535
}
},
{
name: "Testing ANCOUNT field max value",
data: "0000 0000 0000 FFFF 0000 0000",
fields: {
ANCOUNT: 65535
}
},
{
name: "Testing NSCOUNT field max value",
data: "0000 0000 0000 0000 FFFF 0000",
fields: {
NSCOUNT: 65535
}
},
{
name: "Testing ARCOUNT field max value",
data: "0000 0000 0000 0000 0000 FFFF",
fields: {
ARCOUNT: 65535
}
},
{
name: "Testing all Flags and Values max",
data: "FFFF FFFF FFFF FFFF FFFF FFFF",
fields: {
ID: 65535,
QR: 1,
OPCODE: 15,
AA: 1,
TC: 1,
RD: 1,
RA: 1,
Z: 1,
AD: 1,
CD: 1,
RCODE: 15,
QDCOUNT: 65535,
ANCOUNT: 65535,
NSCOUNT: 65535,
ARCOUNT: 65535
}
}
];
tests.forEach(function (e) {
it(e.name, function () {
let testdata = fromHex(e.data);
let should = Object.assign({}, should_templ, e.fields); // Build in "clone" function
let header = request_1.parseHeader(testdata);
chai_1.assert.hasAllKeys(header, Object.keys(should), "Parsed header is missing some fields");
chai_1.assert.deepEqual(header, should, "Parsed header has not expected values!");
});
});
});
describe("header serializer", function () {
let empty_header = {
ID: 0,
QR: 0,
OPCODE: 0,
AA: 0,
TC: 0,
RD: 0,
RA: 0,
Z: 0,
AD: 0,
CD: 0,
RCODE: 0,
QDCOUNT: 0,
ANCOUNT: 0,
ARCOUNT: 0,
NSCOUNT: 0
};
let tests = [
{
name: "Fill header with 0s",
result: "0000 0000 0000 0000 0000 0000",
values: {}
},
{
name: "Set header id to 5",
result: "0005 0000 0000 0000 0000 0000",
values: {
ID: 5
}
},
{
name: "Set QR",
result: "0000 8000 0000 0000 0000 0000",
values: {
QR: 1
}
},
{
name: "Set OPCODE",
result: "0000 7800 0000 0000 0000 0000",
values: {
OPCODE: 15
}
},
{
name: "Set AA",
result: "0000 0400 0000 0000 0000 0000",
values: {
AA: 1
}
},
{
name: "Set TC",
result: "0000 0200 0000 0000 0000 0000",
values: {
TC: 1
}
},
{
name: "Set RD",
result: "0000 0100 0000 0000 0000 0000",
values: {
RD: 1
}
},
{
name: "Set RA",
result: "0000 0080 0000 0000 0000 0000",
values: {
RA: 1
}
},
{
name: "Set Z",
result: "0000 0040 0000 0000 0000 0000",
values: {
Z: 1
}
},
{
name: "Set AD",
result: "0000 0020 0000 0000 0000 0000",
values: {
AD: 1
}
},
{
name: "Set CD",
result: "0000 0010 0000 0000 0000 0000",
values: {
CD: 1
}
},
{
name: "Set RCODE",
result: "0000 000F 0000 0000 0000 0000",
values: {
RCODE: 15
}
},
{
name: "Set QDCOUNT",
result: "0000 0000 FFFF 0000 0000 0000",
values: {
QDCOUNT: 65535
}
},
{
name: "Set ANCOUNT",
result: "0000 0000 0000 FFFF 0000 0000",
values: {
ANCOUNT: 65535
}
},
{
name: "Set NSCOUNT",
result: "0000 0000 0000 0000 FFFF 0000",
values: {
NSCOUNT: 65535
}
},
{
name: "Set ARCOUNT",
result: "0000 0000 0000 0000 0000 FFFF",
values: {
ARCOUNT: 65535
}
},
];
tests.forEach(function (e) {
it(e.name, function () {
let header = Object.assign({}, empty_header, e.values);
let serialized = new request_1.Header(header).serialize();
chai_1.assert.equal(serialized.toString("hex"), e.result.replace(/\s/g, "").toLowerCase(), "Header serialization failed");
});
});
});
});
describe("question", function () {
let questionData = fromHex("0474 6573 7407 6578 616d 706c 6503 636f 6d00 0001 0001");
let questionObj = {
QNAME: "test.example.com",
QTYPE: types_1.QueryTypes.A,
QCLASS: 1
};
it("check question parser with one question", function () {
let res = request_1.parseQuestions(1, questionData);
let should = [questionObj];
chai_1.assert.deepEqual(res, should, "Question parser does not parse input correctly");
});
it("check question serialization", function () {
let res = new request_1.Question(questionObj).serialize();
chai_1.assert.equal(res.toString("hex"), questionData.toString("hex"), "Query serializer does not serialite correctly");
});
});
it("recource record serialization", function () {
let should = "07 6578616D706C65 03 636f6D 00 0001 0001 00000640 0004 0A000001";
let rr = new request_1.RecourceRecord();
rr.CLASS = 1;
rr.NAME = "example.com";
rr.TTL = 1600;
rr.TYPE = 1;
rr.RDATA = fromHex("0A 00 00 01");
let res = rr.serialize().toString("hex");
chai_1.assert.equal(res, should.replace(/\s/g, "").toLowerCase(), "Serialization not working properly");
});
it("full response serialization", function () {
let reqData = fromHex("E835 0100 0001 0000 0000 0000 07 6578616D706c65 03636F6D 00 0001 0001");
let should = "E835 8580 0001000100000000 076578616D706C6503636F6D0000010001 07 6578616D706C65 03 636F6D 00 0001 0001 0000 0640 0004 0A000001";
let request = new request_1.Request(reqData, () => null);
let rr = new request_1.RecourceRecord();
rr.CLASS = 1;
rr.NAME = "example.com";
rr.TTL = 1600;
rr.TYPE = 1;
rr.RDATA = fromHex("0A 00 00 01");
request.answers.push(rr);
let data = request.serialize();
chai_1.assert.equal(data.toString("hex"), should.replace(/\s/g, "").toLowerCase(), "Whole packet serialization failed");
});
// it("full response serialization benchmark", function () {
// let reqData = fromHex("E835 0100 0001 0000 0000 0000 07 6578616D706c65 03636F6D 00 0001 0001");
// for (let i = 0; i < 100; i++) {
// let request = new Request(reqData, () => null)
// let rr = new RecourceRecord()
// rr.CLASS = 1
// rr.NAME = "example.com"
// rr.TTL = 1600
// rr.TYPE = 1
// rr.RDATA = fromHex("0A 00 00 01")
// request.answers.push(rr)
// request.serialize()
// }
// })
});
//# sourceMappingURL=test.js.map //# sourceMappingURL=test.js.map

File diff suppressed because one or more lines are too long

102
lib/types.d.ts vendored
View File

@ -25,97 +25,7 @@ export declare enum ErrorCodes {
*/ */
Refused = 5, Refused = 5,
} }
export declare enum QueryTypes { export interface MessageHeader {
/**
* IPv4 address
*/
A = 1,
/**
* Nameserver
*/
NS = 2,
/**
* Obsolete
*/
MD = 3,
/**
* Obsolete
*/
MF = 4,
/**
* Alias
*/
CNAME = 5,
/**
* Start of authority
*/
SOA = 6,
/**
* Experimental
*/
MB = 7,
/**
* Experimental
*/
MG = 8,
/**
* Experimental
*/
MR = 9,
/**
* Experimental
*/
NULL = 10,
/**
* Service description
*/
WKS = 11,
/**
* Reverse entry (inaddr.arpa)
*/
PTR = 12,
/**
* Host information
*/
HINFO = 13,
/**
* Mailbox / Mail-list information
*/
MINFO = 14,
/**
* Mail exchange
*/
MX = 15,
/**
* Text strings
*/
TXT = 16,
/**
* IPv6 address
*/
AAAA = 28,
/**
* SRV records
*/
SRV = 33,
/**
* Request to transfer entire zone
*/
AXFR = 252,
/**
* Request for mailbox related records
*/
MAILA = 254,
/**
* Request for mail agend RRs
*/
MAILB = 253,
/**
* Any class
*/
ANY = 255,
}
export interface IMessageHeader {
/** /**
* A 16 bit identifier assigned by the program that * A 16 bit identifier assigned by the program that
* generates any kind of query. This identifier is copied * generates any kind of query. This identifier is copied
@ -163,7 +73,7 @@ export interface IMessageHeader {
/** /**
* Reserved for future usage, must be 0 in all queries * Reserved for future usage, must be 0 in all queries
*/ */
Z: 0 | 1; Z: 0;
AD: 0 | 1; AD: 0 | 1;
CD: 0 | 1; CD: 0 | 1;
/** /**
@ -199,7 +109,7 @@ export interface IMessageHeader {
*/ */
ARCOUNT: number; ARCOUNT: number;
} }
export interface IMessageQuestion { export interface MessageQuestion {
/** /**
* Domain name represented as sequence of labels * Domain name represented as sequence of labels
* Each label consists of a length octed followed * Each label consists of a length octed followed
@ -259,9 +169,9 @@ export interface MessageRecourceRecord {
*/ */
RDATA: Buffer; RDATA: Buffer;
} }
export interface IMessage { export interface Message {
header: IMessageHeader; header: MessageHeader;
questions: IMessageQuestion[]; questions: MessageQuestion[];
answers: MessageRecourceRecord[]; answers: MessageRecourceRecord[];
authorities: MessageRecourceRecord[]; authorities: MessageRecourceRecord[];
additionals: MessageRecourceRecord[]; additionals: MessageRecourceRecord[];

View File

@ -1,5 +1,13 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
// 0 No error condition
// * 1 Format error - unable to interpret query
// * 2 Server failure - internal problem
// * 3 Name error - Only for authorative name server, domain name of query does not exist
// * 4 Not implemented - Request not supported
// * 5 Refused - Nameserver refuses request
// * 6 - 15 Reserved for future usage
// *
var ErrorCodes; var ErrorCodes;
(function (ErrorCodes) { (function (ErrorCodes) {
/** /**
@ -27,95 +35,4 @@ var ErrorCodes;
*/ */
ErrorCodes[ErrorCodes["Refused"] = 5] = "Refused"; ErrorCodes[ErrorCodes["Refused"] = 5] = "Refused";
})(ErrorCodes = exports.ErrorCodes || (exports.ErrorCodes = {})); })(ErrorCodes = exports.ErrorCodes || (exports.ErrorCodes = {}));
var QueryTypes;
(function (QueryTypes) {
/**
* IPv4 address
*/
QueryTypes[QueryTypes["A"] = 1] = "A";
/**
* Nameserver
*/
QueryTypes[QueryTypes["NS"] = 2] = "NS";
/**
* Obsolete
*/
QueryTypes[QueryTypes["MD"] = 3] = "MD";
/**
* Obsolete
*/
QueryTypes[QueryTypes["MF"] = 4] = "MF";
/**
* Alias
*/
QueryTypes[QueryTypes["CNAME"] = 5] = "CNAME";
/**
* Start of authority
*/
QueryTypes[QueryTypes["SOA"] = 6] = "SOA";
/**
* Experimental
*/
QueryTypes[QueryTypes["MB"] = 7] = "MB";
/**
* Experimental
*/
QueryTypes[QueryTypes["MG"] = 8] = "MG";
/**
* Experimental
*/
QueryTypes[QueryTypes["MR"] = 9] = "MR";
/**
* Experimental
*/
QueryTypes[QueryTypes["NULL"] = 10] = "NULL";
/**
* Service description
*/
QueryTypes[QueryTypes["WKS"] = 11] = "WKS";
/**
* Reverse entry (inaddr.arpa)
*/
QueryTypes[QueryTypes["PTR"] = 12] = "PTR";
/**
* Host information
*/
QueryTypes[QueryTypes["HINFO"] = 13] = "HINFO";
/**
* Mailbox / Mail-list information
*/
QueryTypes[QueryTypes["MINFO"] = 14] = "MINFO";
/**
* Mail exchange
*/
QueryTypes[QueryTypes["MX"] = 15] = "MX";
/**
* Text strings
*/
QueryTypes[QueryTypes["TXT"] = 16] = "TXT";
/**
* IPv6 address
*/
QueryTypes[QueryTypes["AAAA"] = 28] = "AAAA";
/**
* SRV records
*/
QueryTypes[QueryTypes["SRV"] = 33] = "SRV";
/**
* Request to transfer entire zone
*/
QueryTypes[QueryTypes["AXFR"] = 252] = "AXFR";
/**
* Request for mailbox related records
*/
QueryTypes[QueryTypes["MAILA"] = 254] = "MAILA";
/**
* Request for mail agend RRs
*/
QueryTypes[QueryTypes["MAILB"] = 253] = "MAILB";
/**
* Any class
*/
QueryTypes[QueryTypes["ANY"] = 255] = "ANY";
})(QueryTypes = exports.QueryTypes || (exports.QueryTypes = {}));
//# sourceMappingURL=types.js.map //# sourceMappingURL=types.js.map

View File

@ -1 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AAAA,IAAY,UA8BX;AA9BD,WAAY,UAAU;IACnB;;OAEG;IACH,iDAAW,CAAA;IAEX;;OAEG;IACH,yDAAW,CAAA;IAEX;;OAEG;IACH,6DAAa,CAAA;IAEb;;OAEG;IACH,qDAAS,CAAA;IAET;;OAEG;IACH,+DAAc,CAAA;IAEd;;OAEG;IACH,iDAAO,CAAA;AACV,CAAC,EA9BW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QA8BrB;AAED,IAAY,UA8GX;AA9GD,WAAY,UAAU;IACnB;;OAEG;IACH,qCAAQ,CAAA;IAER;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,6CAAY,CAAA;IAEZ;;OAEG;IACH,yCAAU,CAAA;IAEV;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,uCAAS,CAAA;IAET;;OAEG;IACH,4CAAW,CAAA;IAEX;;OAEG;IACH,0CAAU,CAAA;IAEV;;OAEG;IACH,0CAAU,CAAA;IAEV;;OAEG;IACH,8CAAY,CAAA;IAEZ;;OAEG;IACH,8CAAY,CAAA;IAEZ;;OAEG;IACH,wCAAS,CAAA;IAET;;OAEG;IACH,0CAAU,CAAA;IAEV;;OAEG;IACH,4CAAW,CAAA;IAEX;;OAEG;IACH,0CAAU,CAAA;IAEV;;OAEG;IACH,6CAAW,CAAA;IAEX;;OAEG;IACH,+CAAY,CAAA;IAEZ;;OAEG;IACH,+CAAY,CAAA;IAEZ;;OAEG;IACH,2CAAU,CAAA;AACb,CAAC,EA9GW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QA8GrB"} {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AACA,uBAAuB;AACvB,kDAAkD;AAClD,8CAA8C;AAC9C,kGAAkG;AAClG,0DAA0D;AAC1D,0DAA0D;AAC1D,wCAAwC;AACxC,WAAW;AACX,IAAY,UA8BX;AA9BD,WAAY,UAAU;IACnB;;OAEG;IACH,iDAAW,CAAA;IAEX;;OAEG;IACH,yDAAW,CAAA;IAEX;;OAEG;IACH,6DAAa,CAAA;IAEb;;OAEG;IACH,qDAAS,CAAA;IAET;;OAEG;IACH,+DAAc,CAAA;IAEd;;OAEG;IACH,iDAAO,CAAA;AACV,CAAC,EA9BW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QA8BrB"}

View File

@ -8,19 +8,13 @@
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"watch": "tsc --watch", "watch": "tsc --watch",
"test": "mocha src/test.ts --require ts-node/register", "test": "nodemon lib/test.js"
"testwatch": "mocha src/test.ts --require ts-node/register --watch --watch-extensions ts"
}, },
"devDependencies": { "devDependencies": {
"@types/binary-parser": "^1.3.0", "@types/binary-parser": "^1.3.0",
"@types/chai": "^4.1.3",
"@types/mocha": "^5.2.0",
"@types/node": "^10.0.8", "@types/node": "^10.0.8",
"chai": "^4.1.2",
"mocha": "^5.1.1",
"nodemon": "^1.17.4", "nodemon": "^1.17.4",
"typescript": "^2.8.3", "typescript": "^2.8.3"
"ts-node": "^6.0.3"
}, },
"dependencies": { "dependencies": {
"binary-parser": "^1.3.2" "binary-parser": "^1.3.2"

View File

@ -2,16 +2,15 @@ import * as net from "net"
import * as dgram from "dgram"; import * as dgram from "dgram";
import { Request } from "./request"; import { Request } from "./request";
import { PassThrough } from "stream"; import { PassThrough } from "stream";
export default class Listener { export default class Listener {
private udp: dgram.Socket private udp: dgram.Socket
private tcp: net.Server private tcp: net.Server
constructor(type: "udp" | "tcp", onRequest: (request: Request) => any, host: string = "0.0.0.0") { constructor(type: "udp" | "tcp", onRequest: (request: Request) => any, port: number, host: string = "0.0.0.0") {
switch (type) { switch (type) {
case "udp": case "udp":
this.udp = dgram.createSocket("udp4") this.udp = dgram.createSocket("udp4")
this.udp.on("listening", () => { this.udp.on("listening", () => {
console.log(`UDP Server Listening on 53`) console.log(`UDP Server Listening on ${port}`)
}) })
this.udp.on("message", (message, remote) => { this.udp.on("message", (message, remote) => {
@ -22,7 +21,7 @@ export default class Listener {
onRequest(request); onRequest(request);
}) })
this.udp.bind(53, host) this.udp.bind(port, host)
break; break;
case "tcp": case "tcp":
console.log("Not correct implemented") console.log("Not correct implemented")
@ -54,8 +53,7 @@ export default class Listener {
} }
}); });
}); });
this.tcp.listen(53, host); this.tcp.listen(port, host);
console.log(`TCP Server Listening on 53`)
break; break;
default: default:
throw new Error("Unknown socket type") throw new Error("Unknown socket type")

View File

@ -1,7 +1,121 @@
import { Parser } from "binary-parser" import { Parser } from "binary-parser"
import { IMessage, IMessageHeader, IMessageQuestion, MessageRecourceRecord, ErrorCodes } from "./types" import { Message, MessageHeader, MessageQuestion, MessageRecourceRecord, ErrorCodes } from "./types"
const headerParser: Parser = new Parser() const MAX_LABEL_SIZE = 63;
export enum QueryTypes {
/**
* IPv4 address
*/
A = 0x01,
/**
* Nameserver
*/
NS = 0x02, // nameserver
/**
* Obsolete
*/
MD = 0x03, // obsolete
/**
* Obsolete
*/
MF = 0x04, // obsolete
/**
* Alias
*/
CNAME = 0x05, // alias
/**
* Start of authority
*/
SOA = 0x06, // start of authority
/**
* Experimental
*/
MB = 0x07, // experimental
/**
* Experimental
*/
MG = 0x08, // experimental
/**
* Experimental
*/
MR = 0x09, // experimental
/**
* Experimental
*/
NULL = 0x0A, // experimental null RR
/**
* Service description
*/
WKS = 0x0B, // service description
/**
* Reverse entry (inaddr.arpa)
*/
PTR = 0x0C, // reverse entry (inaddr.arpa)
/**
* Host information
*/
HINFO = 0x0D, // host information
/**
* Mailbox / Mail-list information
*/
MINFO = 0x0E, // mailbox or mail list information
/**
* Mail exchange
*/
MX = 0x0F, // mail exchange
/**
* Text strings
*/
TXT = 0x10, // text strings
/**
* IPv6 address
*/
AAAA = 0x1C, // ipv6 address
/**
* SRV records
*/
SRV = 0x21, // srv records
/**
* Request to transfer entire zone
*/
AXFR = 0xFC, // request to transfer entire zone
/**
* Request for mailbox related records
*/
MAILA = 0xFE, // request for mailbox related records
/**
* Request for mail agend RRs
*/
MAILB = 0xFD, // request for mail agent RRs
/**
* Any class
*/
ANY = 0xFF, // any class
}
const headerParser = new Parser()
.endianess("big") .endianess("big")
.uint16("ID") .uint16("ID")
.bit1("QR") .bit1("QR")
@ -19,14 +133,6 @@ const headerParser: Parser = new Parser()
.uint16("NSCOUNT") .uint16("NSCOUNT")
.uint16("ARCOUNT") .uint16("ARCOUNT")
export function parseHeader(data: Buffer): IMessageHeader {
try {
return <any>headerParser.parse(data);
} catch (e) {
throw new Error("Header parsing failed" + e.message)
}
}
const labelParser = new Parser() const labelParser = new Parser()
.endianess("big") .endianess("big")
.uint8("dataLength") .uint8("dataLength")
@ -50,22 +156,16 @@ const questionParser = new Parser()
.uint16("QTYPE") .uint16("QTYPE")
.uint16("QCLASS") .uint16("QCLASS")
export function parseQuestions(count: number, packet: Buffer): IMessageQuestion[] { function parseQuestions(count: number, packet: Buffer): MessageQuestion[] {
try { return <any>new Parser()
return <any>new Parser() .endianess("big")
.endianess("big") .array("questions", {
.array("questions", { type: questionParser,
type: questionParser, length: count
length: count }).parse(packet).questions;
}).parse(packet).questions;
} catch (e) {
throw new Error("Question parsing failed" + e.message)
}
} }
const MAX_LABEL_SIZE = 63; export function SerializeName(name: string) {
export function serializeName(name: string) {
let length = 0; let length = 0;
let parts = name.split("."); let parts = name.split(".");
parts.forEach(e => { parts.forEach(e => {
@ -87,32 +187,33 @@ export function serializeName(name: string) {
return data; return data;
} }
export class Request implements IMessage { export class Request implements Message {
private _header: Header; private _header: MessageHeader;
get header() { get header() {
return Object.assign({}, this._header); return Object.assign({}, this._header);
} }
private _questions: Question[]; private _questions: MessageQuestion[];
get questions() { get questions() {
return this._questions.map(e => Object.assign({}, e)); return this._questions.map(e => e);
} }
answers: RecourceRecord[] = []; answers: RecourceRecord[] = [];
authorities: RecourceRecord[] = []; authorities: RecourceRecord[] = [];
additionals: RecourceRecord[] = []; additionals: RecourceRecord[] = [];
constructor(packet: Buffer, private sendCallback: (packet: Buffer) => any, private max_size = 512) { constructor(packet: Buffer, private sendCallback: (packet: Buffer) => any) {
let headerData = Buffer.alloc(12); let headerData = Buffer.alloc(12);
packet.copy(headerData, 0, 0, 12); packet.copy(headerData, 0, 0, 12);
let bodyData = Buffer.alloc(packet.length - 12); let bodyData = Buffer.alloc(packet.length - 12);
packet.copy(bodyData, 0, 12, packet.length); packet.copy(bodyData, 0, 12, packet.length);
this._header = new Header(parseHeader(headerData)); this._header = <any>headerParser.parse(headerData);
this._header.AD = 0; this._header.AD = 0;
this._header.RCODE = ErrorCodes.NoError; this._header.RCODE = ErrorCodes.NoError;
this._header.RA = this._header.RD; this._header.RA = this._header.RD;
this._questions = parseQuestions(this._header.QDCOUNT, bodyData).map(e => new Question(e));
this._questions = parseQuestions(this._header.QDCOUNT, bodyData);
} }
error(error: ErrorCodes) { error(error: ErrorCodes) {
@ -128,53 +229,50 @@ export class Request implements IMessage {
this.sendCallback(this.serialize()); this.sendCallback(this.serialize());
} }
serialize() { serialize(truncate: boolean = false, rcode: 0 | 1 | 2 | 3 | 4 | 5 = 0) {
this._header.AA = 1; this._header.AA = 1;
this._header.ANCOUNT = this.answers.length; this._header.ANCOUNT = this.answers.length;
this._header.ARCOUNT = this.additionals.length; this._header.ARCOUNT = this.additionals.length;
this._header.NSCOUNT = this.authorities.length; this._header.NSCOUNT = this.authorities.length;
this._header.QR = 1; this._header.QR = 1;
let questions = this._questions.map(e => e.serialize()) this._header.RCODE = rcode;
let answers = this.answers.map(e => e.serialize())
let authority = this.authorities.map(e => e.serialize())
let additional = this.additionals.map(e => e.serialize())
let length = 12; let questions = this.questions.map(this.serializeQuestion, this)
questions.forEach(e => length += e.length); let answers = this.answers.map(this.serializeResourceRecord, this)
answers.forEach(e => length += e.length) let authority = this.authorities.map(this.serializeResourceRecord, this)
authority.forEach(e => length += e.length) let additional = this.additionals.map(this.serializeResourceRecord, this)
additional.forEach(e => length += e.length)
// let questionsByteLength = 0;
// questions.forEach(e => questionsByteLength += e.length);
// let answersByteLength = 0; let questionsByteLength = 0;
// answers.forEach(e => answersByteLength += e.length) questions.forEach(e => questionsByteLength += e.length);
// let authorityByteLength = 0; let answersByteLength = 0;
// authority.forEach(e => authorityByteLength += e.length) answers.forEach(e => answersByteLength += e.length)
// let additionalByteLength = 0; let authorityByteLength = 0;
// additional.forEach(e => additionalByteLength += e.length) authority.forEach(e => authorityByteLength += e.length)
// let length = 12 + questionsByteLength + answersByteLength + authorityByteLength + additionalByteLength; //Header is always 12 byte large let additionalByteLength = 0;
additional.forEach(e => additionalByteLength += e.length)
if (length > this.max_size) { let length = 12 + questionsByteLength + answersByteLength + authorityByteLength + additionalByteLength; //Header is always 12 byte large
if (truncate && length > 512) {
this._header.TC = 1; this._header.TC = 1;
//Will ignore data, that exceeds length //Buffer will ignore data that exeeds the max buffer length
length = this.max_size; length = 512;
} }
let header = this._header.serialize();
let header = this.serializeHeader()
let data = Buffer.alloc(length) let data = Buffer.alloc(length)
let offset = 0; let offset = 0;
let append = (buffer: Buffer) => { let append = (buffer: Buffer) => {
if (offset <= length) { buffer.copy(data, offset, 0, buffer.length)
buffer.copy(data, offset, 0, buffer.length) offset += buffer.length;
offset += buffer.length;
}
} }
append(header) append(header)
questions.forEach(append) questions.forEach(append)
answers.forEach(append) answers.forEach(append)
@ -182,73 +280,57 @@ export class Request implements IMessage {
additional.forEach(append) additional.forEach(append)
return data; return data;
} }
}
export class Header implements IMessageHeader { private serializeHeader() {
ID: number; let header = this.header;
QR: 0 | 1;
OPCODE: number
AA: 0 | 1;
TC: 0 | 1;
RD: 0 | 1;
RA: 0 | 1;
Z: 0 | 1;
AD: 0 | 1;
CD: 0 | 1;
RCODE: ErrorCodes;
QDCOUNT: number;
ANCOUNT: number;
NSCOUNT: number;
ARCOUNT: number;
constructor(header: IMessageHeader) {
for (let k in header) {
this[k] = header[k];
}
}
serialize() {
let data = Buffer.alloc(12); let data = Buffer.alloc(12);
data.writeUInt16BE(this.ID, 0); data.writeUInt16BE(header.ID, 0);
var f = 0x0000; var f = 0x0000;
f = f | (this.QR << 15); f = f | (header.QR << 15);
f = f | (this.OPCODE << 11); f = f | (header.OPCODE << 11);
f = f | (this.AA << 10); f = f | (header.AA << 10);
f = f | (this.TC << 9); f = f | (header.TC << 9);
f = f | (this.RD << 8); f = f | (header.RD << 8);
f = f | (this.RA << 7); f = f | (header.RA << 7);
f = f | (this.Z << 6); f = f | (header.Z << 6);
f = f | (this.AD << 5); f = f | (header.AD << 5);
f = f | (this.CD << 4); f = f | (header.CD << 4);
f = f | this.RCODE; f = f | header.RCODE;
data.writeUInt16BE(f, 2); data.writeUInt16BE(f, 2);
data.writeUInt16BE(this.QDCOUNT, 4)
data.writeUInt16BE(this.ANCOUNT, 6) data.writeUInt16BE(header.QDCOUNT, 4)
data.writeUInt16BE(this.NSCOUNT, 8) data.writeUInt16BE(header.ANCOUNT, 6)
data.writeUInt16BE(this.ARCOUNT, 10) data.writeUInt16BE(header.NSCOUNT, 8)
data.writeUInt16BE(header.ARCOUNT, 10)
return data; return data;
} }
}
export class Question implements IMessageQuestion { private serializeQuestion(question: MessageQuestion) {
QNAME: string; let qname = SerializeName(question.QNAME);
QTYPE: number;
QCLASS: number;
constructor(question: IMessageQuestion) {
for (let k in question) {
this[k] = question[k]
}
}
serialize() {
let qname = serializeName(this.QNAME);
let data = Buffer.alloc(qname.length + 4); let data = Buffer.alloc(qname.length + 4);
qname.copy(data, 0, 0, qname.length); qname.copy(data, 0, 0, qname.length);
let offset = qname.length; let offset = qname.length;
data.writeUInt16BE(this.QTYPE, offset); data.writeUInt16BE(question.QTYPE, offset);
offset += 2; offset += 2;
data.writeUInt16BE(this.QCLASS, offset); data.writeUInt16BE(question.QCLASS, offset);
return data;
}
private serializeResourceRecord(record: MessageRecourceRecord) {
// TODO: Implement compression
let name = SerializeName(record.NAME);
let data = Buffer.alloc(name.length + 10 + record.RDLENGTH) // For TYPE, CLASS, TTL, RLENGTH
name.copy(data, 0, 0, name.length);
let offset = name.length;
data.writeUInt16BE(record.TYPE, offset)
offset += 2
data.writeUInt16BE(record.CLASS, offset)
offset += 2
data.writeUInt32BE(record.TTL, offset)
offset += 4
data.writeUInt16BE(record.RDLENGTH, offset)
offset += 2
record.RDATA.copy(data, offset, 0, record.RDLENGTH)
return data; return data;
} }
} }
@ -283,7 +365,6 @@ export class RecourceRecord implements MessageRecourceRecord {
private _TTL: number; private _TTL: number;
set TTL(value) { set TTL(value) {
if (value < 0 || value > 4294967295) throw new TypeError("TTL Range: 0 - 4.294.967.295") if (value < 0 || value > 4294967295) throw new TypeError("TTL Range: 0 - 4.294.967.295")
this._TTL = value;
} }
get TTL() { get TTL() {
@ -295,22 +376,4 @@ export class RecourceRecord implements MessageRecourceRecord {
get RDLENGTH() { get RDLENGTH() {
return this.RDATA.length; return this.RDATA.length;
} }
public serialize() {
// TODO: Implement compression
let name = serializeName(this.NAME);
let data = Buffer.alloc(name.length + 10 + this.RDLENGTH) // For TYPE, CLASS, TTL, RLENGTH
name.copy(data, 0, 0, name.length);
let offset = name.length;
data.writeUInt16BE(this.TYPE, offset)
offset += 2
data.writeUInt16BE(this.CLASS, offset)
offset += 2
data.writeUInt32BE(this._TTL, offset)
offset += 4
data.writeUInt16BE(this.RDLENGTH, offset)
offset += 2
this.RDATA.copy(data, offset, 0, this.RDLENGTH)
return data;
}
} }

View File

@ -1,359 +1,5 @@
import { assert, expect } from "chai"; // const t = `71 15 01 00 00 01 00 00 00 00 00 00 02 64 63 08 73 65 72 76 69 63 65 73 0c 76 69 73 75 61 6c 73 74 75 64 69 6f 03 63 6f 6d 00 00 01 00 01`.split(" ").join("");
// // const tp = Buffer.from(t, "hex")
import { parseHeader, Header, parseQuestions, Question, RecourceRecord, Request } from "./request" // // // import Parse from "./index";
import { IMessageHeader, IMessageQuestion, QueryTypes } from "./types"; // // import * as util from "util";
// // console.log(util.inspect(Parse(tp), false, 20, true));
function fromHex(data: string) {
return Buffer.from(data.replace(/\s/g, ""), "hex");
}
describe("parser", function () {
describe("header", function () {
describe("header parser", function () {
let should_templ: IMessageHeader = {
ID: 0,
QR: 0,
OPCODE: 0,
AA: 0,
TC: 0,
RD: 0,
RA: 0,
Z: 0,
AD: 0,
CD: 0,
RCODE: 0,
QDCOUNT: 0,
ANCOUNT: 0,
ARCOUNT: 0,
NSCOUNT: 0
}
let tests: { name: string, data: string, fields: Partial<IMessageHeader> }[] = [
{
name: "Testing ID field",
data: "0001 0000 0000 0000 0000 0000",
fields: {
ID: 1
}
},
{
name: "Testing ID field with max value",
data: "FFFF 0000 0000 0000 0000 0000",
fields: {
ID: 65535
}
},
{
name: "Testing QR field",
data: "0000 8000 0000 0000 0000 0000",
fields: {
QR: 1
}
},
{
name: "Testing OPCODE field value 2",
data: "0000 1000 0000 0000 0000 0000",
fields: {
OPCODE: 2
}
},
{
name: "Testing OPCODE field value 1",
data: "0000 0800 0000 0000 0000 0000",
fields: {
OPCODE: 1
}
},
{
name: "Testing AA field",
data: "0000 0400 0000 0000 0000 0000",
fields: {
AA: 1
}
},
{
name: "Testing TC field",
data: "0000 0200 0000 0000 0000 0000",
fields: {
TC: 1
}
},
{
name: "Testing RD field",
data: "0000 0100 0000 0000 0000 0000",
fields: {
RD: 1
}
},
{
name: "Testing RCODE field",
data: "0000 0002 0000 0000 0000 0000",
fields: {
RCODE: 2
}
},
{
name: "Testing QDCOUNT field max value",
data: "0000 0000 FFFF 0000 0000 0000",
fields: {
QDCOUNT: 65535
}
},
{
name: "Testing ANCOUNT field max value",
data: "0000 0000 0000 FFFF 0000 0000",
fields: {
ANCOUNT: 65535
}
},
{
name: "Testing NSCOUNT field max value",
data: "0000 0000 0000 0000 FFFF 0000",
fields: {
NSCOUNT: 65535
}
},
{
name: "Testing ARCOUNT field max value",
data: "0000 0000 0000 0000 0000 FFFF",
fields: {
ARCOUNT: 65535
}
},
{
name: "Testing all Flags and Values max",
data: "FFFF FFFF FFFF FFFF FFFF FFFF",
fields: {
ID: 65535,
QR: 1,
OPCODE: 15,
AA: 1,
TC: 1,
RD: 1,
RA: 1,
Z: 1,
AD: 1,
CD: 1,
RCODE: 15,
QDCOUNT: 65535,
ANCOUNT: 65535,
NSCOUNT: 65535,
ARCOUNT: 65535
}
}
]
tests.forEach(function (e) {
it(e.name, function () {
let testdata = fromHex(e.data)
let should: IMessageHeader = Object.assign({}, should_templ, e.fields) // Build in "clone" function
let header = parseHeader(testdata);
assert.hasAllKeys(header, Object.keys(should), "Parsed header is missing some fields")
assert.deepEqual(header, should, "Parsed header has not expected values!")
})
})
})
describe("header serializer", function () {
let empty_header: IMessageHeader = {
ID: 0,
QR: 0,
OPCODE: 0,
AA: 0,
TC: 0,
RD: 0,
RA: 0,
Z: 0,
AD: 0,
CD: 0,
RCODE: 0,
QDCOUNT: 0,
ANCOUNT: 0,
ARCOUNT: 0,
NSCOUNT: 0
}
let tests: { name: string, result: string, values: Partial<IMessageHeader> }[] = [
{
name: "Fill header with 0s",
result: "0000 0000 0000 0000 0000 0000",
values: {}
},
{
name: "Set header id to 5",
result: "0005 0000 0000 0000 0000 0000",
values: {
ID: 5
}
},
{
name: "Set QR",
result: "0000 8000 0000 0000 0000 0000",
values: {
QR: 1
}
},
{
name: "Set OPCODE",
result: "0000 7800 0000 0000 0000 0000",
values: {
OPCODE: 15
}
},
{
name: "Set AA",
result: "0000 0400 0000 0000 0000 0000",
values: {
AA: 1
}
},
{
name: "Set TC",
result: "0000 0200 0000 0000 0000 0000",
values: {
TC: 1
}
},
{
name: "Set RD",
result: "0000 0100 0000 0000 0000 0000",
values: {
RD: 1
}
},
{
name: "Set RA",
result: "0000 0080 0000 0000 0000 0000",
values: {
RA: 1
}
},
{
name: "Set Z",
result: "0000 0040 0000 0000 0000 0000",
values: {
Z: 1
}
},
{
name: "Set AD",
result: "0000 0020 0000 0000 0000 0000",
values: {
AD: 1
}
},
{
name: "Set CD",
result: "0000 0010 0000 0000 0000 0000",
values: {
CD: 1
}
},
{
name: "Set RCODE",
result: "0000 000F 0000 0000 0000 0000",
values: {
RCODE: 15
}
},
{
name: "Set QDCOUNT",
result: "0000 0000 FFFF 0000 0000 0000",
values: {
QDCOUNT: 65535
}
},
{
name: "Set ANCOUNT",
result: "0000 0000 0000 FFFF 0000 0000",
values: {
ANCOUNT: 65535
}
},
{
name: "Set NSCOUNT",
result: "0000 0000 0000 0000 FFFF 0000",
values: {
NSCOUNT: 65535
}
},
{
name: "Set ARCOUNT",
result: "0000 0000 0000 0000 0000 FFFF",
values: {
ARCOUNT: 65535
}
},
]
tests.forEach(function (e) {
it(e.name, function () {
let header = Object.assign({}, empty_header, e.values)
let serialized = new Header(header).serialize();
assert.equal(serialized.toString("hex"), e.result.replace(/\s/g, "").toLowerCase(), "Header serialization failed");
})
})
})
})
describe("question", function () {
let questionData = fromHex("0474 6573 7407 6578 616d 706c 6503 636f 6d00 0001 0001")
let questionObj = {
QNAME: "test.example.com",
QTYPE: QueryTypes.A,
QCLASS: 1
}
it("check question parser with one question", function () {
let res = parseQuestions(1, questionData)
let should: IMessageQuestion[] = [questionObj]
assert.deepEqual(res, should, "Question parser does not parse input correctly")
})
it("check question serialization", function () {
let res = new Question(questionObj).serialize()
assert.equal(res.toString("hex"), questionData.toString("hex"), "Query serializer does not serialite correctly");
})
})
it("recource record serialization", function () {
let should = "07 6578616D706C65 03 636f6D 00 0001 0001 00000640 0004 0A000001"
let rr = new RecourceRecord()
rr.CLASS = 1
rr.NAME = "example.com"
rr.TTL = 1600
rr.TYPE = 1
rr.RDATA = fromHex("0A 00 00 01")
let res = rr.serialize().toString("hex")
assert.equal(res, should.replace(/\s/g, "").toLowerCase(), "Serialization not working properly")
})
it("full response serialization", function () {
let reqData = fromHex("E835 0100 0001 0000 0000 0000 07 6578616D706c65 03636F6D 00 0001 0001");
let should = "E835 8580 0001000100000000 076578616D706C6503636F6D0000010001 07 6578616D706C65 03 636F6D 00 0001 0001 0000 0640 0004 0A000001"
let request = new Request(reqData, () => null)
let rr = new RecourceRecord()
rr.CLASS = 1
rr.NAME = "example.com"
rr.TTL = 1600
rr.TYPE = 1
rr.RDATA = fromHex("0A 00 00 01")
request.answers.push(rr)
let data = request.serialize()
assert.equal(data.toString("hex"), should.replace(/\s/g, "").toLowerCase(), "Whole packet serialization failed")
})
// it("full response serialization benchmark", function () {
// let reqData = fromHex("E835 0100 0001 0000 0000 0000 07 6578616D706c65 03636F6D 00 0001 0001");
// for (let i = 0; i < 100; i++) {
// let request = new Request(reqData, () => null)
// let rr = new RecourceRecord()
// rr.CLASS = 1
// rr.NAME = "example.com"
// rr.TTL = 1600
// rr.TYPE = 1
// rr.RDATA = fromHex("0A 00 00 01")
// request.answers.push(rr)
// request.serialize()
// }
// })
})

View File

@ -1,3 +1,12 @@
// 0 No error condition
// * 1 Format error - unable to interpret query
// * 2 Server failure - internal problem
// * 3 Name error - Only for authorative name server, domain name of query does not exist
// * 4 Not implemented - Request not supported
// * 5 Refused - Nameserver refuses request
// * 6 - 15 Reserved for future usage
// *
export enum ErrorCodes { export enum ErrorCodes {
/** /**
* No error * No error
@ -30,119 +39,7 @@ export enum ErrorCodes {
Refused Refused
} }
export enum QueryTypes { export interface MessageHeader {
/**
* IPv4 address
*/
A = 0x01,
/**
* Nameserver
*/
NS = 0x02, // nameserver
/**
* Obsolete
*/
MD = 0x03, // obsolete
/**
* Obsolete
*/
MF = 0x04, // obsolete
/**
* Alias
*/
CNAME = 0x05, // alias
/**
* Start of authority
*/
SOA = 0x06, // start of authority
/**
* Experimental
*/
MB = 0x07, // experimental
/**
* Experimental
*/
MG = 0x08, // experimental
/**
* Experimental
*/
MR = 0x09, // experimental
/**
* Experimental
*/
NULL = 0x0A, // experimental null RR
/**
* Service description
*/
WKS = 0x0B, // service description
/**
* Reverse entry (inaddr.arpa)
*/
PTR = 0x0C, // reverse entry (inaddr.arpa)
/**
* Host information
*/
HINFO = 0x0D, // host information
/**
* Mailbox / Mail-list information
*/
MINFO = 0x0E, // mailbox or mail list information
/**
* Mail exchange
*/
MX = 0x0F, // mail exchange
/**
* Text strings
*/
TXT = 0x10, // text strings
/**
* IPv6 address
*/
AAAA = 0x1C, // ipv6 address
/**
* SRV records
*/
SRV = 0x21, // srv records
/**
* Request to transfer entire zone
*/
AXFR = 0xFC, // request to transfer entire zone
/**
* Request for mailbox related records
*/
MAILA = 0xFE, // request for mailbox related records
/**
* Request for mail agend RRs
*/
MAILB = 0xFD, // request for mail agent RRs
/**
* Any class
*/
ANY = 0xFF, // any class
}
export interface IMessageHeader {
/** /**
* A 16 bit identifier assigned by the program that * A 16 bit identifier assigned by the program that
* generates any kind of query. This identifier is copied * generates any kind of query. This identifier is copied
@ -196,7 +93,7 @@ export interface IMessageHeader {
/** /**
* Reserved for future usage, must be 0 in all queries * Reserved for future usage, must be 0 in all queries
*/ */
Z: 0 | 1; Z: 0;
AD: 0 | 1; AD: 0 | 1;
@ -239,7 +136,7 @@ export interface IMessageHeader {
*/ */
ARCOUNT: number; ARCOUNT: number;
} }
export interface IMessageQuestion { export interface MessageQuestion {
/** /**
* Domain name represented as sequence of labels * Domain name represented as sequence of labels
* Each label consists of a length octed followed * Each label consists of a length octed followed
@ -306,9 +203,9 @@ export interface MessageRecourceRecord {
*/ */
RDATA: Buffer; RDATA: Buffer;
} }
export interface IMessage { export interface Message {
header: IMessageHeader; header: MessageHeader;
questions: IMessageQuestion[]; questions: MessageQuestion[];
answers: MessageRecourceRecord[]; answers: MessageRecourceRecord[];
authorities: MessageRecourceRecord[]; authorities: MessageRecourceRecord[];
additionals: MessageRecourceRecord[]; additionals: MessageRecourceRecord[];