Help us understand the problem. What is going on with this article?

TyrusのStandalone Modeは0.0.0.0以外をListenすることはできない

More than 3 years have passed since last update.

結論

  • Tyrus1.12のStandalone Modeでは、WebSocketサーバーのListen Addressが0.0.0.0から変更できない。
  • つまり、(ファイヤーウォールがなければ)どこからでもアクセスし放題
  • 制限をかけるには
    • ファイヤーウォールを適切に設定する
    • Jettyを使う

Tyrus in Standalone Modeは0.0.0.0をListenする

スタンドアロンのアプリにWebSocketサーバを組み込みたかったので、調べていたら、Tyrus1.12のドキュメントにTyrus in Standalone Modeという項目を見つけたので試してみました。。

すると、確かに動くのですが、0.0.0.0をlistenしているのが気になりました。スタンドアロンアプリという性質上、localhost以外をlistenしたくなかったのです。

無題.png

制御不可

きっとどこかに設定があるのだと思いドキュメントを探しましたがどうも見当たりません。なので仕方なくソースを追ってみました。

まずはサンプルのソースコードを眺めます。

・・・
public void runServer() {
    Server server = new Server("localhost", 8025, "/websockets", null, EchoEndpoint.class);

    try {
        server.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Please press a key to stop the server.");
        reader.readLine();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        server.stop();
    }
}
・・・

org.glassfish.tyrus.server.Serverクラスをstartしているようです。見てみましょう。

github Server.java#L20

・・・
/**
 * Start the server.
 */
public void start() throws DeploymentException {
    try {
        if (server == null) {
            server = ServerContainerFactory.createServerContainer(properties);

            for (Class<?> clazz : configuration) {
                server.addEndpoint(clazz);
            }

            server.start(contextPath, port);
            LOGGER.info("WebSocket Registered apps: URLs all start with ws://" + this.hostName + ":" + this.port);
            LOGGER.info("WebSocket server started.");
        }
    } catch (IOException e) {
        throw new DeploymentException(e.getMessage(), e);
    }
}
・・・

org.glassfish.tyrus.spi.Server.ContainerFactoryクラスのcreateServerContainerメソッドを呼んでいるようなので更に潜ります。

github ServerContainerFactory.java#L70

・・・
private static final String CONTAINTER_CLASS =
            "org.glassfish.tyrus.container.grizzly.server.GrizzlyServerContainer";
・・・
public static ServerContainer createServerContainer(final Map<String, Object> properties) {
    ・・・
    if (factory == null) {
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Class factoryClass = (classLoader == null)
                    ? Class.forName(CONTAINTER_CLASS)
                    : classLoader.loadClass(CONTAINTER_CLASS);
            factory = (ServerContainerFactory) factoryClass.newInstance();
        } catch (ClassNotFoundException ce) {
            throw new RuntimeException(ce);
        } catch (InstantiationException ie) {
            throw new RuntimeException(ie);
        } catch (IllegalAccessException ie) {
            throw new RuntimeException(ie);
        }
    }
    return factory.createContainer(properties);
}
・・・

どうやらorg.glassfish.tyrus.container.grizzly.server.GrizzlyServerContainerクラスが実体のようです。見てみます。

github GrizzlyServerContainer.java#L172

・・・
@Override
public void start(final String rootPath, int port) throws IOException, DeploymentException {
    contextPath = rootPath;
    server = new HttpServer();
    final ServerConfiguration config = server.getServerConfiguration();

    final NetworkListener listener = new NetworkListener("grizzly", "0.0.0.0", port);  // ★!!!★
    ・・・
}
・・・

うげ!おもいっきり"0.0.0.0"ってハードコードしてあるし!

ということで、0.0.0.0をlistenしてしまうのは変更不可のようです。

代替案

どうすればよいのでしょうか。

ファイヤーウォールを正しく設定する。

「どうすればよいのでしょうか」といってもどうにもできないので、ちゃんとファイヤーウォールを設定しましょうというのが結論でしょう。不正なリクエストは受け付けないようにすればいい話です。とはいえ、自分用のアプリならいいとして、いろいろな人に配るようなアプリの場合「設定してね」と言う以上のことはできません。設定してくれるかどうかは利用者次第です・・・

別の実装を使う

tyrusの実装がこうなっているというだけなので、tyrusじゃない別の実装を使うというのも良い選択でしょう。ただし、現時点ではドキュメントが少ないですね・・・

ちなみに私はJettyを使いました。

JavaSEでJettyを使ってWebSocket(JSR-356)サーバーを立てた

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away