Route 53 支援 DNS64,以及 NAT Gateway 支援 NAT64

AWS 宣佈了一套機制,讓 IPv6-only 的機器可以連到 IPv4-only 的服務:「Let Your IPv6-only Workloads Connect to IPv4 Services」。

首先是 DNS64,針對只有 IPv4-only 的 A record 自動加上 AAAA record (如果已經有 AAAA record 的則不變),這邊提到的 64:ff9b::/96 是來自 DNS64 標準內的規範:

The DNS resolver first checks if the record contains an IPv6 address (AAAA record). If it does, the IPv6 address is returned. The IPv6 host can connect to the service using just IPv6. When the record only contains an IPv4 address, the Route 53 resolver synthesizes an IPv6 address by prepending the well-known 64:ff9b::/96 prefix to the IPv4 address.

再來就是 NAT Gateway 可以把 64:ff9b::/96 透過 NAT64 轉到 IPv4 network 上:

You may configure subnet routing to send all packets starting with 64:ff9b::/96 to the NAT gateway. The NAT gateway recognizes the IPv6 address prefix, extracts the IPv4 address from it, and initiates an IPv4 connection to the destination. As usual, the source IPv4 address is the IPv4 address of the NAT gateway itself.

由於有些 protocol 會帶 IP address 資訊,所以不能保證 NAT64 一定會動,但大多數的情況應該是可以解決,至少提供了 IPv6-only server 連到 IPv4-only network 上的方法...

語意化的 CSS 設定 (Contextual awareness) 減少 side effect

前幾天在 Hacker News 上看到 CSS-Tricks 上的文章「You want enabling CSS selectors, not disabling ones」這篇,在講 CSS 的設計問題,對應的 Hacker News 討論在「You want enabling CSS selectors, not disabling ones (css-tricks.com)」這邊。

文章裡面引用文章裡面提到的文章也都蠻值得看的:「You want enabling CSS selectors, not disabling ones (2021/03/08)」、「Axiomatic CSS and Lobotomized Owls (2014/10/21)」。

其中 2014 年那篇居然是 A List Apart 上的文章,好久沒看到了這個站了... 也發現居然不在 RSS/Atom feed 清單裡面,重新訂起來。

這邊拿 A List Apart 上面的圖來說明,出自「CONTEXTUAL AWARENESS」這個段落的例子。

在很多段落時,我們常使用 margin-top (或是 margin-bottom,例子可以自己變換) 來設定間距,也就是 (a) 的例子。但可以看到第一個元素就會「多出來」:

A List Apart 裡面提到的解法是 * + * (或是 p + p,看你怎麼選 CSS selector),也就是前面有相鄰的元素才需要設定 margin-top

回到 CSS-Tracks 上的文章,有些人會這樣指定 CSS (這邊用 margin-bottom,所以搭搭配的是 :last-child):

.card {
  margin-bottom: 1rem;
}

/* Wait but not on the last one!! */
.parent-of-cards :last-child {
  margin-bottom: 0;
}

也就是全部都先加上 margin-bottom,然後針對最後一個元素拿掉 margin-bottom。而另外的版本則是:

.card:not(:last-child) {
  margin-bottom: 1rem;
}

或是:

/* Only space them out if they stack */
.card + .card {
  margin-top: 1rem;
}

這樣就不用蓋來蓋去,可以降低 side effect:margin-bottom 可能會在其他地方指定,你設為 0 可能是不對的值;另外寫成兩組時 CSS 的優先順序其實是不同的,Mozilla 的 Specificity 可以參考,Specifishity 這個網站給了很有趣的 cheatsheet (你要先了解才能當 cheatsheet 用):

在文章最後面有提到 gap 這個用法,查了一下「CSS property: gap: Supported in Grid Layout」,看起來現代的瀏覽器應該是都支援了,不過如果要支援舊的瀏覽器的話就是問題...

另外順便提一下,早期大家會偏好用 + 是因為 IE7+,而 :last-child 則是 IE9+ 了:「CSS Selectors and Pseudo Selectors and browser support」。雖然現在看起都是時代的眼淚了,但可以了解一下 2014 年的時候為什麼會偏好 + 的設計。

Ansible 的爭論

