Tag Archives: DNS

Fixing TXTRDATATooLong Errors for AWS Route 53

RFC 4408 3.1.3 says

     IN TXT "v=spf1 .... first" "second string..."
   MUST be treated as equivalent to
      IN TXT "v=spf1 .... firstsecond string..."
   SPF or TXT records containing multiple strings are useful in
   constructing records that would exceed the 255-byte maximum length of
   a string within a single TXT or SPF RR record.

so if you are getting error “TXTRDATATooLong” a solution for you will be splitting it into multiple strings within the same record set. For example, instead of:

"v=DKIM1; k=rsa; g=*; s=email; h=sha1; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx2zIlneFcE2skbzXjq5GudbHNntCGNN9A2RZGC/trRpTXzT/+oymxCytrEsmrwtvKdbTnkkWOxSEUcwU2cffGeaMxgZpONCu+qf5prxZCTMZcHm9p2CwCgFx3

you can pick a split point where each part is less than 255 characters long and put [double quote][space][double quote] 

for example I tried:

"v=DKIM1; k=rsa; g=*; s=email; h=sha1; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx2zIlneFcE2skbzXjq5GudbHNntCGNN9A2RZGC/trRpTXzT/+oymxCytrEsmrwtvKdbTnkkWOxSEUcwU2cffGeaMxgZpONCu+qf5prxZCT" "MZcHm9p2CwCgFx3reSF+ZmoaOvvgVL5TKTzYZK7jRktQxPdTvk3/yj71NQqBGatLQIDAQAB;"

and as a result I’ve got:

dig -t TXT long.xxxxxx.yyyy @ns-iiii.awsdns-jj.org.
long.xxxxxxx.yyyy. 300    IN      TXT     "v=DKIM1\; k=rsa\; g=*\; s=email\; h=sha1\; t=s\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDx2zIlneFcE2skbzXjq5GudbHNntCGNN9A2RZGC/trRpTXzT/+oymxCytrEsmrwtvKdbTnkkWOxSEUcwU2cffGeaMxgZpONCu+qf5prxZCT" "MZcHm9p2CwCgFx3reSF+ZmoaOvvgVL5TKTzYZK7jRktQxPdTvk3/yj71NQqBGatLQIDAQAB\;"

Note that returned TXT contains [double quote][space][double quote] , however the RFC above mandates that string to be treated as the same as concatenated one.

Note that your example does the same too on 128 character boundary

dig s2048._domainkey.yahoo.com TXT                                                                                                                                      /workspace/stepany-HaasControlAPI-development
;; Truncated, retrying in TCP mode.
; <<>> DiG 9.4.2 <<>> s2048._domainkey.yahoo.com TXT
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61356
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
;s2048._domainkey.yahoo.com.    IN      TXT
s2048._domainkey.yahoo.com. 61881 IN    TXT     "k=rsa\; t=y\; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoWufgbWw58MczUGbMv176RaxdZGOMkQmn8OOJ/HGoQ6dalSMWiLaj8IMcHC1cubJx2gz" "iAPQHVPtFYayyLA4ayJUSNk10/uqfByiU8qiPCE4JSFrpxflhMIKV4bt+g1uHw7wLzguCf4YAoR6XxUKRsAoHuoF7M+v6bMZ/X1G+viWHkBl4UfgJQ6O8F1ckKKoZ5K" "qUkJH5pDaqbgs+F3PpyiAUQfB6EEzOA1KMPRWJGpzgPtKoukDcQuKUw9GAul7kSIyEcizqrbaUKNLGAmz0elkqRnzIsVpz6jdT1/YV5Ri6YUOQ5sN5bqNzZ8TxoQlkb" "VRy6eKOjUnoSSTmSAhwIDAQAB\; n=A 2048 bit key\;"

Configuring White-Label Name Servers with AWS Route53

Create a Route 53 reusable delegation set

