Skip to content

Relay(プロキシ)

Relay は「サーバー + クライアント」の組み合わせで、中間者(MITM)接続 を実現するクラスです。クライアントと宛先サーバーの間に割り込み、通過するパケットを観測・改変・遮断できます。認証や暗号化の処理は Relay が面倒を見ます。

最小のサンプル

js
const { Relay } = require('bedrock-protocol')

const relay = new Relay({
  version: '1.21.50',
  host: '0.0.0.0',   // クライアントの受け口
  port: 19132,
  destination: {     // 転送先サーバー
    host: '127.0.0.1',
    port: 19131
  }
})

relay.listen() // 待ち受け開始

relay.on('connect', player => {
  console.log('新しい接続:', player.connection.address)

  // サーバー → クライアント方向のパケットを観測・改変
  player.on('clientbound', ({ name, params }, des) => {
    if (name === 'disconnect') {
      params.message = 'Intercepted' // キックメッセージを書き換え
    }
  })

  // クライアント → サーバー方向のパケットを観測・改変・遮断
  player.on('serverbound', ({ name, params }, des) => {
    if (name === 'text') {
      params.message += `, on ${new Date().toLocaleString()}` // チャットに時刻を追記
    }

    if (name === 'command_request' && params.command === '/test') {
      des.canceled = true // パケットを握りつぶす(転送しない)
    }
  })
})

使い方の要点

パケットの流れ

クライアント ⇄ [Relay サーバー] ⇄ [Relay 上流クライアント] ⇄ 宛先サーバー

              clientbound / serverbound イベントで傍受
イベント対象
clientbound宛先サーバーから クライアントへ向かう パケット
serverboundクライアントから 宛先サーバーへ向かう パケット

ハンドラは (packet, des) を受け取ります。

  • packet.name … パケット名(例: 'text')
  • packet.params … パケット本体(ここを書き換えると改変される)
  • des.canceled = true … そのパケットの転送をキャンセル

送信

操作コード
クライアントへ送るplayer.queue(name, params)
宛先サーバーへ送るplayer.upstream.queue(name, params)

主なオプション

オプション説明
destination.host / port転送先サーバー(必須)
destination.offline上流接続で認証をスキップするか
offline接続してきたクライアントの認証をスキップ(false 指定時はログイン要求)
version動作させるバージョン
loggingパケットログの出力
enableChunkCachingチャンクキャッシュを有効化(デフォルト false)
forceSingle同時接続を 1 クライアントに制限(デフォルト false)
omitParseErrorsパースエラー時に切断せずパケットを破棄(デフォルト false)
onMsaCode上流参加用の認証トークンが必要になったときに呼ばれるコールバック。未指定の場合、クライアントはログインプロンプト付きで切断されます

認証について

offline を指定しない場合、Relay に接続してきたクライアントに対してログイン(Xbox Live 認証)を求めます。上流サーバーがオンラインモードの場合、その認証情報がそのまま転送に使われます。

上級者向けの拡張ポイント(コードから)

src/relay.js を読むと、ドキュメント外のカスタマイズポイントが見つかります。

オプション / 機能説明
relayPlayer独自の RelayPlayer 派生クラスを注入できる(new Relay({ relayPlayer: MyPlayer }))。パケット中継ロジックを丸ごと差し替え可能
noLoginForward(Client 側フラグ)下流クライアントの skinData を上流ログインに転送しない
'join' イベントRelay 自体が (下流 Player, 上流 Client) の 2 引数付きで発火する。両側を直接操作したい場合に便利
双方向キュー上流 / 下流のどちらかが未接続でも、到着したパケットは自動でキューイングされ、接続後にフラッシュされる
client_cache_status 強制制御チャンクキャッシュ要求は enableChunkCaching の値で常に上書きされる
js
relay.on('join', (downstream, upstream) => {
  // downstream: Relay に接続した Player
  // upstream:   バックエンドに接続済みの Client
})

Realm を経由する Relay

destination.realms を指定すると、宛先として Realm を使えます。実装例はリポジトリの examples/realmRelay.js を参照してください。