Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can be added DNS check for Adguard DoT,DoH.... (other self hosted DNS projects) or allow use dig - simple bash? #175

Open
ghostersk opened this issue Mar 22, 2025 · 2 comments

Comments

@ghostersk
Copy link

Hello, as mentioned on Discord, I was trying to test a Adguard DNS if it is resolving using Dns over HTTPS

  • i could not find any mentions how i can test Adguard DoT with curl, as curl what works on Google DNS is not available for adguard.
  • On the end I made long Javascript what does request via https and just checks if response contains domain name ( cannot get the IP lookup work in the hex output)

Could be added function to query DNS servers to see if the resolution works?
Not just simple DNS but encrypted DNS too.
I found some simple GO project what claim to do it, as you use GO it may be easier to add then working with JS or adding Curl to the monitoring as option.
github.com/ameshkov/dnslookup/blob/master/main.go

Just I am not sure if this Go project would work with something like adguard, what probably people would test as self hosted solution. Possibly there are more variants of selfhosted DoT and DoH servers what may act differently.

I was able to test the dns using dig
dig +short @adguardhome.example.com +https=/dns-query/client-id231 google.com A
This way it could be possible to check also if the IP changed, if there is check for the ip value

  • the /dns-query/client-id231 is specific to Adguard Home - if clients are set
  • otherwise it would be ommited or just /dns-query

This is example of code I use for checking if my DoH Adguard server works:

const url_link = "https://adguardhome.example.com/dns-query/client-id231";

const domain_name = "bbc.com";

function encodeDomainToDNSQuery(domain) {
    function domainToDNSFormat(domain) {
        let parts = domain.split('.');
        let buffer = [];

        parts.forEach(part => {
            buffer.push(part.length);
            buffer.push(...part.split('').map(c => c.charCodeAt(0)));
        });

        buffer.push(0); // Null terminator for the domain name

        return new Uint8Array(buffer);
    }

    function buildDNSQuery(domainBuffer) {
        let header = new Uint8Array([
            0xAB, 0xCD, // Transaction ID (randomized)
            0x01, 0x00, // Standard query with recursion
            0x00, 0x01, // One question
            0x00, 0x00, // Zero answer records
            0x00, 0x00, // Zero authority records
            0x00, 0x00  // Zero additional records
        ]);

        let questionTypeClass = new Uint8Array([
            0x00, 0x01, // Query Type: A (IPv4 Address)
            0x00, 0x01  // Query Class: IN (Internet)
        ]);

        return new Uint8Array([...header, ...domainBuffer, ...questionTypeClass]);
    }

    function base64Encode(arrayBuffer) {
        const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
        let result = '';
        let i = 0;

        while (i < arrayBuffer.length) {
            const byte1 = arrayBuffer[i] || 0;
            const byte2 = arrayBuffer[i + 1] || 0;
            const byte3 = arrayBuffer[i + 2] || 0;

            const group = (byte1 << 16) + (byte2 << 8) + byte3;
            result += base64Chars[(group >> 18) & 0x3F];
            result += base64Chars[(group >> 12) & 0x3F];
            result += (i + 1 < arrayBuffer.length) ? base64Chars[(group >> 6) & 0x3F] : '';
            result += (i + 2 < arrayBuffer.length) ? base64Chars[group & 0x3F] : '';

            i += 3;
        }

        return result;
    }

    let domainBuffer = domainToDNSFormat(domain);
    let dnsQuery = buildDNSQuery(domainBuffer);
    return base64Encode(dnsQuery);
}

const url_check = `${url_link}?dns=${encodeDomainToDNSQuery(domain_name)}`;
const res = await request({
    url: url_check,
    method: 'GET',
    headers: { 'accept': 'application/dns-message' }
});

// Convert res.data to hexdump
let hexDump = '';
let asciiDump = '';
for (let i = 0; i < res.data.length; i++) {
    const byte = res.data.charCodeAt(i) & 0xFF;
    const hex = byte.toString(16).padStart(2, '0');
    hexDump += hex + ' ';
    asciiDump += (byte >= 32 && byte <= 126) ? String.fromCharCode(byte) : '.';
    if ((i + 1) % 16 === 0) {
        hexDump = '';
        asciiDump = '';
    }
}

// Extract domain from question section (starting at byte 12)
let pos = 12;
let domain = '';
while (pos < res.data.length && res.data.charCodeAt(pos) !== 0) {
    const len = res.data.charCodeAt(pos);
    pos++;
    for (let i = 0; i < len; i++) {
        domain += res.data[pos];
        pos++;
    }
    domain += '.';
}
domain = domain.slice(0, -1);

// Skip QTYPE (2 bytes) and QCLASS (2 bytes) after domain
pos += 4;

// Check if it’s working (contains domain and has an IP)
let fullText = '';
for (let i = 0; i < res.data.length; i++) {
    const byte = res.data.charCodeAt(i) & 0xFF;
    fullText += (byte >= 32 && byte <= 126) ? String.fromCharCode(byte) : '.';
}
const containsDomain = fullText.includes(domain_name);
if (containsDomain) {
    console.log('Contains domain:', containsDomain);
    return 1
} else {
    return -1
}

Image

@moonrailgun
Copy link
Contributor

idk much clear with whats your problem about it? looks like your code works very well.

how can i help you?

@ghostersk
Copy link
Author

ghostersk commented Mar 24, 2025

idk much clear with whats your problem about it? looks like your code works very well.

how can i help you?

Yes, the code works, for some reason after little while it stopped working for me.( aprox after half an hour)
I am just saying there would be nice to have option to test DNS over HTTPS if it is resolving, and what I was able to test, best one is with dig, as that also returns the IP, so you can confirm that the resolution works, and in case you have some dynamic name resolution it could inform about the change of ip as well.

The js code I have can only check if the domain was returned in the request
Also It may be possible that the reason It stopped working for me after longer period was crowdsec, but I tried it by quering the IP directly but that did not work either.
I have stopped the check, and I have now re-enabled it but it is still failing. and to my knowledge nothing changed.
So it does not seem to be so reliable.
When I test the code, it runs up to line 67, if I put for example console.log(url_check) what returns the URL it shows correct url.
but anything from line 72 fails, the console.log(res) is never executed

  • so it seems like the request failing

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants