Featured image of post Google Play ストアの中国CDN:暗号学入門から分流戦略の最適化まで

Google Play ストアの中国CDN:暗号学入門から分流戦略の最適化まで

ブロックされているサービスが中国CDNを持っているのは、なかなか興味深い。

Mihomoのルールをカスタマイズした後、Google Playからアプリをダウンロードすると、なぜかずっとローディングが続くようになりました。しかし、他のルールを使うと問題なく動作します。これは非常に奇妙な現象です。そこで、Mihomoのカーネルログを確認してみました。

1
2
3
4
5
play-lh.googleusercontent.com:443 match RuleSet(cdn_domainset) using 静的リソース[🇭🇰 香港 07]
play.googleapis.com:443 match GeoSite(GFW) using ノード選択[🇭🇰 香港 07]
play-lh.googleusercontent.com:443 match RuleSet(cdn_domainset) using 静的リソース[🇭🇰 香港 07]
play-fe.googleapis.com:443 match GeoSite(GFW) using ノード選択[🇭🇰 香港 07]
services.googleapis.cn:443 match GeoSite(CN) using グローバルダイレクト[DIRECT]

(上記のログは簡略化されています)

中国国内向けのスマートフォンにプリインストールされているGoogle Playサービスは、services.googleapis.comではなくservices.googleapis.cnというドメインを使用しています。このドメインは、ほとんどの分流ルールでダイレクト接続に設定されています。ここに問題があるのです。このドメインをプロキシに分流するようにルールを修正すれば、問題は解決します!

……本当に解決するのでしょうか?

1
2
3
rr4---sn-j5o7dn7s.xn--ngstr-lra8j.com:443 match Match using 漏網の魚[🇭🇰 香港 07]
rr2---sn-j5o7dn7s.xn--ngstr-lra8j.com:443 match Match using 漏網の魚[🇭🇰 香港 07]
rr1---sn-j5o76n7z.xn--ngstr-lra8j.com:443 match Match using 漏網の魚[🇭🇰 香港 07]

待ってください、なぜPlayストアからアプリをダウンロードするたびにこれらの奇妙なドメインが現れるのでしょうか?オンラインで調べてみると、新たな世界が開けました。

Googleとは対照的でありながらも似ているÅngströ

xn--ngstr-lra8j.comというドメインを見て、ドメインに詳しい人はすぐにこれがPunyCodeエンコーディングであることに気づくでしょう。この文字列をデコードすると、ångströ.comとなります。Anders Jonas Ångströmは、スウェーデンの物理学者で、分光学の創始者です。1エングストローム(Ångström)は、彼を記念して名付けられた長さの単位で、$ 1 Å = 10^{-10} m = \frac{1}{10} nm $と定義され、原子や分子のサイズ、光の波長など、非常に短い距離を表すために使用されます。これは、特に物理学や化学における微細な測定において、極めて小さな量を表すために使用されます。

Googleの名前は直接「Googol」から取られたわけではありませんが、そのインスピレーションはこの言葉から得られています。「Googol」は数学用語で、$10^{100}$、つまり1の後に0が100個続く数を表し、非常に大きな数を表すために使用されます。これは、コンピュータサイエンスにおいて扱われる巨大な数や情報量を表すためによく使われます。

命名の哲学において、GoogleとÅngströは、一見すると対極にあるように見える技術概念ですが、興味深い対称性を持っています。前者は数学的概念「Googol」から創造的に改変されたものであり、後者は物理単位「Ångström」からイメージを再構築したものです。この2つの芸術的に変奏された名称は、技術文明の二重螺旋のように見えます。Googleという名前は、星の海のような数字の宇宙を制御する野心を担い、Ångströという名称は、原子レベルの技術的ビジョンを象徴しています。これら2つの創造的に変形された専門用語がシリコンバレーで出会ったとき、それはまさに完璧な認知座標を構成します——情報処理のスケールの限界を示し、技術文明がマクロとミクロの両方に向かって進む壮大な旅を示しています。

暗号学入門:Googleインフラストラクチャードメインの規則2

さて、話をGoogleのインフラストラクチャーに戻しましょう。まず、完全な接続ドメインを見てみます:

1
2
3
rr4---sn-j5o7dn7s.xn--ngstr-lra8j.com
rr1---sn-j5o76n7z.xn--ngstr-lra8j.com
rr5---sn-i3b7knzs.xn--ngstr-lra8j.com

これらの一見ランダムな文字列は、実は簡単な暗号学的な変換を経た結果です。その核心部分を分解してみましょう。

都市名の変換規則

rr1---sn-j5o76n7zを例に取ると、重要な情報はsn-の後の8文字:r1---sn-[123][45][6][78]です。最初の3文字、この場合はj5oは都市名で、その都市の主要空港のIATAコードを一定の暗号学的変換を経て得られます。

まず、5 * 7の数字とアルファベットの表を作成します:

1
2
3
4
5
6
7
行0: 1 0 2 3 4
行1: 5 6 7 8 9
行2: a b c d e
行3: f g h i j
行4: k l m n o
行5: p q r s t
行6: u v w x y

