-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathdns_query.ts
97 lines (88 loc) · 2.53 KB
/
dns_query.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import UDP from 'dgram';
import { DnsMessage } from './dns_message';
import {
ICommandWaitingForReply,
IDnsHeader,
IDnsMessage,
IDnsQuery,
IQuestion
} from './types';
import { Queue } from '../utils/queue';
import { ClassValues, TypeValues } from './enums';
import DnsMessageParser from './parser';
export default class DnsQuery implements IDnsQuery {
domain;
host;
port;
debug;
private client: UDP.Socket;
private commandsQueue: Queue<ICommandWaitingForReply>;
constructor(
domain: string,
host: string,
port: number,
debug: boolean = false
) {
this.domain = domain;
this.host = host;
this.port = port;
this.debug = debug;
this.commandsQueue = new Queue<ICommandWaitingForReply>();
this.client = UDP.createSocket('udp4');
this.client.on('message', (msg) => {
// Close the client as the query is finished
this.client.close();
// Resolve promise
const promise = this.commandsQueue.dequeue();
const dnsMessage = new DnsMessageParser(msg).parse();
if (promise && promise.request.header.id === dnsMessage.header.id) {
promise.resolve(dnsMessage);
} else if (promise) {
promise.reject(
new Error(
`Invalid id ${dnsMessage.header.id} received in response. Expected ${promise.request.header.id}`
)
);
}
if (this.debug) {
console.log(`received> ${msg.toString('hex')}`);
}
});
}
async sendMessage(header?: Partial<IDnsHeader>): Promise<IDnsMessage> {
// Create a DNS request for fetching A records
const questions: IQuestion[] = [
{
name: this.domain,
type: TypeValues.A,
class: ClassValues.IN
}
];
const message = new DnsMessage({ header, questions });
const byteString = message.toByteString();
const messageBuffer = Buffer.from(byteString, 'hex');
// Create a promise that will be resolved when server sends message
const promise = new Promise<IDnsMessage>((res, rej) => {
this.commandsQueue.enqueue({
resolve: res,
reject: rej,
request: message
});
});
// Send the DNS query
this.client.send(messageBuffer, this.port, this.host, (err) => {
if (err) {
this.commandsQueue.dequeue()?.reject(err);
if (this.debug) {
console.error('Some error occurred %s', err);
}
} else {
if (this.debug) {
console.log(`sent> ${byteString}`);
}
}
});
// Wait for promise
return await promise;
}
}