😺

来た。ネットワークごと WARP 、無料で SWG & WAN。

2024/02/25に公開

はじめに

これまで何回か WARP クライアントについて書いたことがあります。
...3年前
https://note.com/tkn_cloudflare/n/n541543e67611
..2年前
https://qiita.com/KeioCF/items/5699bb95104d10d18d19

そして、2023 年末、
個人的にずっとひっそり待ち望んでいた機能が来てました。

WARP connector

こいつで下記が可能になります。

  • WARP クライアントが入らないローカルネットワーク端末のインターネット接続の制御
  • ローカルネットワーク間のプライベート通信(双方向!)

無料で。

執筆時点でベータなので、試してみて、イシューや要望がいろいろ出てくると思います。
ご興味ある方は一緒に試してフィードバックできればと。

WARP 接続方法の変遷

本題に入る前に WARP の接続方式の進化について主なトピック書いてみます。

  1. WARP で Cloudflare Gateway の自分のオーガニゼーションに入り、インターネット接続をポリシーで制御するというのが基本
  2. WARP to Tunnel で cloudflared の先にいるプライベートネットワークに接続(WARP から cloudflared への片方向)
  3. WARP-to-WARP で WARP 端末間(ピアツーピア)の直接通信
  4. WARP connector でローカルネットワークのゲートウェイ、および、ネットワーク同士(サイトツーサイト)の通信


    こんな利用シーンも書いてあります。

cloudflared との違い

どちらも Cloudflare にトンネルを掘りますが、執筆時点では下記の違いがあるようです。
今回は Internet への出口およびローカルネットワークの双方向通信をしたいので、 WARP connector の出番です。

ご承知のとおり、cloudflared は L7(HTTP)Proxy もします。

実践

Dev Doc に従えば OK でした。

以下は補足メモになります。
執筆時点でベータなこともあり、Dev Doc の内容や条件は適時更新されることが想定されます。
下記は参考までにとどめていただければと思います。

Cloudflare ダッシュボード

  • Service Tokens の作成
  • Device enrollment rules の追加
    • あらかじめ Any Access Service Token を設定しておくか、作成した Sevice Token を都度追加
  • WARP to WARP の有効化
  • Override local interface IP の有効化
  • Split Tunnels の設定
    • WARP が Gateway に転送するネットワークの仕分け(下記のモードどちらかを選ぶ)
    • exclude モードの場合
      • ローカルインターフェースに転送するネットワークを列記
      • リストから以下を抜く
        • 100.96.0.0/12(WARP インターフェースに付与される IPレンジ)
          • デフォルトで登録されている 100.64.0.0/10 を消して 100.64.0.0/11 と 100.112.0.0/12 を追加
        • Linux に SSH リモート接続中の端末 IP
          • リモートから WARP connector の Linux へ SSH して設定中の場合
          • あとで WARP を接続したときに SSH が切れてしまうのを回避
    • include モードの場合
      • WARP トンネルに転送するネットワークを列記
      • リストに以下を入れる
        • 100.96.0.0/12
  • Tunnel の作成
    • WARP (Beta) を選び、設定する
    • Linux に WARP をインストールするスクリプトが作成されるのでコピー
    • WARP に関連つけるローカルネットワークを設定(Route)

Linux ホスト

  • WARP connector のインストール
    • コピーした Tunnel インストールスクリプトを実行
  • Gateway のオーガニゼーションとの関連付け
    • /var/lib/cloudflare-warp/mdm.xml の作成
      • コピーした xml ファイルの中身を Service Token の値で置換
  • OS の設定
    • IP forwarding 有効化 net.ipv4.ip_forward=1
    • TCP MSS Clamping 有効化 iptables -t mangle
    • 設定すると下記のような処理をする