この表を反時計回りに回転させ、新しい表の左下から始めて、元の表のデータを「下から上、左から右」の順に書き写します。

回転が完了すると、次の表が得られます:

1
2
3
4
5
6
7
8
9
| 6 d k r y |
| --------- |
| 5 c j q x |
| 4 b i p w |
| 3 a h o v |
| 2 9 g n u |
| 0 8 f m t |
| --------- |
| 1 7 e l s | 

表の中央に線で囲まれた5*5の部分が最終的な暗号表で、25文字あり、「左から右、上から下」の順にaからyまでの文字を表します。例えば、上海虹橋国際空港のIATAコードはshaで、この表を使って暗号化されたテキストを得ることができます:

  • sはアルファベットの19番目の文字で、「左から右、上から下」の順に暗号表で19番目の文字を数えると、nになります。
  • hはアルファベットの8番目の文字で、暗号表で8番目の文字を数えると、iになります。
  • aはアルファベットの1番目の文字で、暗号表で1番目の文字を数えると、5になります。

暗号化されたテキストはni5です。

逆に、最初の都市名j5oを暗号表から逆算すると:

  • jは「左から右、上から下」の順に3番目の文字で、cになります。
  • 5は「左から右、上から下」の順に1番目の文字で、aになります。
  • oは「左から右、上から下」の順に14番目の文字で、nになります。

翻訳された平文はcanで、これは広州白雲国際空港のIATAコードです。つまり、私たちが接続しているサーバーは広州にあります。

もしGoogleがチューリッヒにサーバーを持っている場合、チューリッヒ空港のIATAコードはzrhで、zという文字がありますが、私たちの暗号表にはaからyまでの文字しかありません。心配しないでください、Googleもこの問題を考慮しています。zは暗号表の1に対応します。

このルールをコードで表現すると次のようになります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
table = "5cjqx4bipw3ahov29gnu08fmt1"
def iata2cipher(iata):
    global table
    iata = iata.upper()
    cipher = ""
    for element in iata:
        index = ord(element) - 65
        cipher += table[index]
    return cipher

def cipher2iata(cipher):
    global table
    cipher = cipher.lower()
    iata = ""
    for element in cipher:
        index = table.find(element)
        iata += chr(65 + index)
    return iata

# print(iata2cipher(input("IATA:")))
# print(cipher2iata(input("Cipher:")))

サーバーグループ番号

[45]と[78]番目の文字、例えば767zは、サーバーグループ(アクセスポイント)番号を表し、以下の表の最初の列(すでに区切り線で区切られています)に含まれる文字で構成されます。7elsz6dkryはそれぞれ0123456789を表します。したがって、76の平文は057zの平文は04です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | 1 2 3 4 5 6
7 | 8 9 a b c d
e | f g h i j k
l | m n o p q r
s | t u v w x y
z | 0 1 2 3 4 5
6 | 7 8 9 a b c
d | e f g h i j
k | l m n o p q
r | s t u v w x
y | z

Pythonで表現すると次のようになります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
codeTable = "7elsz6dkry"
def cipher2code(cipher):
    global codeTable
    cipher = cipher.lower()
    codeString = ""
    for element in cipher:
        index = codeTable.find(element)
        codeString += chr(index + 48)
    return codeString

# print(cipher2code(input("Cipher:")))

同様に、数字を暗号化する方法もここでは詳しく説明しません。

サポートプロトコル

[6]番目の文字はネットワークプロトコル情報を表します:

  • n:IPv6(アドレス範囲 0x000-0x3FF)
  • u:IPv6(アドレス範囲 0x400-0x7FF)
  • m:IPv4のみサポート

例えば:

  • a5mekn7r、IPv6プレフィックス:2607:f8b0:4007:a::/64、IPv4プレフィックス:74.125.103.0/24
  • a5m7zu7r、IPv6プレフィックス:2607:f8b0:4007:407::/64、IPv4プレフィックス:74.125.215.0/24
  • a5mekm76、IPv4のみサポート、プレフィックス:208.117.242.0/24

適切なトラフィック分流の実装

この解析情報を基に、より正確な Google ドメインの分流を設定できる。 現在、中国の Google CDN は主に北京(2x3)、上海(ni5)、広州(j5o)に分布している。これに基づいて、以下の正規表現ルールを作成できる。

1
2
rules:
  - DOMAIN-REGEX,^r+[0-9]+(---|\.)sn-(2x3|ni5|j5o)\w{5}\.xn--ngstr-lra8j\.com$,DIRECT

このルールにより、rr1---sn-j5o76n7z.xn--ngstr-lra8j.com のような Google Play の中国 CDN ドメインを「直通(DIRECT)」で処理し、それ以外の Google サービスは従来通りプロキシ経由でアクセスする。

さらに、GeoSite データベース(v2fly/domain-list-community)は、Google Play の中国 CDN に対し最適化済みのルールを提供している3

1
2
3
rules:
  - GEOSITE,GOOGLE-PLAY@CN,全球直连
  - GEOSITE,GOOGLE,代理选择
Licensed under CC BY-NC-SA 4.0
Hugo で構築されています。
テーマ StackJimmy によって設計されています。