dnspythonはPythonでDNSを扱う上で,もっともよく使用されているライブラリだと思います. 普通にクエリを投げたりする場合には,特に問題にはならないのですが,dnspythonを用いてコンテンツサーバを作成する場合などに,一部,ひっかかってしまうような挙動があります. 今回実験したdnspythonのバージョンは以下の通りです.

$ pip freeze | grep dns
dnspython==1.16.0

具体的には以下の部分です.

  • 255文字より長いテキストをホストしたい場合
  • ; が入っているTXTレコードをホストしたい場合

まぁ,具体的に言うと,DKIMを追加したい場合にハマったという所です.

まず,255文字より長いテキストをホストしたい場合は, "" で255文字以下になるようにテキストを分割する必要があります,

In [16]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, 'a'*255))
0 IN TXT "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

In [17]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, 'a'*256))
SyntaxError: string too long

と,255文字を超えるテキストを入れると,エラーになってしまいます. そこで,DNSの一般的な対処法として,255文字以下を1つの文字列として "" でくくります.

In [20]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, f"\"{'a'*255}\" \"{'b'*255}\""))
0 IN TXT "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

このようにすれば,255文字を超えるテキストを1つのレコードとしてホスト出来ます. RFC4408にて,スペースで分割されたTXT Recordは連結して取り合うべきだということになっているので,信じて行きましょう. Can I have a TXT or SPF record longer than 255 characters? - BIND 9

続いて, ; が入っているTXTレコードの問題です. これはdnspythonが ; を区切り文字の1つとして認識してるために発生する問題です. 具体的には, を入力したい場合は以下のように "" で囲わないと,末尾と認識されてその前のテキストまでがrdataとなります.

In [21]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, 'aaa; bbb'))
0 IN TXT "aaa"

In [22]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, '"aaa; bbb"'))
0 IN TXT "aaa; bbb"

また,少し面白い挙動だと,ミスで2回 "" で括った場合には,括ってない場合と同様の挙動にもなります,

In [25]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, '""aaa; bbb""'))
0 IN TXT "" "aaa"

ということで,DKIMをdnspythonで追加したい場合は,以下のように指定しましょう.

In [26]: print(dns.rdataset.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 0, '"v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwDc+AabcditzcdHYwOooW7HmqsPFzZUUb1nNqMj7ozyv/Q0WwwGJ+bdS4a9tO9roiT+VyyyMfIBoTdMNEWoXUMHafPgkOFPl5YO52pZM40bdXY/qtfT2nglJqS53zFFqB36q" "HoN9lgPRwP/e+ScCPlwHkcfIwD58ISU/lC5Bx+wIDAQAB"'))
0 IN TXT "v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwDc+AabcditzcdHYwOooW7HmqsPFzZUUb1nNqMj7ozyv/Q0WwwGJ+bdS4a9tO9roiT+VyyyMfIBoTdMNEWoXUMHafPgkOFPl5YO52pZM40bdXY/qtfT2nglJqS53zFFqB36q" "HoN9lgPRwP/e+ScCPlwHkcfIwD58ISU/lC5Bx+wIDAQAB"