context switch

and here ^context-switch2

https://tailscale.com/kb/1218/nextdns https://tailscale.com/kb/1403/control-d https://github.com/pi-hole/pi-hole

工作原理

dns (domain name system) 查找顺序:

  • local cache local resolver (ISP, DNS recursor) root top level authoritative

实践

执行 dig +trace google.com Using dig +trace to understand DNS resolution from start to finish | IBM

dns search domain

  • 这个是怎么工作的, 我在 dns config 里添加了 company.com 这个 search domain 之后, 怎么知道哪条 dns query 会自动加上这个 search domain?
    • 有的请求不会 respect search domain, 比如 browser;
    • 在 search domain 里加上了 company.com, browser 也不会使用
    • 但是有的会, 比如 ssh、ping
    • 有的情况又比较复杂, 比如 curl 的时候, 涉及到证书
      • curl https://blog/: 通过 search domain, dns lookup 能够 resolve 到正确的证书, 但是 http header 的 host 还是 blog, host 没有 blog 的证书, 只有 blog.mydomain.com;
  • search domain 是个 list, 会根据顺序来 search
    • ^ping-subdomain 这里的两张图, 在 search domain list 里, company.com 是第一个, mydomain.com 是第二个
    • blog.company.com dns lookup 成功了, 就不会再去 lookup blog.mydomain.com 了;
    • company.com 没有 notes 的时候, 就会 dns lookup 到 notes.mydomain.com

different records

A record / AAAA record

“The “A” stands for “address” and this is the most fundamental type of DNS record: it indicates the IP address of a given domain.”

  • 把 域名 和 ip 地址 联系起来
  • A record 只是 IPv4, IPv6 要用 AAAA record
  • 一个域名可以有多个 ip, aka, 一个域名可以有多个 A record Example:
  • use @ for root: root 就是域名本身; 可以直接填域名, 或者填 @
@    A    192.0.2.1      # 把 example.com 指向这个 ip
www  A    192.0.2.1      # 把 www.example.com 指向这个 ip

CNAME record

  • 就是个 alias

  • CNAME record 一定要指向 domain, 不能指向 ip 地址

  • CNAME record 会触发下一轮 dns lookup:

    Transclude of network-stack#dns-cname

  • CNAME 指向的 domain 是这个 subdomain 的 canonical name

For example, suppose blog.example.com has a CNAME record with a value of “example.com” (without the “blog”). This means when a DNS server hits the DNS records for blog.example.com, it actually triggers another DNS lookup to example.com, returning example.com’s IP address via its A record. In this case we would say that example.com is the canonical name (or true name) of blog.example.com.

  • 一个 subdomain 通过 CNAME record 指向另一个 domain, 只代表这两个 domain 有同样的 IP, 但不代表这两个 domain 呈现的内容一样:
    • blog.example.comexample.com 可以是同一个 ip 地址, 但是这两个 domain 对应对的是两个不同的网站, 呈现的内容不一样
    • web server 会根据 client 请求的 url 来呈现网页内容

A frequent misconception is that a CNAME record must always resolve to the same website as the domain it points to, but this is not the case. The CNAME record only points the client to the same IP address as the root domain. Once the client hits that IP address, the web server will still handle the URL accordingly. So for instance, blog.example.com might have a CNAME that points to example.com, directing the client to example.com’s IP address. But when the client actually connects to that IP address, the web server will look at the URL, see that it is blog.example.com, and deliver the blog page rather than the home page.

  • 如果一个 subdomain 被用于一个 CNAME record, 指向了另一个域名 (成为了另一个域名的 alias), 那这个 subdomain 不能被用于其他 record (MX, TXT, SOA record etc)

cname redirection?

