統合版MinecraftのマルチプレイはReverse-Shellだった

# はじめに

統合版マイクラはPortForwardingをしなくともインターネットで友達と一緒のワールドでプレイできますが
私はその仕組みにずっと疑問を抱いてきました。
なぜPortForwardingを行わなくとも他の人が自分のワールドに入ってこれるのだろうと。
今回はその疑問に対する私の仮説を紹介していこうと思います。
それと記事のタイトルはあくまで少し誇張した表現ですので、真剣に受け取らないで下さい。
この記事では、マルチプレイができる仕組みと、PortForwardingの仕組みを簡単に解説した後に、私の仮説を説明したいと思います。

# 前提知識

## マルチプレイの仕組み

マイクラではまずワールドに入って遊ぶ側と、ワールドを提供する側の２つに分かれます。
今回は遊ぶ側をクライアント、提供する側をサーバーと定義して話を進めていきます。
クライアントはワールドの情報(他のプレイヤーの座標、ワールドの地形情報)をリクエストしたり
自分の情報(自分のMCIDや今のワールド内の座標など)をサーバーに送ったりして１つのワールドでみんなで遊んでいる状態を実現します。
![bedrock_clientserver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/de71ae67-1aa5-2788-d49b-77a37f5eb490.png)
図で表すとこのような通信になります。(実際のネットワーク通信を単純化した図です)
これはメッセンジャーアプリでも同じです。クライアントはメッセージを送信したり
他の人がチャンネルに送ったメッセージを取得するリクエストをしたりして、同じチャンネル上での通信を実現させています。

## PortForwardingとは

先述したようにマルチプレイにはクライアントがサーバーと通信する必要があります。
ですが、このままではサーバーと通信しようとしても通信が確立できません。
![lan_and_internet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/6adf06a0-9f98-18d9-c2f7-3aba130729eb.png)
私たちのネットワークでは家のネットワーク(この記事ではLANと定義する)とインターネットが直接つながっているわけではありません。
ある事情でLANとインターネットの間を特殊な処理を通してつなげているのです。
この処理のせいで、インターネットから来るアクセスは基本LANにあるPCに通らないようになっています。
ですが、自分(LAN)からインターネットにあるサーバーに対してアクセスすることはできます。
そして一度サーバーに対して通信を確立してしまえば、サーバーがLANに対してアクセスをすることができます。
ですが、いちいちクライアント一人ひとりに対して自分から通信を確立しにいくのも現実的ではないので
今のインターネットでは特定のサービス(マイクラのサーバーやwebサーバーなど)に対してのアクセスは自分のサーバーに通すという設定を行っているのです。
この設定のことをPortForwardingといいます。
![lan_and_internet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/2486a958-8db0-7fac-13c3-95ec7bd13ced.png)

# 仮説

現在のインターネットの構造上マルチプレイでも、サーバーを立てる側はこの「マイクラサーバーにアクセスしてくる通信は僕のサーバーに通してね」という設定をする必要があるのです。
ですが統合版マイクラではそのような設定をしなくともマルチプレイができています。一体どのような仕組みで動いているのでしょうか？
ここからはその仕組みに対する仮説を紹介していきます。
先ほども説明した通り、インターネットからのアクセスは基本LANのPCに届きません。
ですが、LANのPCからインターネットにあるサーバーにアクセスすることはできます。
そこで通信が確立してしまえば、インターネットにあるサーバーからLANにあるPCに対しての通信が通るようになります。
(今回はなぜコネクションを確立したらインターネットにあるサーバーがLANのPCと通信できるようになるかまでは説明しません)
![reverseshell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/d351f0bb-a7dd-a920-1309-cddcf4d15a07.png)
私たちがウェブサイトを閲覧する時の動作もこれと同じです。
まずウェブサーバーへアクセスし、コネクションを確立します。そうするとウェブサーバー側がウェブサイトの情報をLANにあるPCに送信できるようになります。
私はこの性質を利用してPortForwarding無しでマルチプレイを可能にしているのではないかと考えます。
仕組みとしては、まず最初にインターネット上にマイクラサーバーとクライアントの通信を繋げる中間者サーバーを用意します。
ここでいう中間者サーバーとは、クライアントから受け取った通信をサーバー側のPCに届ける
(クライアントから受け取ったリクエストの内容をサーバー側のPCにリクエストする)サーバーのことを言います。
そして、サーバー側はこの中間者からのリクエストに対して処理をするようなプログラムを実行させておきます。
(例えば、ワールドの地形情報をリクエストされたらそれを返すような処理や他のクライアントの座標を提供する処理など)
その上でサーバー側のPCと中間者サーバーの間で通信を確立させます。
クライアントは中間者サーバーにリクエスト(ワールドに接続するリクエストやワールドの地形情報のリクエストなど)を投げることで
最終的にクライアントからのリクエストが中間者サーバーを経由してサーバー側のPCに届くことになります。
この記事では中間者サーバーのことをhubサーバーと呼ぶことにしましょう。
![hub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/c4becee3-8d08-67f5-3f4d-8ce0f93fd5d7.png)
この方法ならば、サーバー側がPortForwardingをしなくともクライアントと通信ができます。

# 余談

この方法は統合版マイクラでしかできないということはありません。
中間者サーバーを返して通信ができれば、Java版マイクラでも実現可能です。
実際Essentials modがJava版マイクラでのPortForwarding無しでのマルチプレイを可能にする機能を提供しています。
その他にも外部サービスを利用した方法もあります。(https://www.ravbug.com/tutorials/mc-ngrok/)
ですが、現段階ではまだ仮説に過ぎませんので、統合版マイクラがこのような仕組みで動いていると断定はできません。
それと、この仮説を思いついたきっかけにはreverse-shellというテクニックの動作原理が大きく関係しています。
興味がある人は調べてみてください。