aws route53 create-reusable-delegation-set --caller-reference ns-example-com


    "Location": "https://route53.amazonaws.com/2013-04-01/delegationset/N3PIG1YNLUZGKS",
    "DelegationSet": {
        "Id": "/delegationset/N3PIG1YNLUZGKS",
        "CallerReference": "ns-example-com",
        "NameServers": [

Note down the delegation set ID:


Get IP of delegated name servers

dig +short ns-30.awsdns-03.com
dig +short ns-1037.awsdns-01.org
dig +short ns-1693.awsdns-19.co.uk
dig +short ns-673.awsdns-20.net
dig AAAA +short ns-30.awsdns-03.com
dig AAAA +short ns-1037.awsdns-01.org
dig AAAA +short ns-1693.awsdns-19.co.uk
dig AAAA +short ns-673.awsdns-20.net

Then add these records with your domain registrar and in your current DNS providers. Set TTL to 60s.

Create new zone with white-label name servers

aws route53 create-hosted-zone --caller-reference example-tld --name example.tld --delegation-set-id /delegationset/N3PIG1YNLUZGKS


    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z7RED47DZVVWP",
    "HostedZone": {
        "Id": "/hostedzone/Z7RED47DZVVWP",
        "Name": "example.tld.",
        "CallerReference": "example-tld",
        "Config": {
            "PrivateZone": false
        "ResourceRecordSetCount": 2
    "ChangeInfo": {
        "Id": "/change/C2IAGSQG1G1LCZ",
        "Status": "PENDING",
        "SubmittedAt": "2019-03-10T13:10:53.358Z"
    "DelegationSet": {
        "Id": "/delegationset/N3PIG1YNLUZGKS",
        "CallerReference": "ns-example-com",
        "NameServers": [

Update NS and SOA records

Prepare to change name servers, first lower TTL for the following records:

  • NS records: 172800 to 60 seconds
  • SOA record: 900 to 60 seconds

Dynamic DNS Support with CloudFlare

I’ve been using Route53 and aws-cli to dynamically update DNS for my home server for a long time. This time I tried CloudFlare with dynamic DNS support.

First install cloudflare-cli:

$ npm install -g cloudflare-cli

Configure your bash script:


# Setup envrionment
export PATH=/usr/local/bin:/usr/local/sbin:$PATH

# First install cloudflare-cli on OS X:
# npm install -g cloudflare-cli

# Add this script to cron, run it every 10 mins:
# */10 * * * * bash ~/Dropbox/Mac/Backups/Scripts/server-update-cloudflare.sh

# CloudFlare API key

# CloudFlare account
ACCOUNT="[email protected]"

# Domain name

# The record you want to update e.g. hello, use the bare domain if you want to update root (@) record

# cfcli location
CFCLI=`which cfcli`

# Log file location

# Get the external IP address
IP=`dig +short myip.opendns.com @resolver1.opendns.com`
IPOLD=`$CFCLI listrecords | pcregrep -o1 -e '.+?A.+?example\.com.+?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).+'`
IPVPN=`ifconfig | grep -o ppp`
# Valid IP
function valid_ip() {
  local ip=$1
  local stat=1
  if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
    [[ ${ip[0]} -le 255 &amp;&amp; ${ip[1]} -le 255 \
      &amp;&amp; ${ip[2]} -le 255 &amp;&amp; ${ip[3]} -le 255 ]]
  return $stat
# Compare IPs
if ! valid_ip $IP; then
  echo "[`date`] ERROR: Invalid IP '$IP'" &gt;&gt; "$LOGFILE"
  exit 1
# Check if the IP has changed
if [ "$IP" == "$IPOLD" ] || [[ $IPVPN ]]; then
  echo "[`date`] SAME: $IP $IPVPN" &gt;&gt; "$LOGFILE"
  exit 0
  echo "[`date`] UPDATE: $IPOLD &gt;&gt;&gt; $IP" &gt;&gt; "$LOGFILE"
  $CFCLI -k $TOKEN -e $ACCOUNT -d $DOMAIN editrecord $RECORD $IP

Run it with cron:

*/10 * * * * bash ~/Dropbox/Mac/Backups/Scripts/server-update-cloudflare.sh

How to Configure Multiple DNS Redirections (PlexConnect-like Service) for Apple TV


  • Apple TV 通過修改 DNS,可以觀看 享看
  • 同時也可以通過本地架設 Plex+PlexConnect 來觀看 Plex


  • 「享看」官方的 DNS 和 PlexConnect 都默認劫持 Apple TV 中的 Trailers 頻道,同時使用會造成衝突
  • OS X Server 在 Mavericks 中對 HTTP 的 80 端口享有絕對控制權,而 PlexConnect 需要獨佔 80 端口


  • 在 OS X Server 上安裝 Plex、PlexConnect 和 Dnsmasq
  • 通過在 OS X Server 上創建新介面,設置額外 IP,避免 PlexConnect 80 端口衝突
  • 本地架設 Dnsmasq,同時劫持 Apple TV 上兩個不同頻道來實現「享看」和 PlexConnect 共存


  • 裝有 OS X 的電腦一部
  • Apple TV 一部
  • Plex 一只
  • PlexConnect 一只
  • Dnsmasq 一只


  • X Server,DHCP with manual address(或通過 MAC 地址綁定亦可,主要是需要保持主 IP 固定)
  • X Server,額外 IP(PlexConnect),DHCP with manual address

為 OS X Server 設置額外 IP

由於 OS X 上已經安裝過 Server app,為了避免與系統的 80 端口衝突,我們必須將 PlexConnect 的 80 端口指向額外的 IP。首先我們 duplicate 現有的網絡(或者直接創建新介面),Wi-Fi、以太均可,為了區分,可以將此服務命名為「PlexConnect」,IP 獲取方法為 DHCP with manual address,地址為具體情況請根據自己的路由分配狀況自行修改),然後將 DNS 設置為,即 Dnsmasq 所在的主 IP,Dnsmasq 的相關設置我們會在接下來講,其他設置保持默認

Dnsmasq 安裝與配置

推薦的方法是通過 Homebrew 安裝:

brew install dnsmasq


然後我們需要 vi /usr/local/etc/dnsmasq.conf 來修改 Dnsmasq 的配置,Dnsmasq 的默認配置是無法作為 DNS server 使用的,以下是必備的配置:

# Listen on this specific port instead of the standard DNS port
# (53). Setting this to zero completely disables DNS function,
# leaving only DHCP and/or TFTP.
# The following two options make you a better netizen, since they
# tell dnsmasq to filter out queries which the public DNS cannot
# answer, and which load the servers (especially the root servers)
# unnecessarily. If you have a dial-on-demand link they also stop
# these requests from bringing up the link unnecessarily.
# Never forward plain names (without a dot or domain part)
# Never forward addresses in the non-routed address spaces.
# DNS servers
# Add local-only domains here, queries in these domains are answered
# from /etc/hosts or DHCP only.
# Chinese Apple TV DNS
# PlexConnect DNS
# If you want dnsmasq to listen for DHCP and DNS requests only on
# specified interfaces (and the loopback) give the name of the
# interface (eg eth0) here.
# Repeat the line for more than one interface.
# Or you can specify which interface _not_ to listen on
# Or which to listen on by address (remember to include if
# you use this.)

view raw
hosted with ❤ by GitHub

  • port=53:DNS 默認端口,這裡我們需要禁用 Server app 里的 DNS
  • domain-needed:不轉發 plain name
  • bogus-priv:不轉發本地的 nslookup 請求
  • server=使用 Google 的 DNS 作為主、從 DNS,當然也可以選擇 ISP 提供的
  • local=/localnet/:讓本地域名走 /etc/hosts 或者 DHCP
  • address=/trailers.apple.com/享看 DNS,劫持 Apple TV 中的 Trailers,具體的 IP 地址請去享看官網參考
  • address=/secure.marketwatch.com/ DNS,劫持的是 WSJ,指向的是本地的 PlexConnect instance
  • listen-address:限制 Dnsmasq listen 指定地址,當然也可以按 interface 來限制

以上就是本教程的技巧所在,運用 Dnsmasq 對不同域名進行劫持,來實現「享看」和 PlexConnect 的共存,通過下面的方法可以測試是否設置正確:

dig trailers.apple.com @
dig secure.marketwatch.com @

執行下面命令可以啓動、停止 Dnsmasq

sudo launchctl stop homebrew.mxcl.dnsmasq
sudo launchctl start homebrew.mxcl.dnsmasq

PlexConnect 的安裝與配置

PlexConnect 官方提供有 詳細的教程,具體請參考官方的方法。在這裡我只對配置文件做詳細描述:

配置方面,為了避免與 Server app 的 httpd 衝突,我們要將 PlexConnect 的 server 綁定到之前設置的 上,另外我們也自己搭建了 Dnsmasq,需要把 PlexConnect 自帶的 DNS 服務禁用,於是我們的 PlexConnect 配置如下:

enable_plexgdm = True
ip_pms =
port_pms = 32400
enable_dnsserver = False
port_dnsserver = 53
ip_dnsmaster =
prevent_atv_update = True
enable_plexconnect_autodetect = False
ip_plexconnect =
hosttointercept = secure.marketwatch.com
port_webserver = 80
enable_webserver_ssl = True
port_ssl = 443
certfile = ./assets/certificates/wsj.pem
loglevel = Normal
logpath = .

view raw
hosted with ❤ by GitHub


  • enable_plexconnect_autodetect = False:因為我們有多 IP,避免造成混亂,我們把 Plex server 的 auto detect 禁用掉
  • ip_pms =既然禁用了,我就需要指定 Plex 的 IP
  • port_pms = 32400:相應的端口,我是用的默認端口
  • ip_plexconnect =指定 PlexConnect 的 IP 地址,這裡用我們創建的新 IP
  • enable_dnsserver = False:這裡禁用自帶 DNS
  • ip_dnsmaster =使用我們自己的 Dnsmasq
  • hosttointercept = secure.marketwatch.com:設置要劫持的域名,這裡要與 Dnsmasq 中的設置保持一致


當以上都設置好後,確認 Dnsmasq、PlexConnect 均已運行,在瀏覽器中打開,應該可以返回 httpd 的網站;打開 則是返回「Error response」,一個 code 403 的頁面,這時就是配置正確了

Apple TV 證書設置

測試都沒甚麼問題後,可以開始搞 Apple TV 的證書了,Apple TV 從某一版本更新後,所有的連接都走 HTTPS 了,這時候我們如果直接劫持就不會奏效,於是我們需要使用自己的證書並上傳到 Apple TV,讓 Apple TV 認為我們的劫持的內容才是真正的網站內容

設置方法比較簡單,可以通過 USB 線與 Apple TV 連接傳輸,也可以通過直接在 Apple TV 中直接添加,具體方法請參考 PlexConnect 文檔,需要注意的是,因為我們劫持了兩個頻道,所以兩個頻道的證書都需要進行 hack 並通過 profile 上傳到 Apple TV 中

證書設置好了,接下來就可以在 Apple TV 上進行測試了,將 Apple TV 的 DNS 改為,然後回到主屏分別進入 Trailers 和 WSJ 測試即可


  • 你可以設置讓 Dnsmasq 開機時自動加載,設置方法可以參考 brew info dnsmasq
  • 你也可以設置讓 PlexConnect 開機是自動加載,設置方法請參考 官方文檔
  • 如果你也有使用 Server app 自帶的 DNS,可以有多種方案,一是全轉移到 Dnsmasq(推薦);或者保持 nameddnsmasq 共存,但這時需要設置 named 只監聽;再或者全部轉移到自帶 DNS 服務,如果是後兩者,這篇文章 可能會幫到你
  • 如果你 Server app 中的 httpd 沒跑任何服務,也可以通過 配置反向代理 來將系統的 web 服務轉向 PlexConnect 的內容