ネットワークオーバーレイ

アウトバウンドHTTPコール用のSOCKS5オーバーレイを構成し、継承、インバウンドリスナー、アプリケーション既定値、権限を確認します。

分類: 実行可能なSOCKS5チュートリアルと、部分的なTailscaleレシピです。 外部Torリスナーを利用できれば、direct/Torプローブは完全に実行できます。Tailscaleセクションは Wippy側の配線を説明しますが、アカウントのプロビジョニングはTailscale側に委ねます。 I2Pの設定は、後述のネットワークシステムリファレンスを参照してください。

概要

Wippyはオーバーレイネットワークをレジストリエントリとして表現します。コードは呼び出し用のオーバーレイを選択でき、 子孫が上書きするまでその選択がネストした呼び出しへ伝播します。

Wippyは3種類のオーバーレイエントリをサポートします:

  • network.socks5 — 汎用SOCKS5プロキシ(TorのSOCKS5リスナーにも使用可)
  • network.tailscale — tsnetオーバーレイノード
  • network.i2p — I2P SAM v3ブリッジ

前提条件

  • Wippyランタイムv0.3.32a。

  • curlとapi.ipify.orgへのアウトバウンドHTTPSアクセス。

  • 127.0.0.1:9050でSOCKS5を公開するTorデーモン。Tor Projectのダウンロードページから 対応パッケージをインストールして起動し、Wippyを実行する前にリスナーを確認します:

    curl --socks5-hostname 127.0.0.1:9050 https://api.ipify.org?format=json
    

    成功するとIPアドレスを含むJSONが返ります。Tor Browserは一般にポート9150を使用します。 意図してそのリスナーを使う場合は、レジストリエントリと検証コマンドを同時に変更してください。

  • 空の作業ディレクトリ:

    mkdir netdemo
    cd netdemo
    mkdir src
    

プロジェクト構造

netdemo/
├── wippy.lock
└── src/
    ├── _index.yaml
    └── probe.lua

ステップ1: オーバーレイを定義する

src/_index.yamlを作成:

version: "1.0"
namespace: app

entries:
  - name: net_policy
    kind: security.policy
    policy:
      actions:
        - http_client.request
        - network.select
      resources: "*"
      effect: allow

  - name: processes
    kind: process.host
    lifecycle:
      auto_start: true

  - name: terminal
    kind: terminal.host
    lifecycle:
      auto_start: true

  # SOCKS5 proxy entry (Tor exposes one at 127.0.0.1:9050 by default)
  - name: tor
    kind: network.socks5
    host: 127.0.0.1
    port: 9050
    isolate_streams: true

  - name: probe
    kind: process.lua
    meta:
      command:
        name: probe
        short: Check outbound IP through overlays
        security:
          actor:
            id: system.probe
          policies:
            - app:net_policy
    source: file://probe.lua
    method: main
    modules:
      - io
      - http_client
      - json

isolate_streams: trueを指定すると、SOCKS5ドライバーが接続ごとにランダムなクレデンシャルを生成し、Torが各ダイアルで新しいサーキットを開きます。

セキュリティはデフォルトでストリクトなため、コマンドは起動時に使用するアクターとポリシーを携えます。http_client.requestがアウトバウンドコールを、network.selectが明示的なオーバーレイ選択をカバーします。これらがないとすべてのチェックがフェイルクローズします。

ステップ2: アウトバウンドコールをルーティングする

src/probe.luaを作成:

local io = require("io")
local http_client = require("http_client")
local json = require("json")

local function fetch_ip(overlay)
    local options = { timeout = "15s" }
    if overlay then
        options.overlay_network = overlay
    end

    local resp, err = http_client.get("https://api.ipify.org?format=json", options)
    if err then
        return nil, tostring(err)
    end
    if resp.status_code ~= 200 then
        return nil, "HTTP " .. resp.status_code
    end

    local body = json.decode(resp.body or "")
    return body and body.ip, nil
end

local function main()
    local direct, d_err = fetch_ip(nil)
    if d_err then
        io.print("direct failed: " .. d_err)
    else
        io.print("direct IP: " .. direct)
    end

    local routed, r_err = fetch_ip("app:tor")
    if r_err then
        io.print("tor failed: " .. r_err)
    else
        io.print("tor IP:    " .. routed)
    end

    return 0
end

return { main = main }

