How to configure DNS properly while two LANs are running? The device can't ping www.google.com but ping 8.8.8.8 is okay. My OS is Android 6.0.1, the kernel is 4.1.15

I've tried the resolv.conf and /etc/hosts. But these methods seem can not work on Android.

And I couldn't figure out what the exact problem is.

eth0      Link encap:Ethernet  HWaddr EE:DE:17:79:BB:42
          inet addr:192.168.1.10  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::ecde:17ff:fe79:bb42/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:7 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:600 TX bytes:1166

eth1      Link encap:Ethernet  HWaddr 00:0E:C6:81:79:01
          inet addr:192.168.120.57  Bcast:192.168.121.255  Mask:255.255.254.0
          inet6 addr: fe80::20e:c6ff:fe81:7901/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:41709 errors:0 dropped:0 overruns:0 frame:0
          TX packets:113 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2738793 TX bytes:8354


I closed the netd service so that it is able to configure eth0 and eth1 respectively.

Here is my IP rule

0:      from all lookup local
9998:   from all to 192.168.120.0/23 lookup 4
9999:   from all to 192.168.1.0/24 lookup 3
10000:  from all fwmark 0xc0000/0xd0000 lookup legacy_system
13000:  from all fwmark 0x10063/0x1ffff lookup local_network
15000:  from all fwmark 0x0/0x10000 lookup legacy_system
16000:  from all fwmark 0x0/0x10000 lookup legacy_network
17000:  from all fwmark 0x0/0x10000 lookup local_network
23000:  from all fwmark 0x0/0xffff uidrange 0-0 lookup main
32000:  from all unreachable


Here is a result of ping IP, you can see the response is fine.

root# ping 192.168.120.1
PING 192.168.120.1 (192.168.120.1) 56(84) bytes of data.
64 bytes from 192.168.120.1: icmp_seq=1 ttl=64 time=1.08 ms
64 bytes from 192.168.120.1: icmp_seq=2 ttl=64 time=0.986 ms
64 bytes from 192.168.120.1: icmp_seq=3 ttl=64 time=1.00 ms

root# ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=255 time=0.718 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=255 time=0.420 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=255 time=0.403 ms


But ping google always returns unknown.

ping: unknown host www.google.com


I expect I could ping IP and URL in my case.

BTW, the DNS from eth0 192.168.1.245 and the DNS from eth1 is 8.8.8.8
I'll try to explain my understanding of DNS on Android. It will help you troubleshoot related problems and serve me as future notes.

DNS

Domain Name Resolver has traditionally been a part of OS's C library (commonly called libc). GNU libc (which is most common on Linux distros) implements a complicated name resolution mechanism named NSS which can prioritize in what order database services like LDAP / NIS, local files (/etc/hosts) and DNS have to be used in order to resolve host / domain names. DNS resolver then reads /etc/resolv.conf to get the name server address which is to be queried.

Unlike GNU libc, Android's Bionic libc (which depends on netd for DNS) doesn't regard /etc/resolv.conf unless ANDROID_CHANGES build variable is defined (only when libc++ is built as static library?). However /etc/hosts entries are valued by Android's resolver when resolving names.
But if you are using a statically compiled / linked binary with some other - such as musl or uC or diet - libc, that must be reading /etc/resolv.conf to get Domain Name Server's IP address. Busybox ping is a common example.

Android's DNS

Within Android's Java runtime environment, either a DHCP provided or manually set or hard coded DNS server is used. Properties net.dns1 and net.dns2 are set with values of DNS servers received from DHCP server (on Wi-Fi or Mobile Data) by ConnectivityService and then forwarded to netd. Starting with Android Oreo, these properties are no longer available through Android APIs, but only readable as root or shell - once removed then re-added. So changing properties net.dns* using setprop only affects the programs (running with UID 0 or 2000) that explicitly read these properties. One such example is meefik's busybox. Also there were some other DNS related properties set in good old days of dhcpcd which was the DHCP client up to Lollipop.

See some more details in How does Android OS do DNS name resolution?.

Caching

DNS queries are cached on Android by netd as NSCD does on Linux distros to speed up name resolution. Android has a commandline tool ndc that could clear DNS cache but the command was removed in Android 7. Now it's possible to bypass caching by setting environment variable ANDROID_DNS_MODE which prevents Bionic libc from proxying back to netd service for cache lookup. See How to modify environment variables like PATH at startup? to set the variable globally.

How to set DNS

As mentioned earlier, previously different methods used to change default Domain Name Servers on Android don't seem to work now. Setting name servers and/or search domain name through commandline:

~$ ndc resolver setnetdns &lt;network_id&gt; &lt;domain&gt; &lt;DNS&gt;


* Commands syntax is a bit different on older versions

Similarly ndc tether dns set works for dnsmasq. To get current network ID:

~$ dumpsys netd | grep 'Default network'


Clear set DNS servers:

~# ndc resolver clearnetdns &lt;network_id&gt;


However some apps may sometimes bypass Android's name resolution mechanism trying directly reach out to some nameserver, I have observed WhatsApp. Or the hard-coded value is used (may be when router is advertising the IPv6 DNS server). The only certain working option is iptables DNAT:

~# iptables -t nat -I OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.1:53


DNS servers can also be configured in Settings for Wi-Fi network. Android 9+ supports Private DNS / DNS over TLS (DoT) which sends encrypted DNS queries on port 853 as standardized in RFC7858.

Non-root solution which works for both Wi-Fi and Mobile data is to use VPN apps like Virtual Hosts or Personal DNS Filter which intercept DNS traffic and makes queries to configured upstream DNS server.

Testing

To test what name server is being used by connectivity and netd services in Java runtime:

~# dumpsys connectivity | grep CONNECTED | grep -o 'DnsAddresses: \[[^ ]*'
~# dumpsys netd | grep -A2 'DNS servers:'


And those used by tethering forwarding DNS server:

~# ndc tether dns list
~# logcat -d -s TetherController,dnsmasq | grep -E 'update_dns|nameserver'


To see where the DNS queries are going, you may capture traffic destined for port 53:

~# iptables -I OUTPUT -m udp -p udp --dport 53 -j LOG --log-prefix 'DNS_QUERIES '
~# iptables -I OUTPUT -m tcp -p tcp --dport 53 -j LOG --log-prefix 'DNS_QUERIES '
~# dmesg -w | grep 'DNS_QUERIES'


Or

~# tcpdump -n -i any port 53


If the queries are not going to desired destination, there is some trouble with your DNS configuration, particularly if you use VPN. Please note that iptables and tcpdump (capturing on port 53) won't work with Private DNS (port 853). Dynamic nature of RPDB and routing tables (rt_tables keeps on changing, main table is not used) accompanied by fwmark (SO_MARK) make things complicated for manual control.

So if above mentioned steps don't work, there's nothing much you can do to fix DNS issues on Android devices. A Factory Reset or re-flashing of ROM may resolve the problem.

Additionally, if a local DNS server is provided by DHCP (server on Wi-Fi router), you may check if that's really listening on port 53:

~# nmap -e eth0 -sUT -p53 --script=dns-recursion 192.168.1.245