-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathutils.ts
143 lines (122 loc) · 3.62 KB
/
utils.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { TypeValues } from './enums';
import { IDnsHeader, IQuestion, IResourceRecord } from './types';
/**
* Given a domain string, convert it into valid byte string.
*
* @param {string} domain
* @returns {string}
*/
function parseDomainToByteString(
domain: string,
isIp: boolean = false
): string {
let encodedDomain = '';
// Parsing domain IP, e.g. 8.8.8.8
if (isIp) {
const domainSplitArr = domain.split('.');
// Add length
encodedDomain += domainSplitArr.length.toString(16).padStart(2, '0');
// Add hex for each integer
domainSplitArr.forEach((label) => {
encodedDomain += parseInt(label).toString(16).padStart(2, '0');
});
return encodedDomain;
}
domain.split('.').forEach((label) => {
// Add the length of the label
encodedDomain += label.length.toString(16).padStart(2, '0');
// Convert label into a byte string
encodedDomain += label
.split('')
.map((char) => {
return char.charCodeAt(0).toString(16).padStart(2, '0');
})
.join('');
});
// Add terminating character
encodedDomain += (0).toString(16).padStart(2, '0');
return encodedDomain;
}
/**
* This function returns a valid byte string for a given header.
*
* @param {IDnsHeader} header
* @returns {string}
*/
function convertHeaderToByteString(header: IDnsHeader): string {
let output = '';
const radix = 16;
// Add header id
output += header.id.toString(radix).padStart(4, '0');
// Add flags
output += (
(header.qr << 15) +
(header.opcode << 11) +
(header.aa << 10) +
(header.tc << 9) +
(header.rd << 8) +
(header.ra << 7) +
(header.z << 4) +
header.rCode
)
.toString(radix)
.padStart(4, '0');
// Question count, Answer count, Authority count and Additional count
output += header.qdCount.toString(radix).padStart(4, '0');
output += header.anCount.toString(radix).padStart(4, '0');
output += header.nsCount.toString(radix).padStart(4, '0');
output += header.arCount.toString(radix).padStart(4, '0');
return output;
}
/**
* This function converts the given list of questions into a valid byte string.
*
* @param {IQuestion[]} questions
* @returns {string}
*/
function convertQuestionsToByteString(questions: IQuestion[]): string {
let output = '';
questions.forEach((question) => {
output += parseDomainToByteString(question.name);
output += question.type.toString(16).padStart(4, '0');
output += question.class.toString(16).padStart(4, '0');
});
return output;
}
/**
* This function converts a given Resource Record (RR) into a valid byte string.
*
* @param {IResourceRecord[]} arr
* @returns {string}
*/
function convertResourceRecordToByteString(arr: IResourceRecord[]): string {
let output = '';
arr.forEach((rr) => {
output += parseDomainToByteString(rr.name);
output += rr.type.toString(16).padStart(4, '0');
output += rr.class.toString(16).padStart(4, '0');
output += rr.ttl.toString(16).padStart(8, '0');
output += rr.dataLength.toString(16).padStart(4, '0');
// For A record the data represents a valid ip
// Example - 8.8.4.4
if (rr.type === TypeValues.A) {
output += parseDomainToByteString(rr.data, true);
}
// For NS record, the data is a domain string
// Example - dns.google.com
else if (rr.type === TypeValues.NS) {
output += parseDomainToByteString(rr.data);
}
// Otherwise the data is having the byte string already
else {
output += rr.data;
}
});
return output;
}
export {
convertHeaderToByteString,
parseDomainToByteString,
convertQuestionsToByteString,
convertResourceRecordToByteString
};