http_clientのoverlay_networkオプションは、その呼び出しのみにオーバーレイを適用します。指定しない場合、ダイアルはプロセスデフォルト(.wippy.yamlのnetwork_service.default_networkまたはダイレクト)を使用します。

ステップ3: 実行する

wippy init
wippy run probe

Torがローカルで動作している場合:

direct IP: <your public IP>
tor IP:    <Tor exit IP>

Torが動作していない場合、tor IP行にダイアルエラーが報告されます — SOCKS5オーバーレイはダイレクト接続に静かにフォールバックしません。

継承

オーバーレイの選択はネストされた呼び出しを通じて伝播します。funcs.callまたはprocess.spawnの境界で一度オーバーレイを指定すれば、その下のすべての内部HTTPコール、ネストされたfuncs.call、およびprocess.spawnは明示的なオーバーライドがあるまでそれを使用します:

local funcs = require("funcs")

local result, err = funcs.new()
    :with_options({ network = "app:tor" })
    :call("app:scrape_site", url)
local pid, err = process.with_options({ network = "app:tor" })
    :spawn_monitored("app.workers:probe", "app:processes")

ネストされた関数またはスポーンされたプロセスは、明示的に渡さなくても、すべてのアウトバウンドダイアルでオーバーレイを使用します。

リスナーのバインド

TailscaleはHTTPリスナーも受け付けられます。クライアントではなくhttp.serviceにオーバーレイを付与します:

  - name: bind_policy
    kind: security.policy
    policy:
      actions: "network.bind"
      resources: "*"
      effect: allow

  - name: tailnet
    kind: network.tailscale
    hostname: wippy-node
    auth_key: ${env:TS_AUTHKEY}
    ephemeral: true

  - name: gateway
    kind: http.service
    addr: ":8080"
    network: app:tailnet
    lifecycle:
      auto_start: true
      security:
        actor:
          id: system.gateway
        policies:
          - app:bind_policy

auth_keyはenv レジストリ経由で解決されるため、TS_AUTHKEYは登録済みの変数です。OSの値を使うにはenv.storage.osに紐づくenv.variableが必要です。

オーバーレイ経由のバインドはnetwork.bindで制御され、リスナーの起動時にチェックされます。そのためサービスはそれを許可するスコープを宣言します。サーバーはtailnetインターフェースにバインドし、クライアントはTailscaleアドレス経由でアクセスします。SOCKS5はアウトバウンド専用です — http.serviceに割り当てるとリスナーがinbound listeners are not exposed over SOCKS5で失敗します。

アプリ全体のデフォルト

.wippy.yamlにデフォルトオーバーレイを設定すると、オーバーライドされない限りすべての呼び出しで使用されます:

network_service:
  state_dir: .wippy/net
  default_network: app:tor

パーミッション

network.selectアクションが明示的なオーバーレイ選択を制御します。スコープで拒否するとコードがオーバーレイを選択できなくなります:

  - name: deny_network
    kind: security.policy
    policy:
      actions: "network.select"
      resources: "*"
      effect: deny
    groups:
      - untrusted

継承されたオーバーレイはこのチェックをバイパスします — 呼び出し元の境界で認可済みです。Lua境界での明示的な再選択のみが制御されます。

トラブルシューティングとクリーンアップ

  • 127.0.0.1:9050でconnection refusedになる場合は、設定したポートでTorがリッスンしていません。 Wippyを調べる前に、前提条件のcurlコマンドでTorを確認してください。
  • 直接リクエストが失敗しルーティングしたリクエストが成功する場合、通常はローカルDNS、プロキシ、 ファイアウォールの規則が直接経路に影響しています。2つの呼び出しは独立しています。
  • ルーティングした呼び出しのaccess deniedは、コマンドのセキュリティコンテキストにapp:torへの network.selectがないことを示します。meta.command.security配下にapp:probe_policyを付けたままにしてください。
  • SOCKS5ドライバーは直接接続へフォールバックしません。デモを続行させるためだけにエラーを削除しないでください。
  • Wippyコマンドが終了したら停止し、このチュートリアル専用にTorを起動した場合だけTorも停止してください。 SOCKS5の例は永続的なネットワーク状態を作りません。Tailscaleエントリは.wippy/net/tailscale/にノード状態を 保存する場合があります。Wippyを停止し、ローカルのtailnet IDを破棄する意図がある場合だけ.wippy/netを削除してください。

次のステップ