前幾天在 Hacker News Daily 上看到「Five Ansible Techniques I Wish I’d Known Earlier」這篇,裡面提到了一些 Ansible 的用法還蠻有用的,算是開始用 Ansible 後應該都會有幫助的用法... 不過 Hacker News 上的討論「Ansible Techniques I Wish I’d Known Earlier (zwischenzugs.com)」比較精彩...

目前在頂端的留言對 Ansible 幹到不行,尤其是那個 YAML 格式:

Ansible is abysmal. I don't know why anyone still chooses it. It's a mess of yaml and what feels like a million yaml files that is always extremely hard to follow. Honestly writing some python, or bash is a lot easier to follow, read, and understand. The only thing it has going for it is the inventory system. I wish ansible would die already.

然後講到 bash 與 python 之類的工具時有人提到 idempotent:

>bash and python
Neither of those of idempotent.

馬上就有人幹勦,大多數人在寫 Ansible playbook 時根本沒人在注意 idempotent,而且一堆 shell script 的東西被塞進 YAML 只能說痛苦 XDDD

Most of the ansible roles I come across written by my team are not idempotent either, its a huge lie that Ansible is idempotent. Its idempotent if you put the effort into make it be but if I see tons of shell or command module invocations without prerequisite checks to see if the work should be done. Most devs I see using Ansible treat it like a shell script written in YAML and to that purpose it sucks.

我自己目前會挑 Ansible 主要還是因為 server 不需要另外裝軟體,是個 production 為導向的設計,再更大的時候就要想一下要怎麼繼續搞下去了...

Amazon 取得了整塊 3.0.0.0/8 的使用權...

Hacker News 上的「Tell HN: Amazon now owns 3.0.0.0/8」這邊看到 Amazon (AWS?) 拿到 3.0.0.0/8 的使用權了,而且已經有人在 Elastic IP 拿到了:

Apparently bought in two chunks: 3.0.0.0/9 and 3.128.0.0/9.
Previous owner was GE.

Anecdotal reports across the Internet that AWS EIPs are now being assigned in that range.

https://whois.arin.net/rest/net/NET-3-0-0-0-1.html

https://whois.arin.net/rest/net/NET-3-128-0-0-1.html

可以在上面提到的兩個網址確認:「whois.arin.net/rest/net/NET-3-0-0-0-1.html」、「whois.arin.net/rest/net/NET-3-128-0-0-1.html」,前半段在 2017/12/20 註冊,後半段在 2018/06/25 註冊...

另外有人在下面提到 Amazon 說不定會推出 3.3.3.3 之類的 DNS Resolver 服務?至少先把 3.3.3.0/24 這段預留起來?

GitHub 透過 Let's Encrypt 提供自訂網域的 HTTPS 服務

以往在 GitHub 上如果要使用 HTTPS 只能使用 *.github.io 網域,現在 GitHub 宣佈透過 Let's Encrypt 的服務支援了:「Custom domains on GitHub Pages gain support for HTTPS」:

We have partnered with the certificate authority Let’s Encrypt on this project. As supporters of Let’s Encrypt’s mission to make the web more secure for everyone, we’ve officially become Silver-level sponsors of the initiative.

不過目前只支援 CNAME record (標準) 或是 ALIAS record 的方式 (非標準,也稱為 ANAME,有些 DNS provider 有支援,主要用在網域本身 (i.e. root domain) 無法使用 CNAME)。

如果是使用 A record,則是需要更新 IP 位置:

If you are using A records, you must update your site’s DNS records with new IP addresses. Please see our guide to setting up your custom domain with Pages and update any A records you might have set.

另外也提供 HTTP 轉 HTTPS 的選項:

以前 HTTPS 還得自己弄伺服器處理,現在可以直接往 GitHub 上丟了...

另外用查出來的 IP 看了一下架構,IP 是 Fastly 的,所以應該是跟 Fastly 合作,但不確定是 Fastly 自己搞定 Let's Encrypt 的憑證,或是 Fastly 提供 Port 80/443 的 TCP Proxy?

PChome 修正了問題,以及 RFC 4074 的說明

早些時候測試發現 PChome 已經修正了之前提到的問題:「PChome 24h 連線會慢的原因...」、「PChome 24h 連線會慢的原因... (續篇)」,這邊除了整理一下以外,也要修正之前文章裡的錯誤。

