mirror of
https://github.com/parnic/node-intellicenter.git
synced 2025-06-17 02:21:53 -05:00
WIP: DNS response parsing
This commit is contained in:
39
dist/dns.d.ts
vendored
Normal file
39
dist/dns.d.ts
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
export declare const TypeTxt = 16;
|
||||
export declare const TypePtr = 12;
|
||||
export declare const TypeSrv = 33;
|
||||
export declare const TypeA = 1;
|
||||
export declare class Question {
|
||||
name: string;
|
||||
type: number;
|
||||
class: number;
|
||||
endOffset: number;
|
||||
constructor(_name: string, _type: number, _cls: number, _endOffset: number);
|
||||
}
|
||||
export interface Record {
|
||||
interface: string | undefined;
|
||||
type: number;
|
||||
ttlSeconds: number;
|
||||
name: string;
|
||||
endOffset: number;
|
||||
}
|
||||
export interface PtrRecord extends Record {
|
||||
interface: "ptr";
|
||||
domain: string;
|
||||
}
|
||||
export interface TxtRecord extends Record {
|
||||
interface: "txt";
|
||||
text: string;
|
||||
}
|
||||
export interface SrvRecord extends Record {
|
||||
interface: "srv";
|
||||
priority: number;
|
||||
weight: number;
|
||||
port: number;
|
||||
target: string;
|
||||
}
|
||||
export interface ARecord extends Record {
|
||||
interface: "a";
|
||||
address: string;
|
||||
}
|
||||
export declare function GetDNSQuestion(msg: Buffer, startOffset: number): Question;
|
||||
export declare function GetDNSAnswer(msg: Buffer, startOffset: number): Record | undefined;
|
146
dist/dns.js
vendored
Normal file
146
dist/dns.js
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
export const TypeTxt = 16;
|
||||
export const TypePtr = 12;
|
||||
export const TypeSrv = 33;
|
||||
export const TypeA = 1;
|
||||
export class Question {
|
||||
name = "";
|
||||
type = 0;
|
||||
class = 0;
|
||||
endOffset = 0;
|
||||
constructor(_name, _type, _cls, _endOffset) {
|
||||
this.name = _name;
|
||||
this.type = _type;
|
||||
this.class = _cls;
|
||||
this.endOffset = _endOffset;
|
||||
}
|
||||
}
|
||||
class dnsAnswerParseResult {
|
||||
name = "";
|
||||
endOffset = 0;
|
||||
}
|
||||
function parseDnsName(msg, startOffset) {
|
||||
const result = new dnsAnswerParseResult();
|
||||
let offset = startOffset;
|
||||
while (offset < msg.length) {
|
||||
const nextByte = msg.readUInt8(offset);
|
||||
if (nextByte === 0) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
const pointerMask = (1 << 6) | (1 << 7);
|
||||
if ((nextByte & pointerMask) === pointerMask) {
|
||||
offset++;
|
||||
const pointerOffset = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const nestedResult = parseDnsName(msg, pointerOffset);
|
||||
if (result.name.length > 0 && nestedResult.name.length > 0) {
|
||||
result.name += ".";
|
||||
}
|
||||
result.name += nestedResult.name;
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
const segment = msg.toString("ascii", offset, offset + nextByte);
|
||||
offset += nextByte;
|
||||
if (result.name.length > 0 && segment.length > 0) {
|
||||
result.name += ".";
|
||||
}
|
||||
result.name += segment;
|
||||
}
|
||||
result.endOffset = offset;
|
||||
return result;
|
||||
}
|
||||
export function GetDNSQuestion(msg, startOffset) {
|
||||
let offset = startOffset;
|
||||
const parsedResult = parseDnsName(msg, offset);
|
||||
offset = parsedResult.endOffset;
|
||||
const type = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const cls = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
return new Question(parsedResult.name, type, cls, offset);
|
||||
}
|
||||
export function GetDNSAnswer(msg, startOffset) {
|
||||
let offset = startOffset;
|
||||
const parsedResult = parseDnsName(msg, offset);
|
||||
offset = parsedResult.endOffset;
|
||||
const type = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
offset += 2; // don't care about "class" of answer
|
||||
const ttlSeconds = msg.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
const remainingDataLength = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
switch (type) {
|
||||
case TypePtr: {
|
||||
const domainResult = parseDnsName(msg, offset);
|
||||
const ret = {
|
||||
interface: "ptr",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
domain: domainResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
case TypeTxt: {
|
||||
const textResult = parseDnsName(msg, offset);
|
||||
const ret = {
|
||||
interface: "txt",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
text: textResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
case TypeSrv: {
|
||||
const priority = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const weight = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const port = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const targetResult = parseDnsName(msg, offset);
|
||||
offset = targetResult.endOffset;
|
||||
const ret = {
|
||||
interface: "srv",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset,
|
||||
priority: priority,
|
||||
weight: weight,
|
||||
port: port,
|
||||
target: targetResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
case TypeA: {
|
||||
const o1 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o2 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o3 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o4 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const address = `${o1.toString()}.${o2.toString()}.${o3.toString()}.${o4.toString()}`;
|
||||
const ret = {
|
||||
interface: "a",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
address: address,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
//# sourceMappingURL=dns.js.map
|
1
dist/dns.js.map
vendored
Normal file
1
dist/dns.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"dns.js","sourceRoot":"","sources":["../dns.ts"],"names":[],"mappings":"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"}
|
41
dist/finder.js
vendored
41
dist/finder.js
vendored
@ -2,6 +2,7 @@ import * as dgram from "dgram";
|
||||
import { EventEmitter } from "events";
|
||||
import { setTimeout as setTimeoutSync } from "timers";
|
||||
import os from "os";
|
||||
import { GetDNSAnswer, GetDNSQuestion } from "./dns.js";
|
||||
export class FindUnits extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
@ -103,6 +104,46 @@ export class FindUnits extends EventEmitter {
|
||||
}
|
||||
foundServer(msg, remote) {
|
||||
// debugFind("found something");
|
||||
let flags = 0;
|
||||
if (msg.length > 4) {
|
||||
flags = msg.readUInt16BE(2);
|
||||
const answerBit = 1 << 15;
|
||||
if ((flags & answerBit) === 0) {
|
||||
// received query, don't process as answer
|
||||
return;
|
||||
}
|
||||
}
|
||||
let nextAnswerOffset = 12;
|
||||
let questions = 0;
|
||||
if (msg.length >= 6) {
|
||||
questions = msg.readUInt16BE(4);
|
||||
let nextQuestionOffset = 12;
|
||||
for (let i = 0; i < questions; i++) {
|
||||
const parsed = GetDNSQuestion(msg, nextQuestionOffset);
|
||||
nextQuestionOffset = parsed.endOffset;
|
||||
}
|
||||
nextAnswerOffset = nextQuestionOffset;
|
||||
}
|
||||
let answers = 0;
|
||||
if (msg.length >= 8) {
|
||||
answers = msg.readUInt16BE(6);
|
||||
}
|
||||
if (answers > 0) {
|
||||
for (let i = 0; i < answers; i++) {
|
||||
if (msg.length <= nextAnswerOffset) {
|
||||
console.error(`while inspecting dns answers, expected message length > ${nextAnswerOffset.toString()} but it was ${msg.length.toString()}`);
|
||||
break;
|
||||
}
|
||||
const answer = GetDNSAnswer(msg, nextAnswerOffset);
|
||||
if (!answer) {
|
||||
break;
|
||||
}
|
||||
nextAnswerOffset = answer.endOffset;
|
||||
if (answer.interface === "a") {
|
||||
console.log("a record:", answer);
|
||||
}
|
||||
}
|
||||
}
|
||||
const str = msg.toString();
|
||||
console.log(str);
|
||||
if (msg.length >= 40) {
|
||||
|
2
dist/finder.js.map
vendored
2
dist/finder.js.map
vendored
File diff suppressed because one or more lines are too long
198
dns.ts
Normal file
198
dns.ts
Normal file
@ -0,0 +1,198 @@
|
||||
export const TypeTxt = 16;
|
||||
export const TypePtr = 12;
|
||||
export const TypeSrv = 33;
|
||||
export const TypeA = 1;
|
||||
|
||||
export class Question {
|
||||
public name = "";
|
||||
public type = 0;
|
||||
public class = 0;
|
||||
public endOffset = 0;
|
||||
|
||||
constructor(_name: string, _type: number, _cls: number, _endOffset: number) {
|
||||
this.name = _name;
|
||||
this.type = _type;
|
||||
this.class = _cls;
|
||||
this.endOffset = _endOffset;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Record {
|
||||
interface: string | undefined;
|
||||
type: number;
|
||||
ttlSeconds: number;
|
||||
name: string;
|
||||
endOffset: number;
|
||||
}
|
||||
|
||||
export interface PtrRecord extends Record {
|
||||
interface: "ptr";
|
||||
domain: string;
|
||||
}
|
||||
|
||||
export interface TxtRecord extends Record {
|
||||
interface: "txt";
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface SrvRecord extends Record {
|
||||
interface: "srv";
|
||||
priority: number;
|
||||
weight: number;
|
||||
port: number;
|
||||
target: string;
|
||||
}
|
||||
|
||||
export interface ARecord extends Record {
|
||||
interface: "a";
|
||||
address: string;
|
||||
}
|
||||
|
||||
class dnsAnswerParseResult {
|
||||
public name = "";
|
||||
public endOffset = 0;
|
||||
}
|
||||
|
||||
function parseDnsName(msg: Buffer, startOffset: number): dnsAnswerParseResult {
|
||||
const result = new dnsAnswerParseResult();
|
||||
let offset = startOffset;
|
||||
|
||||
while (offset < msg.length) {
|
||||
const nextByte = msg.readUInt8(offset);
|
||||
if (nextByte === 0) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
|
||||
const pointerMask = (1 << 6) | (1 << 7);
|
||||
if ((nextByte & pointerMask) === pointerMask) {
|
||||
offset++;
|
||||
const pointerOffset = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const nestedResult = parseDnsName(msg, pointerOffset);
|
||||
if (result.name.length > 0 && nestedResult.name.length > 0) {
|
||||
result.name += ".";
|
||||
}
|
||||
result.name += nestedResult.name;
|
||||
break;
|
||||
}
|
||||
|
||||
offset++;
|
||||
const segment = msg.toString("ascii", offset, offset + nextByte);
|
||||
offset += nextByte;
|
||||
if (result.name.length > 0 && segment.length > 0) {
|
||||
result.name += ".";
|
||||
}
|
||||
result.name += segment;
|
||||
}
|
||||
|
||||
result.endOffset = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function GetDNSQuestion(msg: Buffer, startOffset: number): Question {
|
||||
let offset = startOffset;
|
||||
const parsedResult = parseDnsName(msg, offset);
|
||||
offset = parsedResult.endOffset;
|
||||
const type = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const cls = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
return new Question(parsedResult.name, type, cls, offset);
|
||||
}
|
||||
|
||||
export function GetDNSAnswer(
|
||||
msg: Buffer,
|
||||
startOffset: number,
|
||||
): Record | undefined {
|
||||
let offset = startOffset;
|
||||
const parsedResult = parseDnsName(msg, offset);
|
||||
offset = parsedResult.endOffset;
|
||||
|
||||
const type = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
offset += 2; // don't care about "class" of answer
|
||||
const ttlSeconds = msg.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
const remainingDataLength = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
|
||||
switch (type) {
|
||||
case TypePtr: {
|
||||
const domainResult = parseDnsName(msg, offset);
|
||||
const ret: PtrRecord = {
|
||||
interface: "ptr",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
domain: domainResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
case TypeTxt: {
|
||||
const textResult = parseDnsName(msg, offset);
|
||||
const ret: TxtRecord = {
|
||||
interface: "txt",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
text: textResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
case TypeSrv: {
|
||||
const priority = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const weight = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const port = msg.readUInt16BE(offset);
|
||||
offset += 2;
|
||||
const targetResult = parseDnsName(msg, offset);
|
||||
offset = targetResult.endOffset;
|
||||
|
||||
const ret: SrvRecord = {
|
||||
interface: "srv",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset,
|
||||
priority: priority,
|
||||
weight: weight,
|
||||
port: port,
|
||||
target: targetResult.name,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
case TypeA: {
|
||||
const o1 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o2 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o3 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const o4 = msg.readUInt8(offset);
|
||||
offset++;
|
||||
const address = `${o1.toString()}.${o2.toString()}.${o3.toString()}.${o4.toString()}`;
|
||||
|
||||
const ret: ARecord = {
|
||||
interface: "a",
|
||||
type: type,
|
||||
ttlSeconds: ttlSeconds,
|
||||
name: parsedResult.name,
|
||||
endOffset: offset + remainingDataLength,
|
||||
address: address,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
51
finder.ts
51
finder.ts
@ -3,6 +3,7 @@ import { Socket } from "dgram";
|
||||
import { EventEmitter } from "events";
|
||||
import { setTimeout as setTimeoutSync } from "timers";
|
||||
import os from "os";
|
||||
import { GetDNSAnswer, GetDNSQuestion } from "./dns.js";
|
||||
|
||||
export class FindUnits extends EventEmitter {
|
||||
constructor() {
|
||||
@ -119,6 +120,56 @@ export class FindUnits extends EventEmitter {
|
||||
foundServer(msg: Buffer, remote: dgram.RemoteInfo) {
|
||||
// debugFind("found something");
|
||||
|
||||
let flags = 0;
|
||||
if (msg.length > 4) {
|
||||
flags = msg.readUInt16BE(2);
|
||||
const answerBit = 1 << 15;
|
||||
if ((flags & answerBit) === 0) {
|
||||
// received query, don't process as answer
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let nextAnswerOffset = 12;
|
||||
|
||||
let questions = 0;
|
||||
if (msg.length >= 6) {
|
||||
questions = msg.readUInt16BE(4);
|
||||
let nextQuestionOffset = 12;
|
||||
for (let i = 0; i < questions; i++) {
|
||||
const parsed = GetDNSQuestion(msg, nextQuestionOffset);
|
||||
nextQuestionOffset = parsed.endOffset;
|
||||
}
|
||||
|
||||
nextAnswerOffset = nextQuestionOffset;
|
||||
}
|
||||
|
||||
let answers = 0;
|
||||
if (msg.length >= 8) {
|
||||
answers = msg.readUInt16BE(6);
|
||||
}
|
||||
|
||||
if (answers > 0) {
|
||||
for (let i = 0; i < answers; i++) {
|
||||
if (msg.length <= nextAnswerOffset) {
|
||||
console.error(
|
||||
`while inspecting dns answers, expected message length > ${nextAnswerOffset.toString()} but it was ${msg.length.toString()}`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
const answer = GetDNSAnswer(msg, nextAnswerOffset);
|
||||
if (!answer) {
|
||||
break;
|
||||
}
|
||||
|
||||
nextAnswerOffset = answer.endOffset;
|
||||
if (answer.interface === "a") {
|
||||
console.log("a record:", answer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const str = msg.toString();
|
||||
console.log(str);
|
||||
|
||||
|
Reference in New Issue
Block a user