[GH-ISSUE #652] The resolver doesn't work on Android #267

Closed
opened 2026-03-07 23:07:14 +03:00 by kerem · 17 comments
Owner

Originally created by @fabricedesre on GitHub (Jan 8, 2019).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/652

Describe the bug
Name resolution doesn't work when using the resolver on Android targets.

To Reproduce
Compile any sample using trust-dns-resolve for Android.

Expected behavior
Name resolution should work.

System:

  • OS: Android
  • Architecture: tested on armv7
  • Version
  • rustc version: 1.33

Version:
Crate: resolver
Version: 0.10.2

Additional context
Android builds end up in the unix path, but there is no /etc/resolv.conf on Android. We need an Android specific implementation reading system properties instead (quite similar to what is done with the windows registry).
I'm willing to contribute support if project owners agree.

Originally created by @fabricedesre on GitHub (Jan 8, 2019). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/652 **Describe the bug** Name resolution doesn't work when using the resolver on Android targets. **To Reproduce** Compile any sample using trust-dns-resolve for Android. **Expected behavior** Name resolution should work. **System:** - OS: Android - Architecture: tested on armv7 - Version - rustc version: 1.33 **Version:** Crate: resolver Version: 0.10.2 **Additional context** Android builds end up in the unix path, but there is no /etc/resolv.conf on Android. We need an Android specific implementation reading system properties instead (quite similar to what is done with the windows registry). I'm willing to contribute support if project owners agree.
Author
Owner

@bluejekyll commented on GitHub (Jan 8, 2019):

I'm willing to contribute support if project owners agree.

This would be great, thanks!

Do you know of any automated testing environments we could use to validate that this support wouldn't be broken after it's added?

<!-- gh-comment-id:452456821 --> @bluejekyll commented on GitHub (Jan 8, 2019): > I'm willing to contribute support if project owners agree. This would be great, thanks! Do you know of any automated testing environments we could use to validate that this support wouldn't be broken after it's added?
Author
Owner

@fabricedesre commented on GitHub (Jan 8, 2019):

Do you know of any automated testing environments we could use to validate that this support wouldn't be broken after it's added?

Unfortunately no apart from private, custom setups :(

<!-- gh-comment-id:452466736 --> @fabricedesre commented on GitHub (Jan 8, 2019): > Do you know of any automated testing environments we could use to validate that this support wouldn't be broken after it's added? Unfortunately no apart from private, custom setups :(
Author
Owner

@bluejekyll commented on GitHub (Jan 8, 2019):

I wonder if we could somehow use any of this to help at least check compilation? https://docs.travis-ci.com/user/languages/android/

<!-- gh-comment-id:452471237 --> @bluejekyll commented on GitHub (Jan 8, 2019): I wonder if we could somehow use any of this to help at least check compilation? https://docs.travis-ci.com/user/languages/android/
Author
Owner

@thomcc commented on GitHub (Jan 11, 2019):

You can also check compilation by installing an android target with rustup, and passing --target to cargo build.

<!-- gh-comment-id:453605309 --> @thomcc commented on GitHub (Jan 11, 2019): You can also check compilation by installing an android target with rustup, and passing --target to cargo build.
Author
Owner

@Dushistov commented on GitHub (Feb 12, 2019):

I catched this issue when I try to use trust-dns via reqwest on Android:

NetworkError(Error { kind: DnsSystemConf(Os { code: 2, kind: NotFound, message: "No such file or directory" }), url: None })
<!-- gh-comment-id:462709844 --> @Dushistov commented on GitHub (Feb 12, 2019): I catched this issue when I try to use trust-dns via reqwest on Android: ``` NetworkError(Error { kind: DnsSystemConf(Os { code: 2, kind: NotFound, message: "No such file or directory" }), url: None }) ```
Author
Owner

@wngr commented on GitHub (May 11, 2021):

I wonder what you would think of adding a custom implementation to Android to figure out the system resolver config. According to this Stackoverflow post the universal solution to this would be to parse the output of getprop, which returns something like:

[net.eth0.dns1]: [10.0.2.3]
[net.eth0.dns2]: []
[net.eth0.dns3]: []
[net.eth0.dns4]: []

You'd have those for all interfaces, so I was thinking of just constructing a set of all dns servers, and use that for the system resolver config on Android.

What do you think about this approach?

ref https://github.com/bluejekyll/trust-dns/issues/1099#issuecomment-631785263

<!-- gh-comment-id:838558367 --> @wngr commented on GitHub (May 11, 2021): I wonder what you would think of adding a custom implementation to Android to figure out the system resolver config. According to [this Stackoverflow post](https://stackoverflow.com/questions/3070144/how-do-you-get-the-current-dns-servers-for-android) the universal solution to this would be to parse the output of `getprop`, which returns something like: ``` [net.eth0.dns1]: [10.0.2.3] [net.eth0.dns2]: [] [net.eth0.dns3]: [] [net.eth0.dns4]: [] ``` You'd have those for all interfaces, so I was thinking of just constructing a set of all dns servers, and use that for the system resolver config on Android. What do you think about this approach? ref https://github.com/bluejekyll/trust-dns/issues/1099#issuecomment-631785263
Author
Owner

@link2xt commented on GitHub (Mar 9, 2023):

https://stackoverflow.com/questions/3070144/how-do-you-get-the-current-dns-servers-for-android says getprop is not working on some Androids.

But trust-dns-resolver can use a ConnectivityManager via j4rs.

An example of j4rs usage for similar purposes: https://github.com/n0-computer/iroh/pull/825

<!-- gh-comment-id:1462939606 --> @link2xt commented on GitHub (Mar 9, 2023): https://stackoverflow.com/questions/3070144/how-do-you-get-the-current-dns-servers-for-android says `getprop` is not working on some Androids. But trust-dns-resolver can use a ConnectivityManager via [j4rs](https://lib.rs/crates/j4rs). An example of j4rs usage for similar purposes: https://github.com/n0-computer/iroh/pull/825
Author
Owner

@djc commented on GitHub (Mar 10, 2023):

I'm happy to review a well-argued PR for this. j4rs seems like a pretty ugly workaround, but if we don't know of any alternatives I guess that's what we'll want to do.

<!-- gh-comment-id:1463481456 --> @djc commented on GitHub (Mar 10, 2023): I'm happy to review a well-argued PR for this. j4rs seems like a pretty ugly workaround, but if we don't know of any alternatives I guess that's what we'll want to do.
Author
Owner

@link2xt commented on GitHub (Mar 10, 2023):

There are also native APIs in the Android NDK, but they require recent Android API, at least API level 29 in most cases: https://developer.android.com/ndk/reference/group/networking

<!-- gh-comment-id:1463504000 --> @link2xt commented on GitHub (Mar 10, 2023): There are also native APIs in the Android NDK, but they require recent Android API, at least API level 29 in most cases: https://developer.android.com/ndk/reference/group/networking
Author
Owner

@djc commented on GitHub (Mar 10, 2023):

Ideally we'd have both and switch depending on the API level, if it's not too much extra work?

<!-- gh-comment-id:1463516872 --> @djc commented on GitHub (Mar 10, 2023): Ideally we'd have both and switch depending on the API level, if it's not too much extra work?
Author
Owner

@link2xt commented on GitHub (Mar 10, 2023):

Here is some documentation on how DNS resolver works in Android: https://source.android.com/docs/core/ota/modular-system/dns-resolver

It seems to be possible to learn how to use /dev/socket/dnsproxyd directly from Rust and skip Java and bionic libc dependencies.

Related bionic code referred to in the documentation is at https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/dns/
netd code is at https://android.googlesource.com/platform/system/netd/

<!-- gh-comment-id:1464503560 --> @link2xt commented on GitHub (Mar 10, 2023): Here is some documentation on how DNS resolver works in Android: https://source.android.com/docs/core/ota/modular-system/dns-resolver It seems to be possible to learn how to use `/dev/socket/dnsproxyd` directly from Rust and skip Java and bionic libc dependencies. Related bionic code referred to in the documentation is at https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/dns/ netd code is at https://android.googlesource.com/platform/system/netd/
Author
Owner

@link2xt commented on GitHub (Oct 26, 2023):

dnsproxyd supports resolv_res_nsend which allows to send arbitrary DNS queries: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/res_send.h
Implementation of the client is here: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/res_send.cpp
It is similar to classic res_send interface.

resnsend command implementation is here: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/DnsProxyListener.cpp

Sending commands to /dev/socket/dnsproxyd is easy, e.g. from Termux I can run:

(printf 'gethostbyname ^ www.github.com 2\x00'; sleep 1) | ncat -U /dev/socket/dnsproxyd | hexdump -c

and get some answer.
Commands are null-terminated, without null byte you will get 500 Command too large for buffer response: github.com/aosp-mirror/platform_system_core@268c408310/libsysutils/src/FrameworkListener.cpp (L66)

The documentation for dnsproxyd is the source code it seems. resnsend command gets 4 arguments: resnsend command itself, netId (which can be 0 for NETID_UNSET as described in https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/include/netd_resolv/resolv.h), flags and msg (base64-encoded query).

<!-- gh-comment-id:1781855021 --> @link2xt commented on GitHub (Oct 26, 2023): `dnsproxyd` supports `resolv_res_nsend` which allows to send arbitrary DNS queries: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/res_send.h Implementation of the client is here: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/res_send.cpp It is similar to classic [res_send](https://linux.die.net/man/3/res_send) interface. resnsend command implementation is here: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/DnsProxyListener.cpp Sending commands to `/dev/socket/dnsproxyd` is easy, e.g. from Termux I can run: ``` (printf 'gethostbyname ^ www.github.com 2\x00'; sleep 1) | ncat -U /dev/socket/dnsproxyd | hexdump -c ``` and get some answer. Commands are null-terminated, without null byte you will get `500 Command too large for buffer` response: https://github.com/aosp-mirror/platform_system_core/blob/268c408310082dd873089e718ea4ea8964b003f3/libsysutils/src/FrameworkListener.cpp#L66 The documentation for `dnsproxyd` is the source code it seems. `resnsend` command gets 4 arguments: `resnsend` command itself, netId (which can be 0 for `NETID_UNSET` as described in https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/main/include/netd_resolv/resolv.h), flags and `msg` (base64-encoded query).
Author
Owner

@link2xt commented on GitHub (Oct 26, 2023):

So I used this Python script to generate DNS query with dnspython:

#!/usr/bin/env python3
from base64 import b64encode
import dns.message

print(b64encode(dns.message.make_query("github.com", "MX").to_wire()))

It prints b'OTIBAAABAAAAAAAABmdpdGh1YgNjb20AAA8AAQ=='.
Then in Termux I run:

printf 'resnsend 0 0 OTIBAAABAAAAAAAABmdpdGh1YgNjb20AAA8AAQ==\x00' | ncat -U /dev/socket/dnsproxyd | hexdump

and get a binary response:

00000000  00 00 00 00 00 00 00 8f  39 32 81 80 00 01 00 05  |........92......|
00000010  00 00 00 00 06 67 69 74  68 75 62 03 63 6f 6d 00  |.....github.com.|
00000020  00 0f 00 01 c0 0c 00 0f  00 01 00 00 0e 10 00 18  |................|
00000030  00 05 04 61 6c 74 31 05  61 73 70 6d 78 01 6c 06  |...alt1.aspmx.l.|
00000040  67 6f 6f 67 6c 65 c0 13  c0 0c 00 0f 00 01 00 00  |google..........|
00000050  0e 10 00 09 00 05 04 61  6c 74 32 c0 2f c0 0c 00  |.......alt2./...|
00000060  0f 00 01 00 00 0e 10 00  04 00 01 c0 2f c0 0c 00  |............/...|
00000070  0f 00 01 00 00 0e 10 00  09 00 0a 04 61 6c 74 33  |............alt3|
00000080  c0 2f c0 0c 00 0f 00 01  00 00 0e 10 00 09 00 0a  |./..............|
00000090  04 61 6c 74 34 c0 2f                              |.alt4./|
00000097

So it seems to work, only need to be able to open an unix socket, base64-encode your request and parse the response back.

<!-- gh-comment-id:1781994055 --> @link2xt commented on GitHub (Oct 26, 2023): So I used this Python script to generate DNS query with [dnspython](https://dnspython.readthedocs.io/): ``` #!/usr/bin/env python3 from base64 import b64encode import dns.message print(b64encode(dns.message.make_query("github.com", "MX").to_wire())) ``` It prints `b'OTIBAAABAAAAAAAABmdpdGh1YgNjb20AAA8AAQ=='`. Then in Termux I run: ``` printf 'resnsend 0 0 OTIBAAABAAAAAAAABmdpdGh1YgNjb20AAA8AAQ==\x00' | ncat -U /dev/socket/dnsproxyd | hexdump ``` and get a binary response: ``` 00000000 00 00 00 00 00 00 00 8f 39 32 81 80 00 01 00 05 |........92......| 00000010 00 00 00 00 06 67 69 74 68 75 62 03 63 6f 6d 00 |.....github.com.| 00000020 00 0f 00 01 c0 0c 00 0f 00 01 00 00 0e 10 00 18 |................| 00000030 00 05 04 61 6c 74 31 05 61 73 70 6d 78 01 6c 06 |...alt1.aspmx.l.| 00000040 67 6f 6f 67 6c 65 c0 13 c0 0c 00 0f 00 01 00 00 |google..........| 00000050 0e 10 00 09 00 05 04 61 6c 74 32 c0 2f c0 0c 00 |.......alt2./...| 00000060 0f 00 01 00 00 0e 10 00 04 00 01 c0 2f c0 0c 00 |............/...| 00000070 0f 00 01 00 00 0e 10 00 09 00 0a 04 61 6c 74 33 |............alt3| 00000080 c0 2f c0 0c 00 0f 00 01 00 00 0e 10 00 09 00 0a |./..............| 00000090 04 61 6c 74 34 c0 2f |.alt4./| 00000097 ``` So it seems to work, only need to be able to open an unix socket, base64-encode your request and parse the response back.
Author
Owner

@djc commented on GitHub (Oct 27, 2023):

@link2xt I don't think we'd want to send DNS requests via the Android DNS stack -- the issue here (as I understand it) is that we need to find out the default DNS servers from the operating system. Once we have those, I think we'd want to do our own UDP/TCP/QUIC stuff.

<!-- gh-comment-id:1782431288 --> @djc commented on GitHub (Oct 27, 2023): @link2xt I don't think we'd want to send DNS requests via the Android DNS stack -- the issue here (as I understand it) is that we need to find out the default DNS servers from the operating system. Once we have those, I think we'd want to do our own UDP/TCP/QUIC stuff.
Author
Owner

@link2xt commented on GitHub (Oct 27, 2023):

I don't think we'd want to send DNS requests via the Android DNS stack -- the issue here (as I understand it) is that we need to find out the default DNS servers from the operating system.

This seem to require interacting with Java services now: https://stackoverflow.com/questions/3070144/how-do-you-get-the-current-dns-servers-for-android
You can use Java APIs from Rust using j4rs, I don't see other solutions in this case: https://github.com/n0-computer/iroh/pull/825
But at this point it is probably easier to close the issue and say that Android apps using this API should use Java methods to find DNS servers and provide them to the Rust code.

So for my purposes I can fallback to using /dev/socket/dnsproxyd if AsyncResolver::tokio_from_system_conf() does not work.

<!-- gh-comment-id:1783178552 --> @link2xt commented on GitHub (Oct 27, 2023): > I don't think we'd want to send DNS requests via the Android DNS stack -- the issue here (as I understand it) is that we need to find out the default DNS servers from the operating system. This seem to require interacting with Java services now: https://stackoverflow.com/questions/3070144/how-do-you-get-the-current-dns-servers-for-android You can use Java APIs from Rust using j4rs, I don't see other solutions in this case: https://github.com/n0-computer/iroh/pull/825 But at this point it is probably easier to close the issue and say that Android apps using this API should use Java methods to find DNS servers and provide them to the Rust code. So for my purposes I can fallback to using `/dev/socket/dnsproxyd` if `AsyncResolver::tokio_from_system_conf()` does not work.
Author
Owner

@Millione commented on GitHub (Apr 1, 2025):

I'm wondering if there have been any updates regarding its resolution, if not, is there any workaround suggesting?

<!-- gh-comment-id:2768016428 --> @Millione commented on GitHub (Apr 1, 2025): I'm wondering if there have been any updates regarding its resolution, if not, is there any workaround suggesting?
Author
Owner

@djc commented on GitHub (Apr 1, 2025):

There has been no work on this as far as I've seen. But I think the workaround suggested in https://github.com/hickory-dns/hickory-dns/issues/652#issuecomment-1783178552 makes a lot of sense.

<!-- gh-comment-id:2768598464 --> @djc commented on GitHub (Apr 1, 2025): There has been no work on this as far as I've seen. But I think the workaround suggested in https://github.com/hickory-dns/hickory-dns/issues/652#issuecomment-1783178552 makes a lot of sense.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#267
No description provided.