在 RFC 4074 (Common Misbehavior Against DNS Queries for IPv6 Addresses) 裡面提到了當你只有 IPv4 address 時,DNS server 要怎麼回應的問題。

在「3. Expected Behavior」說明了正確的作法,當只有 A RR 沒有 AAAA RR 的時候,應該要傳回 NOERROR,而 answer section 裡面不要放東西:

Suppose that an authoritative server has an A RR but has no AAAA RR for a host name. Then, the server should return a response to a query for an AAAA RR of the name with the response code (RCODE) being 0 (indicating no error) and with an empty answer section (see Sections 4.3.2 and 6.2.4 of [1]). Such a response indicates that there is at least one RR of a different type than AAAA for the queried name, and the stub resolver can then look for A RRs.

在「4.2. Return "Name Error"」裡提到,如果傳回 NXDOMAIN (3),表示查詢的這個名稱完全沒有 RR,而不僅僅限於 AAAA record,這就是我犯的錯誤 (在前面的文章建議傳回 NXDOMAIN):

This type of server returns a response with RCODE 3 ("Name Error") to a query for an AAAA RR, indicating that it does not have any RRs of any type for the queried name.

With this response, the stub resolver may immediately give up and never fall back. Even if the resolver retries with a query for an A RR, the negative response for the name has been cached in the caching server, and the caching server will simply return the negative response. As a result, the stub resolver considers this to be a fatal error in name resolution.

Several examples of this behavior are known to the authors. As of this writing, all have been fixed.

PChome 這次的修正回應了正確的值 (而不是我提到的 NXDOMAIN):

$ dig shopping.gs1.pchome.com.tw aaaa @ns1.gs1.pchome.com.tw

; <<>> DiG 9.9.5-3ubuntu0.16-Ubuntu <<>> shopping.gs1.pchome.com.tw aaaa @ns1.gs1.pchome.com.tw
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<<<- opcode: QUERY, status: NOERROR, id: 40767
;; flags: qr aa rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1280
;; QUESTION SECTION:
;shopping.gs1.pchome.com.tw.    IN      AAAA

;; AUTHORITY SECTION:
gs1.pchome.com.tw.      5       IN      SOA     ns1.gs1.pchome.com.tw. root.dns.pchome.com.tw. 20171123 3600 3 3600 5

;; Query time: 16 msec
;; SERVER: 210.242.216.91#53(210.242.216.91)
;; WHEN: Fri Nov 24 01:44:52 CST 2017
;; MSG SIZE  rcvd: 134

另外 RFC 也有一些其他的文件可以參考,像是 RFC 2308 (Negative Caching of DNS Queries (DNS NCACHE))、RFC 4697 (Observed DNS Resolution Misbehavior) 以及 RFC 8020 (NXDOMAIN: There Really Is Nothing Underneath),這些文件描述了蠻多常見的問題以及正確的處理方法,讀完對於現在愈來愈複雜的 DNS 架構有不少幫助。

自適應演算法與 A/B Testing

Hacker News Daily 上看到三年前的舊文章,講自適應演算法取代常見的 A/B testing:「20 lines of code that will beat A/B testing every time」。

就拿原文裡面的例子來說明,我想要測試 "Buy Now!" 這個按鈕的顏色來得知哪個顏色的 click rate 最高,而我有 Orange、Green 以及 White 三種顏色為候選。

一開始我初始值都設為「展示了 1 次,被點擊了 1 次」,所以每個點擊率都是 100%:

Orange Green White
1/1 = 100% 1/1=100% 1/1=100%

然後你的網站上只要展示「點擊率最高的那個顏色」,並且記錄下來展示次數與點擊率就好,而整個過程會是自適應而被自動被淘汰掉,最後可能會變成這樣,就會固定是綠色的了:

Orange Green White
114/4071 = 2.8% 205/6385=3.2% 59/2264=2.6%

而這樣做的好處是節省人力成本:你不需要 A/B Testing 完後再人工介入修改。

對於更複雜的例子,雖然原文沒有提到,但你可以直接展開來做,舉例來說,你假設顏色與地區兩個變數所帶出來的 click rate 不是 i.i.d.,那麼你可以針對每個 Color + Region 都存數值去比較。