WARP connector でのキャプチャ
# リモートからローカルへの SYN パケットが CloudflareWARP インターフェースに到着
192.168.88.170 → 172.16.4.253 TCP 76 55276 → 1234 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 ..
# 上記を MSS の書き換え(1460 → 1240)し、ローカルインターフェースへ転送
192.168.88.170 → 172.16.4.253 TCP 76 55276 → 1234 [SYN] Seq=0 Win=65535 Len=0 MSS=1240 ..
  • WARP 操作コマンドの例(トラブル時などに)
    • sudo systemctl restart warp-svc.service サービス再起動
    • warp-cli account 所属オーガニゼーション確認
    • sudo warp-cli delete オーガニゼーションから抜ける
    • warp-cli status 接続状態の確認
    • warp-cli settings ダッシュボードから降ってきた設定
    • warp-cli disconnect WARP を切る
    • warp-cli connect WARP に接続
    • warp-cli -h コマンドヘルプ

Cloudflare ダッシュボード

  • Split Tunnels にローカルネットワークの追加
    • exclude モードの場合
      • リストから以下を抜く
        • 各ローカルネットワーク
    • include モードの場合
      • リストに以下を入れる
        • 各ローカルネットワーク

通信確認

Split Tunnels (Include mode)
# Include mode なので、リストに下記を含む
## ①WARP に振られる CGNAT ②各ローカルネットワーク ③接続したい Internet アドレス

$ warp-cli settings
:
Merged configuration:
:
(network policy)	Include mode, with hosts/ips:
  172.16.0.0/16 (my private net)
  104.26.13.205/32 (api.ipify.org)
  100.64.0.0/10 (cgnat private public)
  192.168.88.0/24 (my private net )
:
WEST WARP connector
# インターフェース
## 物理と CloudflareWARP の IP
$ ip addr show wlp2s0b1
2: wlp2s0b1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.88.250/24 brd 192.168.88.255 scope global dynamic noprefixroute wlp2s0b1
:

$ ip addr show  CloudflareWARP
3: CloudflareWARP: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1280 qdisc mq state UNKNOWN group default qlen 500
    link/none
    inet 100.96.0.2/32 scope global CloudflareWARP
       valid_lft forever preferred_lft forever
    :

# ルーティングテーブル
## WARP トンネルへの経路がルーティングテーブルに書かれるわけではなく、
## WARP の Split Tunnels で仕分けしたあとに、ルーティングテーブルが参照される
$ ip route show table main
default via 192.168.88.254 dev wlp2s0b1 proto dhcp metric 600
169.254.0.0/16 dev wlp2s0b1 scope link metric 1000
192.168.88.0/24 dev wlp2s0b1 proto kernel scope link src 192.168.88.250 metric 600

$ ip route show table local
local 100.96.0.2 dev CloudflareWARP proto kernel scope host src 100.96.0.2
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 192.168.88.250 dev wlp2s0b1 proto kernel scope host src 192.168.88.250
broadcast 192.168.88.255 dev wlp2s0b1 proto kernel scope link src 192.168.88.250

# 接続
## インターネットへの接続(送信元 IP が Cloudflare Gateway)
~$ curl api.ipify.org --resolve api.ipify.org:80:104.26.13.205
104.28.196.2

## 対向ネットワークの WARP connector
$ ping -c 1 100.96.0.3
PING 100.96.0.3 (100.96.0.3) 56(84) bytes of data.
64 bytes from 100.96.0.3: icmp_seq=1 ttl=62 time=49.7 ms

$ ping -c 1 172.16.4.254
いかなかった(デバッグしていない)

##  対向ネットワークのローカル端末
$ ping -c 1 172.16.4.253
PING 172.16.4.253 (172.16.4.253) 56(84) bytes of data.
64 bytes from 172.16.4.253: icmp_seq=1 ttl=61 time=52.1 ms
WEST ローカル端末 vm1
# ルーティングテーブル
## 対向ネットワークとインターネット宛の経路を WARP connector に向かせる
~ $ route -n get 172.16.4.253
   route to: 172.16.4.253
destination: 172.16.4.0
       mask: 255.255.255.0
    gateway: 192.168.88.250
  interface: en0
  :
~ $ route -n get 104.26.13.205
   route to: 104.26.13.205
destination: 104.26.13.205
       mask: 255.255.255.255
    gateway: 192.168.88.250
  interface: en0
  :
~ $ route  -n get 100.96.0.3
   route to: 100.96.0.3
destination: 100.96.0.0
       mask: 255.240.0.0
    gateway: 192.168.88.250
  interface: en0
  :

# 接続
## インターネットへの接続(送信元 IP が Cloudflare Gateway)
~ $ curl api.ipify.org --resolve api.ipify.org:80:104.26.13.205
104.28.196.2

## 対向ネットワークの WARP connector
~ $ ping -c 1 100.96.0.3
PING 100.96.0.3 (100.96.0.3): 56 data bytes
64 bytes from 100.96.0.3: icmp_seq=0 ttl=61 time=61.240 ms

##  対向ネットワークのローカル端末
~ $ ping -c 1 172.16.4.253
PING 172.16.4.253 (172.16.4.253): 56 data bytes
64 bytes from 172.16.4.253: icmp_seq=0 ttl=60 time=66.027 ms

観測とコントロールの例

一通り通信ができてそうです。

たとえば、

  • インターネットの HTTP/HTTPS 通信にはカテゴリーフィルターが効いている 👍
  • プライベート通信では下記のような EAST ←→ WEST の通信を観測 👍
EAST(受信側)WARP connector の CloudflareWARP インターフェース
192.168.88.170 → 172.16.4.253 TCP 60 54519 → 1234 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=3431938176 TSecr=0 WS=8192
172.16.4.253 → 192.168.88.170 TCP 60 1234 → 54519 [SYN, ACK] Seq=0 Ack=1 Win=62636 Len=0 MSS=1240 SACK_PERM=1 TSval=916610536 TSecr=3431938176 WS=128
192.168.88.170 → 172.16.4.253 TCP 52 54519 → 1234 [ACK] Seq=1 Ack=1 Win=65536 Len=0 TSval=3431938179 TSecr=916610536
192.168.88.170 → 172.16.4.253 TCP 54 54519 → 1234 [PSH, ACK] Seq=1 Ack=1 Win=65536 Len=2 TSval=3431938801 TSecr=916610536
172.16.4.253 → 192.168.88.170 TCP 52 1234 → 54519 [ACK] Seq=1 Ack=3 Win=62720 Len=0 TSval=916611161 TSecr=3431938801
172.16.4.253 → 192.168.88.170 TCP 52 1234 → 54519 [FIN, ACK] Seq=1 Ack=3 Win=62720 Len=0 TSval=916635934 TSecr=3431938801
192.168.88.170 → 172.16.4.253 TCP 52 54519 → 1234 [FIN, ACK] Seq=3 Ack=2 Win=65536 Len=0 TSval=3431963577 TSecr=916635934

惜しぃ

後者を Gateway の Network のルールで Block しようとしました。

が、効きませんでした。

ログを見ると Destination IP はローカルネットワークですが、Source IP が WEST の ISP の IP ででています。

ルールの Source IP を ISP に書き換えます。

Block されました。

んー。
パケットキャプチャの通りに、ローカルネットワークのアドレスで指定したいところです。
(GA のときに解消されているといいんですけど)

欲しいものが手に入ると次が欲しくなる、、、欲は尽きません・・・ いかんですね。。

その他

ローカルネットワークからの通信は Network か HTTP のポリシーで制御できます。
DNS ポリシーの適用(WARP connector が DNS クエリーを Proxy する)は今のところ未対応のようです。これも欲しい…

A device profile configured with one of the following WARP modes:
Gateway with WARP
Secure Web Gateway without DNS Filtering

WARP connector 自身の DNS クエリーはポリシーに当たりますが、ローカル端末は自分に設定してある DNS 設定を参照します。

まとめ

とにかく、下記ができるようになって、使い勝手が増えました。

  • WARP クライアントが入らないローカルネットワーク端末のインターネット接続の制御
  • 遠隔のローカルネットワーク間のプライベート通信(双方向)

有償版ではいろいろなアーキテクチャが組めますが、まずはこれだけでも個人使いには便利になります。

また、 MASQUE など新しい挑戦も続いて WARP の今後に期待です。

Discussion