Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
DNS over HTTPS is not what I thought (petefreitag.com)
87 points by rmason on Jan 31, 2024 | hide | past | favorite | 25 comments


Lovely, made a fish shell function out of it:

    # https://www.petefreitag.com/blog/dns-over-https/

    function dnsq --description "Query DNS name(s) over HTTPs using JSON"

        argparse --ignore-unknown 'h/help' 'd/dns=' 'n/name=+' 't/type=+' -- $argv

        if set -q _flag_help
            echo "Usage: $_ example.com"
            echo '  -n --name    DNS query name(s)'
            echo '  -t --type    DNS query type(s), ex: A (default), MX, TXT...'
            echo '  -d --dns     DNS query endpoint: cloudflare (default), google'
            echo '  -h --help    Print this help message and exit'
            return 0
        end

        if not set -q _flag_name && test (count $argv) -eq 0
            echo 'Missing name parameter.'
            return 1
        end

        if not set -q _flag_type
            set _flag_type 'A'
        end

        switch $_flag_dns
            case 'google'
                set url 'https://dns.google/resolve'
            case 'cloudflare' '*'
                set url 'https://cloudflare-dns.com/dns-query'
        end

        for type in $_flag_type
            for name in $_flag_name $argv
                set query (string join '&' (string join '=' 'name' $name) (string join '=' 'type' $type))

                if isatty stdout && type -q jq
                    curl --header 'Accept: application/dns-json' --silent (string join '?' $url $query) | jq -r
                else
                    curl --header 'Accept: application/dns-json' --silent (string join '?' $url $query)
                end
            end
        end

    end


And I made it into a bash script (with a header to have stacktraces in bash):

  #!/bin/env bash
  #--------------------------------------------
  set -Eeuo pipefail
  if [[ -n "${DEBUG:-}" ]]; then
    set -x
  fi
  trap stack_trace ERR
  function stack_trace() {
    echo -e "\nThe command '$BASH_COMMAND' triggerd a stacktrace:\nStack Trace:"
    for (( i = 1; i < ${#FUNCNAME[@]}; i++ )); do
      echo "    ($i) ${FUNCNAME[$i]:-(top level)} ${BASH_SOURCE[$i]:-(no file)}:${BASH_LINENO[$(( i - 1 ))]}"
    done
  }
  error(){ echo "${1:-error message missing}" && trap true ERR && exit 1; }
  SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
  export SCRIPT_DIR
  #--------------------------------------------
  function dnsq {
    # https://www.petefreitag.com/blog/dns-over-https/
    while [[ $# -gt 0 ]]; do
      case "$1" in
        -h|--help)
          echo "Usage: $0 example.com"
          echo '  -n --name    DNS query name(s)'
          echo '  -t --type    DNS query type(s), ex: A (default), MX, TXT...'
          echo '  -d --dns     DNS query endpoint: cloudflare (default), google'
          echo '  -h --help    Print this help message and exit'
          return 0
          ;;
        -n|--name)
          shift
          _flag_name+=("$1")
          ;;
        -t|--type)
          shift
          _flag_type+=("$1")
          ;;
        -d|--dns)
          shift
          _flag_dns="$1"
          ;;
        \*)
          _flag_name+=("$1")
          ;;
      esac
      shift
    done

    if [[ ${_flag_name:-} = "" ]]; then
      echo 'Missing name parameter.'
      return 1
    fi

    if [[ ${_flag_type:-} = "" ]]; then
      _flag_type=("A")
    fi

    case ${_flag_dns:-cloudflare} in
      "google")
        url="https://8.8.8.8/resolve"
        ;;
      "cloudflare")
        url="https://1.1.1.1/dns-query"
        ;;
    esac

    for type in "${_flag_type[@]}"; do
      for name in "${_flag_name[@]}"; do
        query="name=$name&type=$type"
        if [[ -t 1 ]] && command -v jq >/dev/null; then
          curl --header 'Accept: application/dns-json' --silent "$url?$query" | jq -r
        else
          curl --header 'Accept: application/dns-json' --silent "$url?$query"
        fi
      done
    done
  }

  dnsq "$@"