當然還是有他的問題 (comment 有提到),不過可以架出一些全自動的 workaround 來解決,比起要兩階段人工介入省了不少人力。

另外可以想像在大的產品上會遇到效能問題 (因為對同樣資料大量的 read + write),但這個數字不需要太即時,只要量大就會準確,所以技術上也可以解決...

關於 CSS 中 :visited 的隱私問題

在七年半前 (2008 年八月) 寫的「利用 CSS 產生的隱私問題」文章,最近好像是因為 Rplus ChenFacebook 上的這邊提到而又有不少點擊進來,不過這個問題在 2010 年左右已經被解決了。

可以參考 MDN 上「:visited - CSS」的說明,以及當時 Mozilla 所發佈的文章:「privacy-related changes coming to CSS :visited」。

由於隱私問題,Mozilla 的作法是限制 :visited 可以改變的項目,只剩下少數與呈現方式有關的屬性可以用:

For privacy reasons, browsers strictly limit the styles you can apply using an element selected by this pseudo-class: only color, background-color, border-color, border-bottom-color, border-left-color, border-right-color, border-top-color, outline-color, column-rule-color, fill and stroke.

另外各種想要取得 :visited 的 CSS 資訊的方法,也會以沒有瀏覽過該網站重新計算,並且傳回假資料以確保還是不會洩漏:

The first change is that Gecko will lie to web applications under certain circumstances. In particular, getComputedStyle() and similar functions such as element.querySelector() always return values indicating that a user has never visited any of the links on a page.

ptt.cc 偶而會解不出 IP 的問題

Update:感謝正妹 wens 幫忙,現在已經先上 workaround 了,狀況暫時解除...

最近發現 168.95.1.1 有時會找不到 ptt.cc 這個 domain (參考 gist:9995821),原因是 ptt.cc 在 whois 上登記的是:

Name Server: NS0.PTT.CC
Name Server: NS1.PTT.CC
Name Server: NSOUT1.PTT.CC

用 dig 對 cc 的 NS server 查詢也可以確認:

;; AUTHORITY SECTION:
ptt.cc.                 172800  IN      NS      ns0.ptt.cc.
ptt.cc.                 172800  IN      NS      ns1.ptt.cc.
ptt.cc.                 172800  IN      NS      nsout1.ptt.cc.

;; ADDITIONAL SECTION:
ns1.ptt.cc.             172800  IN      A       140.112.172.10
ns0.ptt.cc.             172800  IN      A       140.112.172.16
nsout1.ptt.cc.          172800  IN      A       112.121.80.227

但 ptt.cc 的三台 NS server 上都找不到 nsout1.ptt.cc:

; <<>> DiG 9.8.1-P1 <<>> nsout1.ptt.cc @140.112.172.10

;; AUTHORITY SECTION:
ptt.cc.                 300     IN      SOA     ns0.ptt.cc. contact.ptt.cc. 2013102501 3600 900 2419200 3600
; <<>> DiG 9.8.1-P1 <<>> nsout1.ptt.cc @140.112.172.16

;; AUTHORITY SECTION:
ptt.cc.                 300     IN      SOA     ns0.ptt.cc. contact.ptt.cc. 2013102501 3600 900 2419200 3600
; <<>> DiG 9.8.1-P1 <<>> nsout1.ptt.cc @112.121.80.227

;; AUTHORITY SECTION:
ptt.cc.                 300     IN      SOA     ns0.ptt.cc. contact.ptt.cc. 2013102501 3600 900 2419200 3600

於是就錯亂了...

可以先解決的方法是先把 nsout1.ptt.cc 加上去,然後再規劃要怎麼修改兩邊的 record (Ptt 這側的 A/NS record,與 cc 的 A/NS record)。

補充一下,ptt2.cc 也有同樣問題。

GitHub 的網站功能上 CDN 了...

GitHub Pages 上 CDN 了:「Faster, More Awesome GitHub Pages」。

不過 Apex domain (也就是 domain 本身的 hostname) 無法設定 CNAME record,必須透過 A record,就沒辦法用到 CDN 的地區特性了...

CDN 用的是 Fastly,也丟進 SmokePing 監測好了...