AdguardForMac icon indicating copy to clipboard operation
AdguardForMac copied to clipboard

Adguard interferes with DNS resolving using libresolv's `res_query` when DNS Protection is enabled

Open lukele opened this issue 9 months ago • 7 comments

Please answer the following questions for yourself before submitting an issue

  • [x] Filters were updated before reproducing an issue
  • [x] I checked the knowledge base and found no answer
  • [x] I checked to make sure that this issue has not already been filed

AdGuard version

Version 2.16.4.1870 release

Browser version

No response

OS version

macOS Sequoia 15.4

Ad Blocking

AdGuard Base filter

Privacy

AdGuard URL Tracking filter

Social

AdGuard Social Media filter

Annoyances

No response

Security

No response

Other

AdGuard DNS filter

Language-specific

EasyList Italy

Which DNS server do you use?

AdGuard DNS

DNS protocol

DNS-over-HTTPS

Custom DNS

No response

What Stealth Mode options do you have enabled?

Remove tracking parameters

Support ticket ID

1071945

Issue Details

I run a software company that develops a tool which uses GnuPG to encrypt email messages. GnuPG comes with a service that fetches certificates from key servers called dirmngr. dirmngr uses libresolv on macOS to query DNS in order to then contact the key server. And that is where the problem starts. Once AdGuard (with DNS Protection active) is enabled, libresolv fails to resolve any DNS requests for some reason.

Following are the steps to reproduce the issue and at the end there’s the code mentioned in the steps:

  1. Enable AdGuard (and make sure that DNS Protection is active. Provider can be "System default". Behavior is the same for all of them)
  2. Run ./test-dns-resolve [gpgtools.com](http://gpgtools.com/)
  3. See an error message like: Failed to query A records for [gpgtools.com](http://gpgtools.com/)
  4. Disable AdGuard
  5. Run ./test-dns-resolve [gpgtools.com](http://gpgtools.com/)
  6. See a message like: A Records for [gpgtools.com](http://gpgtools.com/): 185.26.156.66

Code for test-dns-resolve

#define BIND_8_COMPAT
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_a_records(unsigned char *response, int len);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <domain>\n", argv[0]);
        exit(1);
    }

    // Initialize the resolver
    res_init();

    unsigned char response[1024]; // Buffer for DNS response
    int response_len;

    // Query A records
    response_len = res_query(argv[1], ns_c_in, ns_t_a, response, sizeof(response));
    if (response_len < 0) {
        fprintf(stderr, "Failed to query A records for %s\n", argv[1]);
    } else {
        printf("A Records for %s:\n", argv[1]);
        print_a_records(response, response_len);
    }

    return 0;
}

void print_a_records(unsigned char *response, int len) {
    struct in_addr addr;
    ns_msg handle;
    ns_rr rr;

    if (ns_initparse(response, len, &handle) < 0) {
        perror("ns_initparse failed");
        return;
    }

    int msg_count = ns_msg_count(handle, ns_s_an); // Answer section
    for (int i = 0; i < msg_count; i++) {
        if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
            perror("ns_parserr failed");
            continue;
        }

        if (ns_rr_type(rr) == ns_t_a) {
            memcpy(&addr, ns_rr_rdata(rr), sizeof(addr));
            char ip_str[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str));
            printf("  %s\n", ip_str);
        }
    }
}

Compile

clang test-dns-resolve.c -lresolv -o test-dns-resolve

It would be really helpful if you could help me out solving this issue, since some of our customers are also using AdGuard and it’s not great if they have to decide whether to use AdGuard or our tools. Thanks!

Expected Behavior

res_query should succeed and correctly return the requested DNS records even with DNS Protection active in Adguard.

Actual Behavior

Any DNS query fails as soon as DNS Protection is active in AdGuard.

Screenshots

Screenshot 1

Additional Information

No response

lukele avatar Apr 03 '25 11:04 lukele

@lukele Hello!

We apologise for the delay in responding.

Unfortunately, we are unable to reproduce the problem you describe. For example, here is the result of a ./test-dns-resolve gpgtools.com command run on our end with AdGuard enabled and the System default DNS server selected:

A Records for gpgtools.com:
  185.26.156.66 

In this case, we need to get your application logs in order to diagnose and troubleshoot this issue. Here's what we need you to do:

  1. Click AdGuard icon in the menu bar → Gear → Advanced → Logging → Logging level → Debug.
  2. Reproduce the problem, then remember the exact time it happened.
  3. Menu → Advanced → Logging → Export Logs and System Info.….
  4. Send this file to [email protected]: — include [mac] keyword and ISSUE_NUMBER in the subject of your email — specify the exact time when the issue occurred

AlexandrPkhm avatar Apr 09 '25 14:04 AlexandrPkhm

Hi @AlexandrPkhm,

thank you very much for having a look, I just sent the requested debug logs. I really wonder what is going on, that you can't reproduce it. Had a quick look at the collected logs and noticed that AdGuard does send the request, does receive an answer, but then for some reason – if I read the log correctly – invokes an error handler:

2025-04-10 17:09:00.424  2622:1f223    [com.adguard.mac.adguard] D: (DnsProxyCallbacks: onRequestProcessed(_:)) onDnsRequestProcessed: Optional([(0x600003b32700)AGDnsRequestProcessedEvent: domain=gpgtools.com., type=A, status=NOERROR, answer=A, 185.26.156.66
, originalAnswer=, upstreamId=(null), filterListIds=(
), whitelist=NO, error=, cacheHit=NO, dnssec=NO])
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow ~Flow: [id=102260] Closed flow: UDP test-dns-resolve[{length = 20, bytes = 0xab1f0c2bf343cec812157477801c964ff7f3ce4f}] local port 51115 interface en0 with no error
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession onError: [id=1057998]: Error on socket (0.0.0.0:62880): (0) Client UDP socket is closing: (no error) 
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession shutDownSession: [id=1057998]: Graceful: true, reason: Client UDP socket is closing: (no error) 
2025-04-10 17:09:00.426 48902:51b3     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow prepareFd: [id=102261] Interface for destination 0.0.0.0:0: 0 ()
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession onError: [id=1057998]: Error on socket (8.8.8.8:53): (0) Client UDP socket is closing: (no error) 
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProcessingChain shutdown: [id=1057998]: ...
2025-04-10 17:09:00.426 48902:107      [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProcessingChain shutdown: [id=1057998]: Done

lukele avatar Apr 10 '25 15:04 lukele

@lukele Oh, one more thing. Please try running the latest nightly version of AdGuard for Mac. We have made some changes there that may fix the problem. It is available via the following link - https://agrd.io/mac_nightly

Please let us know if this version fixes the problem.

AlexandrPkhm avatar Apr 10 '25 16:04 AlexandrPkhm

@AlexandrPkhm I have now setup a fresh macOS VM with 15.4 24E248, downloaded and installed the nightly, kept the default configuration as proposed by AdGuard, just disabled SSL filtering and can reliably reproduce the issue.

Also in this setup, AdGuard properly handles the DNS request but then fails to forward the answer it appears:

2025-04-10 23:22:02.219  1536:1fa7b    [com.adguard.mac.adguard] D: (DnsProxyCallbacks: onRequestProcessed(_:)) onDnsRequestProcessed: Optional([(0x600003f70980)AGDnsRequestProcessedEvent: domain=gpgtools.com., type=A, status=NOERROR, answer=A, 185.26.156.66
, originalAnswer=, upstreamId=(null), filterListIds=(
), whitelist=NO, error=, cacheHit=NO, dnssec=NO])
2025-04-10 23:22:02.219  1578:8023     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow handleRead: [id=58] Flow closing cleanly (flow: UDP test-dns-resolve[{length = 20, bytes = 0x9209fe7ac6e98aa8a55337614744b0a79ace377e}] local port 52755 interface en0)
2025-04-10 23:22:02.220  1578:682b     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow prepareFd: [id=59] Interface for destination 0.0.0.0:0: 0 ()
2025-04-10 23:22:02.220  1578:682b     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEProxyServer: Accepting UDP flow to 192.168.64.1:53 (redirect to: 192.168.64.1:53) from application com.apple.Terminal (flow: UDP test-dns-resolve[{length = 20, bytes = 0x9209fe7ac6e98aa8a55337614744b0a79ace377e}] local port 64637 interface en0)
2025-04-10 23:22:02.220  1578:682b     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow +[ANNEUdpFlow openWithFlow:remoteEndpoint:oproxySettings:eventLoop:connectionCallback:checkCallback:routeCallback:]: [id=59] Opening flow: UDP test-dns-resolve[{length = 20, bytes = 0x9209fe7ac6e98aa8a55337614744b0a79ace377e}] local port 64637 interface en0
2025-04-10 23:22:02.219  1578:8023     [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession onError: [id=1000004]: Error on socket (0.0.0.0:64061): (0) Client UDP socket is closing: (no error) 
2025-04-10 23:22:02.219  1578:8023     [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession shutDownSession: [id=1000004]: Graceful: true, reason: Client UDP socket is closing: (no error) 
2025-04-10 23:22:02.219  1578:8023     [com.adguard.mac.adguard.network-extension] D: (CL: ) ANNEUdpFlow ~Flow: [id=58] Closed flow: UDP test-dns-resolve[{length = 20, bytes = 0x9209fe7ac6e98aa8a55337614744b0a79ace377e}] local port 52755 interface en0 with no error
2025-04-10 23:22:02.219  1578:8023     [com.adguard.mac.adguard.network-extension] D: (CL: ) AGProxySession onError: [id=1000004]: Error on socket (192.168.64.1:53): (0) Client UDP socket is closing: (no error) 

I have sent you another debug log from the VM with the nightly installed.

lukele avatar Apr 10 '25 21:04 lukele

@AlexandrPkhm just wanted to see if you have any idea already what could be going on here?

lukele avatar May 09 '25 22:05 lukele

@lukele I've traced the issue to IP_RECVIF not working on sockets proxied with an NETransparentProxyProvider: either a bug or a limitation of the transparent proxy mechanism.

libresolv relies on it and breaks if there's no ancillary data:

  1. https://github.com/apple-oss-distributions/libresolv/blob/84e15f965bf75b6696fdb5c21405f141ae660dc5/res_send.c#L1404
  2. https://github.com/apple-oss-distributions/libresolv/blob/84e15f965bf75b6696fdb5c21405f141ae660dc5/res_send.c#L1265

On the other hand, IPV6_PKTINFO seems to work, so users with an IPv6 DNS resolver are not affected.

I've filed a bug report with Apple and opened a thread on their forums. It could, in theory, speed things along if you mentioned that it affects your customers, too.

ngorskikh avatar May 12 '25 17:05 ngorskikh

Very interesting! Thank you for the update! I'll file a feedback item with Apple.

lukele avatar May 13 '25 10:05 lukele