In this case how is dns.google or cloudflare-dns.com resolved?

Maybe in this case, because the author of the post only cares to check whether certain domains resolve or not, having the DNS server be resolved by normal DNS not DNS over HTTPS is fine, and that in other cases you’d hardcode an IP like with normal DNS resolution?


Those are hardcoded.

dns.google is 8.8.8.8 and cloudflare-dns.com is 1.1.1.1. You can replace the names with those IPs in the curl commands if you want, the certificates are valid for the IPs too.


Hard-coded in what? Every DoH client?


Web browsers usually. Chrome uses Google's, Firefox uses Cloudflare's. You can change it in the settings, but the reason it works out of the box is because it's shipped with an IP pre-set.


How are certificates valid for IPs!?!


As a CA, you may sign a certificate for anything. Public CAs don't do it for IPs for obvious reasons, but if you're cloudflare or Google, you can coax them with enough money and goodwill to sign a cert for your very expensive quad-single-digit ip, especially if you manage to motivate that request with the fact that the IP is a DNS resolver and can't be pointed at by a domain in the first place.


Google actually runs their own CA "Google Trust Services", so they just create that certificate for themselves.



They're valid because the certificates include ipAddress Subject Alternative Names. PKIX (the RFC explaining how the X.500 system's X.509 certificates are to be repurposed for use on the Internet) explains several different names for Internet things, the "alternative names" and the most common you'll have seen is the dnsName, but ipAddress is also in there.

As to how and when they're issued, section 3.2.2.5 of the Baseline Requirements explains how an Applicant can prove this is their IP address and so they're entitled to a certificate for that address. Note that the CA is entitled to choose which if any of the methods listed in 3.2.2.5 they will use, and it's not uncommon for the answer to be "None of them".

https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-...


> Note that the CA is entitled to choose which if any of the methods listed in 3.2.2.5 they will use, and it's not uncommon for the answer to be "None of them".

That's not what the baseline says:

> The CA SHALL confirm that prior to issuance, the CA has validated each IP Address listed in the Certificate using at least one of the methods specified in this section.

You are confusing 3.2.2.5.4 with "no verification". It's done, just that the baseline trust that you are not an idiot and have some basis to confirm the ip address belongs to someone. And even that particular section has a sunset clause:

> CAs SHALL NOT perform validations using this method after July 31, 2019. Completed validations using this method SHALL NOT be re‐used for certificate issuance after July 31, 2019. Any certificate issued prior to August 1, 2019 containing an IP Address that was validated using any method that was permitted under the prior version of this Section 3.2.2.5 MAY continue to be used without revalidation until such certificate naturally expires.


Ah, I thought about my choice of phrase "None of them" and I regretted it but was busy.

I meant that it's not uncommon to just not issue such certificates, rather than you don't verify but you issue anyway, you don't verify because you always refuse to issue.


As a CA, you may sign a certificate for anything. Public CAs don't do it for IPs for obvious reasons, but if you're cloudflare or Google, you can coax them with enough money and goodwill to sign a cert for your very expensive quad-single-digit ip, especially if you manage to motivate that request with the fact that the IP is a DNS resolver and can't be pointed at by a domain in the first place


Some public CAs do. Google Public CA issues certs for IP SANs with 10d validity. I think ZeroSSL and SSL.com do to but not ISRG last time I checked.


Certificates can be issued for IPs too, CAs don't usually do it though.


Some CAs do it, for free even. ZeroSSL does iirc.


Google CA does too but only for max of 10 days


They're not. I see queries to dns.google in my pihole all the time.


You usually provide an upstream all IP DNS to query the DoH provider which ultimately resolves whatever queries need resolution.


Ooh, this is awesome! I can start using DNS as a database for even more things with what amounts to an automatic JSON endpoint handled for me.


Ah, yes, Route53, AWS' dirty-cheap globally-replicated database with a 100% uptime SLA.


Well, uhm, actually, what's stopping me from using this as a simple feature-flagging service?


I think the google example should read

    curl -H 'Accept: application/dns-json' 'https://dns.google/resolve?name=example.com&type=A'


yes, you're right - my bad - post updated




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: