自分のPCが今この瞬間、世界のどこと通信しているのか——普段は誰も見ていない。TapMap(★1,390・MIT)は、その通信先を世界地図の上にリアルタイムで描くだけのPython製OSSだ。本記事では v1.10.1 を macOS 上でソースから動かし、画面に何が出るかだけでなく、TapMap自身がどこへ何回通信するのかを条件を変えて3回実測した結果までまとめる。
TAPMAP_LON/TAPMAP_LAT で東京に固定した(画面下の MYLOC: ENV)30秒でわかるTapMap
・やること:OSのソケット情報を読み、接続先IPをローカルのGeoIP DBで地理情報に変換して世界地図に描く
・やらないこと:遮断(ファイアウォールではない)・外部ホストへの探索(スキャナではない)
・自身の外部通信:GeoIP DB未導入なら0件。DB導入後の既定設定で1件だけ(api.ipify.org へ公開IP照会)。座標を手動指定すれば0件に戻る(すべて本記事の実測)
・待ち受け:127.0.0.1:8050 の1本のみ。LANからは到達しない
・導入コスト:GeoIP DB(DB-IP Lite)で133.4 MB・3.3秒。アカウント登録不要
ワークフロー自動化やセルフホスト運用の全体像は「AI自動化ツール|ノーコードからコードまで2026年版の比較と選び方」で整理している。本記事はその中でも「自分の環境で何が起きているかを見る」側のツールを扱う。
TapMapとは——通信先を世界地図に描くだけのツール
TapMapは2026年2月に公開されたPython製のネットワーク可視化ツールだ。作者はノルウェーの Ola Lie 氏で、How-To Geek・MakeUseOf といった海外メディアにも取り上げられている。日本語の解説記事は、本記事の執筆時点で検索上位に見当たらない。
動作の流れは README が明示している4段構成で、驚くほど単純だ。
macOS: lsof
Win/Linux: psutil"] --> B["接続先IPの抽出"] B --> C["ローカルGeoIP DBで
座標・国・ASNに変換"] C --> D["Dash + Plotly で
世界地図に描画"]
重要なのはパケットを見ていないという点だ。TapMapが読むのはOSがすでに持っている「今つながっているソケットの一覧」であって、通信の中身でもなければ、キャプチャでもない。だから管理者権限のパケットキャプチャ設定も要らないし、通信内容がTapMapに渡ることもない。
画面に出る情報
起動すると地図の下に1行のステータスラインが出る。筆者環境での実際の表示はこうなっていた。
・LIVE: TCP 102 EST 89 LST 11 UDP R 6 B 6 — 今この瞬間のソケット内訳(TCP総数102、確立済み89、待ち受け11)
・CACHE: SOCK 93 SERV 51 MAP 26 UNM 0 LOC 25 — 蓄積されたソケット・サービス・地図上の点・未マップ・地点の数
・MYLOC: ENV — 自分の位置の決め方(AUTO=公開IPから推定/ENV=環境変数で手動指定/OFF=表示しない)
右側のパネルには「今日はじめて見たもの」が並ぶ。NEW APPS(新しく通信したアプリ)、NEW PROVIDERS(新しく出てきた接続先の組織)、NEW COUNTRIES(新しい国)、NEW PORTS(新しいポート)だ。この「初めて見たものだけを出す」設計が、常時大量に流れる通信の中から異変を拾う実用性を作っている。
実測:TapMap自身は外部と通信するのか
READMEは冒頭で「Runs locally. No telemetry.」と書いている。一方で PRIVACY.md には「既定では公開IP取得のために外部サービスへ問い合わせる」とも書いてある。この2つは矛盾しないが、結局どこへ何回つなぐのかは文章からは分からない。測った。
測り方
lsof を繰り返し叩くポーリングでは取りこぼす。TapMapの公開IP照会はタイムアウト2秒の短命コネクションで、実際に0.2〜0.33秒間隔のポーリングを合計3回・約145秒ぶん回しても1度も捕まえられなかった。そこで呼び出しそのものを記録する方式に変えた。socket.socket.connect と socket.getaddrinfo をラップしてから TapMap を起動し、ループバック宛以外の呼び出しを全件ログに落とす。取りこぼしが構造的に起きない。
この状態でブラウザからUIを開き(Dashのコールバックを実際に走らせないと位置解決処理が動かない)、各条件を約55〜58秒間そのまま動かした。
結果
| # | 条件 | 外向きの接続 | 外部への名前解決 |
|---|---|---|---|
| A | GeoIPデータベース未導入(初回起動そのまま) | 0件 | 0件 |
| B | DB-IP Lite導入済み・既定(MYLOC: AUTO) |
1件 | 1件 |
| C | DB-IP Lite導入済み・TAPMAP_LON/TAPMAP_LAT で座標指定 |
0件 | 0件 |
条件Bで観測された唯一の外向き接続は、起動から0.62秒後の api.ipify.org:443 に対する名前解決と、続く 104.26.13.205:443(whois で OrgName: Cloudflare, Inc. / NetName: CLOUDFLARENET)への接続1回だけだった。以後58秒間、追加の外向き通信は観測されなかった。ソースを追うと位置解決の関数はアプリのコンストラクタから1回だけ呼ばれており(ポーリングのたびに呼ばれる作りではない)、観測結果と整合する。
ソースを読むと、公開IPの取得先は4つ用意されている(api.ipify.org → checkip.amazonaws.com → ifconfig.me/ip → icanhazip.com)が、これはフォールバックの連鎖であって並列照会ではない。最初の1つが成功する限り、残る3つには接続しない。実測でもそうなった。
条件Aが0件になる理由もソースで裏が取れる。位置を自動推定する処理は「GeoIPの都市データベースが有効か」を先に確認し、無効なら公開IP照会に到達せず即座に打ち切られる。GeoIPデータベースを入れるまで、TapMapはネットワークに一切触れない。
この順序は使う側にとって実用的な意味を持つ。まず素の状態で起動して画面を見るぶんには、TapMapは外へ何も出さない。GeoIPデータベースが無いと地図に点は乗らないが、ステータスラインのソケット内訳とプロセス名の一覧は表示される。「まず挙動を確かめてから地図機能を有効にする」という段階的な導入ができる作りになっている。
なお「外部への名前解決0件」は、TapMapのプロセスが getaddrinfo を呼んでいないことを指す。OSのDNSキャッシュや他プロセスの通信まで止まるわけではないので、そこは混同しないでほしい。
待ち受けはループバックのみ
同時に待ち受け側も確認した。環境変数を何も付けずに起動して lsof -i -nP -a -p <pid> を叩くと、LISTEN ソケットは 127.0.0.1:8050 の1本だけだった(config.py の SERVER_PORT の既定値どおり。上のegress実験では他プロセスとの衝突を避けるため TAPMAP_PORT=8099 に変えており、そちらでも同じく1本のみ)。バインド先は環境変数 TAPMAP_HOST を指定しない限りループバック固定で、LANからは到達しない。Docker で動かす場合だけは --network host が前提になるので条件が変わる。
インストールして動かす
配布物としては Windows インストーラ / macOS の .dmg / Linux の .deb が Releases に置かれている。ここでは検証と同じ「ソースから動かす」手順を示す。なお pyproject.toml に requires-python の宣言は無く、公式が必要Pythonバージョンを明示していない([tool.ruff] target-version = "py310" はlintの構文ターゲットであって実行要件ではない)。本記事の検証は Python 3.14.4 で行い、そこでは問題なく動いたとだけ書いておく。
# 1) 取得して隔離環境に入れる
git clone --depth 1 https://github.com/olalie/tapmap.git
cd tapmap
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -e .
.venv/bin/tapmap --version
--version が版番号を返せば導入は完了だ。CLIのオプションは -h と -v の2つしかなく、挙動の変更はすべて環境変数で行う。
# 2) 起動する(ブラウザ自動起動を止め、位置を手動指定して公開IP照会もしない構成)
TAPMAP_LAUNCH_BROWSER=0 \
TAPMAP_LON=139.6917 TAPMAP_LAT=35.6895 \
.venv/bin/tapmap
# 実行結果: Dash is running on http://127.0.0.1:8050/
起動したら http://127.0.0.1:8050/ をブラウザで開く。GeoIPデータベースが無ければ管理画面が自動で開くので、そこで DB-IP か MaxMind を選んで導入する。
TapMapが数えている接続数が妥当かは、OS側のコマンドで突き合わせられる。
# 3) 独立に確立済みTCPを数えて突き合わせる(ループバックを除く)
lsof -nP -i TCP -s TCP:ESTABLISHED | awk 'NR>1 && $9 !~ /127\.0\.0\.1|\[::1\]/' | wc -l
# 筆者環境: 83 (同時刻のTapMapのステータスラインは EST 89)
数秒ずれた時点の値なので完全一致はしないが、桁も傾向も合っている。ただしmacOSではこれは完全な独立検証ではない——TapMap自身が macOS では lsof を情報源にしているため、同じ井戸を2回汲んでいることになる。ここで検証できるのは「TapMapの集計・パースが妥当か」までで、「lsof が正しいか」ではない。Windows / Linux では TapMap 側が psutil を使うので、ss -tanp などとの突き合わせは独立した検証になる。
AIエージェントとMCPサーバーの通信は誰の名前で見えるか
この記事を書いている端末では Claude Code が動いている。TapMapの significant_connections.json(「初めて見た」条件に合致した接続の記録)から、実際に検出された組み合わせを引き出したのが下の表だ。
| プロセス名 | 接続先の組織(ASN) | 国 | ポート |
|---|---|---|---|
claude(Claude Code) |
Anthropic, PBC(AS399358) | 米国 | 443 |
Claude(デスクトップアプリ) |
Anthropic, PBC(AS399358) | 米国 | 443 |
Claude Helper |
Fastly, Inc.(AS54113) | カナダ | 443 |
bun |
Telegram Messenger Inc(AS62041) | オランダ | 443 |
Cursor Helper (Plugin) |
Cloudflare, Inc.(AS13335) | カナダ | 443 |
Cursor Helper |
Amazon.com, Inc.(AS14618) | 米国 | 443 |
Google Chrome Helper |
Google LLC(AS15169) | オーストラリア | 5228 |
面白いのは bun の行だ。この端末では Telegram 連携のMCPサーバーが bun ランタイム上で動いており、その通信が親のClaude Codeではなく bun というランタイム名で計上されている。MCPサーバーはホスト(エージェント本体)とは別プロセスとして起動するため、通信の主体もホストではなくサーバー側のプロセスになる。「エージェントの通信を見る」つもりでエージェント本体のプロセス名だけを追うと、この行は視界から丸ごと落ちる。
TapMapは接続に紐づくアプリの署名情報も拾おうとする(v1.10系で入った cross-platform application information)。実測では Claude Helper の1件が app_signature_state: DeveloperSigned / app_verification_status: verified / app_creator: Anthropic PBC と解決された一方、他の多くのイベントでは同じ項目が空だった。全接続について署名が判定できるわけではないので、「署名情報が無い=怪しい」とは読めない。
もう1つ目を引くのが Google Chrome Helper と Sidekick Helper の ポート5228 だ。これはGoogleのプッシュ通知(FCM/GCM)が使う定番ポートで、443ではないぶん一覧の中で目立つ。「見慣れないポートが出た」ときに、それが既知のサービスなのか調べる起点として NEW PORTS 欄は機能する。
ここで得られるのは「どのプロセスがどの組織へつないだか」までで、何を送ったかは分からない。TapMapは通信の中身を見ないので当然だが、エージェント常駐環境の監査という文脈では、この粒度で足りるかを先に決めておいたほうがいい。「Anthropicへ443で出ている」ことの確認には十分でも、「送信内容にシークレットが混ざっていないか」の確認には別の手段が要る。
見えた通信を「見る」から「絞る」へ進めたいなら、エージェント側を隔離する設計が要る。使い捨てVMと送信フィルタでコーディングエージェントを囲う手法は「clawk解説|コーディングエージェントに使い捨てLinux VMを渡すサンドボックスと既定許可137件」でまとめている。
GeoIPデータベースはどちらを選ぶか
TapMapは地図を描くためにGeoIPデータベースを必要とし、DB-IP と MaxMind の2社に対応している。導入は TapMap のメニューから行い、実測値は以下の通りだった。
| DB-IP Lite | MaxMind GeoLite2 | |
|---|---|---|
| アカウント登録 | 不要 | 必要(Account ID + License Key) |
| 資格情報の保存先 | — | OSのキーチェーン(keyring) |
| 実測の導入時間 | 3.3秒 | 未検証(資格情報が必要なため) |
| 実測のディスク使用量 | 133.4 MB(City 124.2 + ASN 9.2) | 未検証 |
| 取得したDB版 | 2026-08(city/asn とも 2026-08-01) | — |
| 更新 | ユーザーが明示的に要求したときだけ | 同左 |
「とりあえず動かす」なら DB-IP Lite 一択だ。3.3秒で終わり、外部アカウントも作らずに済む。ディスクを133 MB使う点だけは事前に見ておきたい。
精度の観点ではMaxMindのGeoLite2のほうが一般に評価が高いが、TapMapの用途——「どの国・どの組織につないでいるか」を大づかみに見る——では、DB-IP Lite の粒度で困る場面はほとんど無かった。実測でも Anthropic・Cloudflare・Fastly・Google・Amazon・Telegram といった主要な接続先のASN組織名はすべて解決できている。市区町村レベルの精度が要る用途ではないので、まずは登録不要の側から始めて足りなければ乗り換える、で十分だろう。
PRIVACY.md が「GeoIPデータベースのダウンロード・更新はユーザーが明示的に要求したときだけ」と書いている点も、実測の条件Aと整合している。裏で勝手に更新をチェックする挙動は観測されなかった。
Little Snitch・OpenSnitch との違い
「自分のPCの通信先を見る」で真っ先に挙がるのは Little Snitch(macOS・商用)や OpenSnitch(Linux・GPL)だろう。だが役割が違う。
| TapMap | Little Snitch / OpenSnitch | |
|---|---|---|
| 種別 | 観測(awareness tool) | 送信制御ファイアウォール |
| 通信の遮断 | できない | できる(既定は許可/拒否をその場で選択) |
| 見せ方 | 世界地図+日次の変化サマリ | 接続ごとのダイアログとルール一覧 |
| 導入時の負荷 | Pythonアプリを起動するだけ | カーネル拡張/ネットワーク拡張の権限付与 |
| ライセンス | MIT | Little Snitch=商用 / OpenSnitch=GPL-3.0 |
| プラットフォーム | Windows / macOS / Linux | Little Snitch=macOSのみ / OpenSnitch=Linuxのみ |
TapMapのREADMEは自ら「It is an awareness tool, not a firewall or a full security suite.」と書いている。遮断したいなら別のソフトが要る、というのが正しい理解だ。逆に「まず何が起きているかを把握したい」「3OSで同じ見え方をしてほしい」という用途では、ダイアログ疲れを起こさないぶんTapMapのほうが続く。
同じ「自分の環境を可視化する」系では、ネットワーク構成図を自動生成するScanopy完全解説|ネットワーク図を自動作成・自動更新するセルフホストOSS(エージェントレス)や、SQLトラフィックを覗くsql-tapとは|アプリを無改修でSQLトラフィックをリアルタイムに覗くGo製プロキシ型TUI/Web監視ツールが近い立ち位置にある。TapMapは「自分のマシンから外へ出ていく通信」を担当する。
使う前に知っておくこと
実際に動かして分かった制約と注意点を並べる。
・他人のネットワークをスキャンする道具ではないし、できない。 TapMapはOSが持つ自分のマシンのソケット一覧を読むだけのパッシブな観測ツールで、外部ホストへ探索パケットを送る機能がない。逆に言えば、nmap系のツールを使う場合は「自分が管理するネットワークだけ」という原則を必ず守る必要があるが、TapMapにはその判断が入り込む余地自体がない
・GeoIPの位置は「だいたい」でしかない。 IPから引く座標はISPやCDNの登録情報に基づく推定で、実際のサーバー所在地とは限らない。Cloudflare や Fastly のようなCDN経由の接続は、CDNのエッジやレジストリ登録地に落ちる。上の実測表で「カナダ」「オーストラリア」が並んでいるのはそういう理由で、通信相手の企業がその国にあるという意味ではない
・リポジトリのデモGIFは古い。 README冒頭の docs/images/demo.gif の最終更新は2026-04-24で、最新リリース v1.10.1(2026-08-24)より4か月前だ。その間にアプリ情報の取得(2026-08-18)などが入っているため、GIFの見た目と現物には差がある。本記事の画像はすべて v1.10.1 を実際に動かして撮ったもの
・プロセス名は必ずしもアプリ名ではない。 上で見た bun の例のように、ランタイム経由で動くツールはランタイム名で出る。何のプロセスか分からない行が出たら、lsof -nP -p <pid> で実行ファイルのパスを確認するのが早い
・記録はローカルに残る。 30日ぶんの国・ASN・ポート・プロセス名の履歴が insights.json に、特筆すべき接続が significant_connections.json に保存される。PRIVACY.md はこれらが外部送信されないと明記しているが、端末を共有する環境では中身が読める点は意識しておきたい
まとめ
TapMapは「遮断しない・スキャンしない・パケットを見ない」と引き算を重ねた結果、自分のマシンの通信先を眺めるだけに振り切ったツールになっている。だからこそ導入が軽く、権限も要らず、3OSで同じ体験になる。
そして今回いちばん確かめたかった「このツール自体は信用できるのか」については、文章を読むのではなく数えることで答えが出た。GeoIPデータベースを入れるまでは外向き0件。入れたあとの既定でも起動時に公開IP照会が1回だけで、それも TAPMAP_LON/TAPMAP_LAT を指定すれば消える。待ち受けはループバック1本。
観測窓は各58秒なので「1時間後に何か起きない」ことまでは示せない。ただしソースを検索した限り、バージョン更新チェックのようなネットワーク呼び出しはコードパスとして存在しなかった——ソース中に現れる github.com/olalie/tapmap は、About画面のリンク・公開IP照会時のUser-Agent文字列・Linux用のmanページとdesktopファイルに出てくるだけで、どれも通信を起こさない。「Runs locally. No telemetry.」という主張は、v1.10.1 の実測とソースの両面で裏が取れている。
参照ソース
・olalie/tapmap — 公式リポジトリ / README(v1.10.1)
・TapMap PRIVACY.md — 公式のプライバシー方針
・TapMap Documentation — 環境変数・GeoIPデータベース管理
・DB-IP Lite databases — GeoIPデータベース提供元