https://webmasters.stackexchange.com/a/118053

  • CNAME 是把一个 domainA 指向 另一个 domainB, 是在告诉 dns server, 把 domainA resolve 成 domainB; 但是这个过程 不是 redirect!!
  • 客户端进行 dns lookup, lookup domainA, 最终拿到了 domainB 的 domain, 这时候还要重新进行一次 dns lookup ^dns-cname
    • 所以说, 在 dns server 那注册 cname, 把 domainA resolve 成 domainB 的过程, 最终会导致 客户端 拿到 domainB 的 ip 地址, 客户端的 http 请求是发到 domainB 的 ip 地址
  • 对于 http 请求来说, dns resolution 的时候, 都还没有到 http 请求的那一步, 还没有 redirection 的概念
  • 只有在发 http 请求的时候, 如果是收到了 server 定义的 301 302 之类的, 才是 redirection

客户端最终发送的 http 请求是: destination ip:port 是 domainB 的 ip, http port (80)

GET / HTTP/1.1
Host: domainA

又有 CNAME 又有 redirect 的情况:

Note

如果是 CNAME 的话, client 请求的还是原来的 domain 的资源, 所以 browser url 展示的还是原来的 domain.
如果是 http 层的 redirect, client 实际上请求的是 redirect 过后的 domain, browser url 展示的是 redirect 过后的 domain, e.g., nusrejects.com.

cname and ssl cert

理解了上面 CNAME 的 redirect 的差别之后, 再来理解下, CNAME 和 ssl cert

  • 有一个 CNAME record 把 domainA 指向 domainB, 客户端访问的资源还是 domainA (http header 的 host 还是 domainA), 所以需要 domainA 的 cert
  • 因为有 CNAME, 带有 http header host: domain 的 请求 发到了 domainB 的 ip 上, 说明 host domainB 的 server 上要有 domainA 的 cert

host service and certs:

  • vercel 上的 cert: 能看到每个 subdomain 都有自己的 cert
  • cloudflare 用的是个 wildcard:

others

MX record and NS record

  • MX: mail exchange record, directs email to a mail server (as mentioned above, cannot point to a CNAME record)
  • [?] NS:

github page host quartz 遇到的问题

  • 对于 subdomain, 为什么需要 CNAME 指向 github.io, 而不是 A record 指向 github 的 ip?
  • 我用 subdomain A record 指向 github ip 的时候, 遇到的问题是, ssl 过不了; 我记得 cloudflare 的报错是 ssl 相关的, code 526: invalid ssl cert

cloudflare proxy mode

  • “DNS responses are overridden by Cloudflare IPs”: 也就是说, client 都不会感知到这条 dns record (invisible to client)

who is handling my cert?

  • dns 是 cloudflare, host 是 github、vercel; 这种情况, 是谁在 handle 我的 cert?
  • ^host-certs 可以看到, vercel 和 cloudflare 都是有我的 cert 的
  • 选了 cloudflare 做为 proxy 之后, visitor 就是和 cloudflare 进行连接; 从 visitor 的角度, 一定是 cloudflare 在 handle cert 了

cloudflare 有好 几种模式

  • off:
    • 啥都没有
    • 所有 https 请求都会变成 plaintext http

    “Setting your encryption mode to Off (not recommended) redirects any HTTPS request to plaintext HTTP.”

  • flexible:
    • visitor <-> cloudflare 之间 可以有 SSL 的, 如果 visitor 是 https, 那就是 encrypted
    • cloudflare <-> origin 之间没有 SSL, 是 plain http
  • Full:
    • visitor <-> cloudflare 之间 一定是 SSL
    • cloudflare <-> origin 之间会 match visitor 的请求 protocol; SSL 可有可无
      • 如果 visitor 发的是 https, cloudflare 和 origin 之间也是 https, 但是 cloudflare 不会 verify origin 的 cert
    • 使用场景: 源站的 cert 不一定是 publicly trusted 的 CA 发的, 可能是 self-signed cert

    “cloudflare matches the browser request protocol when connecting to the origin” “If your visitor uses http, then Cloudflare connects to the origin using plaintext HTTP and vice versa.”

  • full (strict):
    • visitor <-> cloudflare 之间 一定是 SSL
    • cloudflare <-> origin 之间会 match visitor 的请求 protocol; SSL 可有可无
      • 如果 visitor 发的是 https, cloudflare 和 origin 之间也是 https
    • cloudflare 对 origin 的 cert 有要求 ^strict-cert
      • 证书没过期
      • 得是 publicly trusted CA 发的, 或 cloudflare 自己的 origin CA 发的
      • 证书上的 domain 和 visitor 请求的 domaincname 指向的 domain 也得保持一致
  • strict (SSL-Only Origin Pull):
    • visitor <-> cloudflare 之间 一定是 SSL
    • cloudflare <-> origin 之间 一定是 SSL
    • cloudflare 和 host 之间一定会用 SSL, 不管 visitor 的请求是 http 还是 https
    • cloudflare 对 origin 的证书也有上面的要求
      Transclude of #strict-cert

visitor <-> cloudflare 之间 一定是 SSL“:

  • 如果 visitor 请求 http, 都会被转成 https

  • 和 off mode 相反, off mode 会把 https 都转成 http

  • http 的请求会被 redirect, cloudflare 收到 http 的请求直接丢个 301

  • [?] 我把 apex domain 指向一个 ip, 假设这个 ip 是美国的, 那我每次请求这个domain的资源的时候, 都是把流量打到美国? 还是说大部分时候我的流量都会被cache在cdn上, 实际上没什么请求

  • [?] 这种静态资源是不是 build 完了之后就可以直接放到 cdn 上 cache 着了? 是不是build 完之后都不需要请求了

  • SSL/TLS certification: For services that provide HTTPS certificates, using their recommended CNAME setup often simplifies the SSL certificate provisioning process.”

full breakdown

proxy mode(SSL full)what to pay attention toblog.domain.com CNAME to user.github.ioblog.domain.com A record to user.github.iodomain.com A record to user.github.io
visitor <-> clouflaredns queryvisitor finding IP for blog.domain.comvisitor finding IP for blog.domain.comvisitor finding IP for domain.com
dns responsecloudflare overwrites dns response, returning cloudflare’s own IP (instead of returning user.github.io as normal)cloudflare overwrites dns response, returning cloudflare’s own IP (instead of returning user.github.io as normal)cloudflare overwrites dns response, returning cloudflare’s own IP (instead of returning user.github.io as normal)
tls sniblog.domain.comblog.domain.comdomain.com
who handles TLS certcloudflare presents cert for blog.domain.comcloudflare presents cert for blog.domain.comcloudflare presents cert for domain.com
http destinationIP address of a Cloudflare edge serverIP address of a Cloudflare edge serverIP address of a Cloudflare edge server
http header host valueblog.domain.comblog.domain.comdomain.com
clouflare <-> github (aka origin request)dns querycloudflare finding IP for user.github.iono second DNS, since no CNAME is used (no CNAME used, cloudflare is NOT EVEN AWARE OF user.github.io)
dns responsegithub’s IPN/A
tls sniuser.github.ioblog.mydomain.com
who handles certgithub presents cert for user.github.iogithub presents cert for blog.mydomain.com (github must have cert, otherwise Cloudflare TLS/SSL full(strict) will FAIL)
http destinationgithub’s IPgithub’s IP in the A record
http header host valueblog.mydomain.com (github uses this http host header value to map to specific site to respond)blog.mydomain.com

如果是 A record, 那在 cloudflare 上的记录就根本没有 user.github.io

  • [?] subdomain A Record 的时候 SSL 过不了, 因为 github 没有 subdomain 的 cert; 但是 为什么 apex domain 用 a record 又可以呢?

“Since you’re using A records, GitHub may not have proper verification that you own this domain, GitHub can’t confidently serve the correct SSL certificate for your domain” - claude

  • [?] 为什么? 展开学习下

dns sinkhole

wikipedia - dns sinkhole:

  • “dns servers hand out non-routable addresses for specific domain”
  • non-routable address: 0.0.0.0

怎么通过 dns 实现 ad block 的

首先, ad 的产生:

  • 用户请求一个网站的 url
  • 服务器返回内容, 内容中夹带了广告的 url
  • 浏览器在处理服务器返回的时候, 会去请求这些广告 url
  • 广告服务器返回广告, 浏览器把广告加载出来 通过 dns 实现 ad block:
  • 把常见的广告 domain 都屏蔽掉
  • 浏览器在请求这些广告 url 的时候, dns 就会返回个 0.0.0.0 这样的 non-routable address
  • 广告就请求不到了, 在本来有广告的地方就变成空白 能通过 dns 实现广告拦截的主要原因, 是因为 广告域名 和 主网站域名 不是同一个, 要分开进行 dns lookup

dns 服务器的上下游

  • 从 query response 的角度来说, 层级高的 dns server 就是 upstream server
  • 像是这里 stackoverflow - http upstream/downstream 所说的, “all messages flow from upstream to downstream”

DNS sinkhole:

The higher up the DNS resolution chain the sinkhole is, the more requests will fail, because of the greater number of lower nameservers that in turn serve a greater number of clients. Some of the larger botnets have been made unusable by top-level domain sinkholes that span the entire Internet.

  • 层级越高的 dns server, 会被越多的层级低的 dns server 请求

DoH DoT

  • dns over https: 用 https 来发 dns query, port 443
    • dns query 就和其他 https traffic 混在一起了, 就很难被网络 monitoring 给发现了
  • dns over TLS: 不用 udp, 用 tcp + TLS 来发 dns query, port 853
    • 企业可以监控 port 853 的流量, 可以把 853 的流量都拦截
  • 用这两个都是通过 TLS 把 dns query 加密起来, 中间人就看不到 dns query 的内容 (不能通过 dns 知道客户端想要访问什么网站), 只能看到是个 dns query
  • 但是客户端拿到 dns query 的结果之后, 还要再请求这个 ip address, 中间人还是能看到客户端想要访问什么网站
  • 得 DoH DoT 和 proxy 啥的结合

Multicast DNS

  • 在 local network 里的 dns
  • 不依赖于一个单一的 dns server
  • 向 local network 里的设备广播一个 dns query
  • 如果 dns query 里的域名符合某个机器的话, 它就会回复自己的 ip

others

场景: 在一个 subnet (如企业环境) 里配置 dns server, 然后让这个 subnet 里的所有设备都使用这个 dns server 问题: 用户可能会在自己的机器上手动修改 dns server, 绕过企业的 dns server; 如何防止这种现象发生? 回答:

  • 防火墙拦截: 只允许 dns 流量 (port 53) 发到指定机器, 不允许发往其他地址的 dns 请求
  • dns transparent proxy: 把发往非指定机器的 port 53 的流量转发到指定机器
  • NAT 重定向: 把发往 port 53 的请求在 router 这层通过 NAT 重定向到指定机器
  • 强制使用 dhcp 配置: 强制用户使用 DHCP 获取 动态 ip 和 dns 地址, 防止用户手动配置 静态 ip 和 dns 地址 以上方法对 Dns over HTTPS 都有效吗?
  • 前三个方法都是通过 port 53 来实现的, DoH 的本质是 https 请求, 端口是 443
  • 强制 DHCP 配置也没用, 本身 强制 DHCP 是为了强制在子网设备上添加上 dns server 的配置; 但是 DoH 是发 https 请求, 直接无视设备上的 dns 配置

https://adguard-dns.io/en/public-dns.html

  • [?] nslookup -q=cname example.com 这里出来的结果, non-authoritative answer 是啥? authoritative 是 cloudflare 作为 dns provider 的回答, non-auth 是啥?