(input)
| 155 | } |
| 156 | |
| 157 | async function handleResolve(input) { |
| 158 | let { host, port } = parseTarget(input); |
| 159 | |
| 160 | const tpPortMatch = host.toLowerCase().match(/\.tp(\d{1,5})\./); |
| 161 | if (tpPortMatch) { |
| 162 | const tpPort = Number(tpPortMatch[1]); |
| 163 | if (tpPort >= 1 && tpPort <= 65535) { |
| 164 | port = tpPort; |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | const bracketedIPv6 = host.startsWith('[') && host.endsWith(']'); |
| 169 | const rawIPv6 = /^[0-9a-fA-F:]+$/.test(host); |
| 170 | if (isIPv4(host) || bracketedIPv6 || rawIPv6) { |
| 171 | const finalHost = rawIPv6 && !bracketedIPv6 ? `[${host}]` : host; |
| 172 | return [`${finalHost}:${port}`]; |
| 173 | } |
| 174 | |
| 175 | const [txtRecords, aRecords, aaaaRecords] = await Promise.all([ |
| 176 | dohQuery(host, 'TXT'), |
| 177 | dohQuery(host, 'A'), |
| 178 | dohQuery(host, 'AAAA') |
| 179 | ]); |
| 180 | |
| 181 | const results = []; |
| 182 | for (const record of txtRecords.filter(item => item.type === 16 && item.data)) { |
| 183 | const value = normalizeTxtValue(record.data); |
| 184 | for (const part of value.split(',')) { |
| 185 | const candidate = part.trim(); |
| 186 | if (candidate) results.push(candidate); |
| 187 | } |
| 188 | } |
| 189 | for (const record of aRecords.filter(item => item.type === 1 && item.data)) { |
| 190 | results.push(`${record.data}:${port}`); |
| 191 | } |
| 192 | for (const record of aaaaRecords.filter(item => item.type === 28 && item.data)) { |
| 193 | results.push(`[${record.data}]:${port}`); |
| 194 | } |
| 195 | |
| 196 | if (!results.length) { |
| 197 | throw new Error('Could not resolve domain'); |
| 198 | } |
| 199 | |
| 200 | return uniqueStrings(results); |
| 201 | } |
| 202 | |
| 203 | function parseTarget(input) { |
| 204 | let host = String(input || '').split('#')[0].trim(); |
no test coverage detected