Search code examples
loggingdnsforwardingdnsmasqcoredns

Identify device from public DNS server


I have old case to get client IP from secondary DNS server (see get client IP from secondary dns server)

Now I want to upgrade this case by identify device in local network from public DNS server, simple model is:

device <-> gateway <-> internet <-> DNS server

Specifically, I want to get more information about devices on the network to identify each device specifically, instead of just having an IP address (representing a group of devices on the network, through NAT).

I plan to develop cross-platform (mobile, desktop, ...) apps to install on my device, but the two problems I can see immediately are

  • After the app retrieves the device information, how do I attach the device information to the DNS packets, or somehow at the DNS server I can get the device information. But this is only internal in the app, please read the next
  • Suppose if my app has the above capability, then how do I do when installing the app on my device, all DNS queries from the device are forced to go through the DNS that my app has installed, my idea can is to get the system permissions of the device, because I recently checked a few phone models that there is no DNS editing function

Thanks!


Solution

  • In the past, DNS proxy apps on Android usually rely on VPN API like Intra and Nebulo where they turn all Do53 request into encrypted request (or just forward them wholesale if it's only to change Do53 server on mobile connection) while leaving the rest of the traffic untouched. DNSCloak for iOS takes the same approach. There is a DNS proxy provider API for iOS but it can only run on devices enrolled in MDM, which kinda make it useless for the general public. On Windows, this pretend-VPN approach is used by NextDNS to cover the OS, though it's not exactly necessary, most desktop OSes allows changing the Do53 address regardless of the network being used, so just a regular proxy app listening on port 53 and configuring the OS to direct request to localhost works.

    Today, both Android and iOS have native encrypted DNS support, with macOS using the same configuration profile as iOS, and Windows support coming soon. What it means is, if apps use the standard DNS resolving API from the OS, it will be resolved by the configured DoT/DoH. Note that if the app is configured to use its own DoH (I'm not aware of a mainstream app that supports custom DoT), it will ignore the OS configuration. As in, if Chrome is set to use Cloudflare DoH and the OS is set to use a different DNS provider, Cloudflare DoH will be used to resolve the address in Chrome.

    Okay, great, you might be confused why I bring it up when you just want to add an additional payload about the device information right? Think about what DoH & DoT need, a domain. If you bought a domain, you can have a practically infinite subdomain, and if each device (or even apps) is set to use its own subdomain, there you have it, the identifying payload. This doesn't require setting tons of DNS entries, both A & AAAA supports wildcard entries. So all it takes is for your web server app to note what subdomain is used by the request and either logs them or transform them to an easier format to process. Another easier route is the path itself, though it's only available for DoH.

    Can it actually work? Is it scalable? Yup, I know because that's exactly what NextDNS do. Each user account can have multiple configurations. Each of those configurations (represented as six-digit hexadecimal, enough for sixteen million configurations) have their own DoT subdomain and DoH path, and additionally, the device (or app) can include their own identifying string on top of them.

    So, for example, if one has a config named abcdef in NextDNS, and they set their phone to use phone-abcdef.dns.nextdns.io as DoT resolver, tablet-abcdef.dns.nextdns.io as DoT resolver in their tablet, and dns.nextdns.io/abcdef/phone-chrome, they can see in their log the requests separated by the originating device, even apps, regardless where the request comes from, be it a home connection, mobile data, office, TOR, etc.

    In your case, the easiest solution will be telling your user to download Intra/Nebulo if they're using ancient pre-Android 9 (about a quarter of the market) or guide them on how to use the OS built-in support to use your own DNS provider. You can even see the NextDNS example by creating a temporary config then scroll down to the Setup Guide. If you're expecting to sell to the general public from this endeavor, you're going against a very experienced player, but if this is just for a small organization, sure, go on, even a rudimentary PHP page can extract and process DoH payload, I don't see why it can't extract additional path information then log it into a database.

    Here's a very rough example of how it could work (I believe NextDNS, Cloudflare Teams, etc use far more optimized logic though) :

    • User register an account, then create at least one configuration
    • This configuration, defining what category/list is being blocked, what features are used, etc, is probably just a single DB row with a couple of additional rows in detail tables listing them. The DB isn't necessarily an SQL, so it might be just a NoSQL entry. What's important is each user config just costs very small storage. Notice that NextDNS doesn't allow arbitrary third-party lists, only preselected ones.
    • Upon receiving DoH/DoT request, the server matches the configuration from the domain/path of the DoH/DoT, and load which customization is used, parse the requested domain, let's say example.com
    • Do whatever needed with that example.com, only send the DNS payload to the upstream/recursive resolver if it isn't in the rewrite rule/blacklist/custom blocklists of the configuration. Some rules/configuration might require additional processing of the resolver output (modifying TTL, blocking the domain if it's registered just this month, if it resolves to a local address, etc)
    • Log the originating IP and/or device identification string and action taken
    • Return the query result

    So not all DNS payload is sent to the upstream/recursive resolver, and even those that do might still get replaced with NXDOMAIN (or a predefined result). The blocklist is very likely optimized for all users, oisd list can be implemented as a method call like isBlocked("oisd","example.com"). Since the majority of users will mostly visit sites from a very limited group, the result for each blocklist can be cached and this cache is reused among all users (after all, the result is simply yes or no, without privacy risk).