deathcap / wsmc

WebSocket proxy to Minecraft
33 stars 10 forks source link

[wsmc/Java] HTTP server returns 'Not implemented' on non-localhost hostnames #30

Closed deathcap closed 8 years ago

deathcap commented 8 years ago

http://localhost:24444/ - ok http://127.0.0.1:24444/ - Not implemented http://anythingelse:24444/ - Not implemented

voxel-clientmc $ curl -v 'http://127.0.0.1:24444/'
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 24444 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:24444
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Mon, 08 Feb 2016 10:00:09 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
< 
* Connection #0 to host 127.0.0.1 left intact
Not implemented

Non-localhost hosts are very important so that the service can be reachable externally

deathcap commented 8 years ago

Figured this was caused by the Host header, but seems to be binding to only IPv6 not IPv4(?!):

wsmc $ perl -e'print "GET / HTTP/1.0\r\n\r\n"'|nc -vv localhost 24444
found 0 associations
found 1 connections:
     1: flags=82<CONNECTED,PREFERRED>
    outif lo0
    src ::1 port 49606
    dst ::1 port 24444
    rank info not available
    TCP aux info available

Connection to localhost port 24444 [tcp/*] succeeded!
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 633

<!DOCTYPE HTML>
<html>
<head>
<title>voxel-clientmc</title>
<style>
body {
    background-color: lightgray;
}
</style>
</head>
<body>
<a href="https://github.com/voxel/voxel-clientmc"><img style="position: absolute; top: 0; left: 0; border: 0;" src="https://camo.githubusercontent.com/121cd7cbdc3e4855075ea8b558508b91ac463ac2/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f677265656e5f3030373230302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_green_007200.png"></a>
<script src="bundle.js"></script>
</body>
</html>
wsmc $ perl -e'print "GET / HTTP/1.0\r\n\r\n"'|nc -vv 127.0.0.1 24444
found 0 associations
found 1 connections:
     1: flags=82<CONNECTED,PREFERRED>
    outif lo0
    src 127.0.0.1 port 49607
    dst 127.0.0.1 port 24444
    rank info not available
    TCP aux info available

Connection to 127.0.0.1 port 24444 [tcp/*] succeeded!
HTTP/1.1 200 OK
Content-Type: text/plain
Date: Tue, 09 Feb 2016 09:10:43 GMT
Connection: close

Not implementedwsmc $ 

passing to ServerBootstrap bind, "0.0.0.0" wsAddress by default:

            Channel channel = bootstrap.bind(this.wsAddress, this.wsPort)
deathcap commented 8 years ago

bind(SocketAddress) : ChannelFuture bind(int) : ChannelFuture bind(InetAddress, int) : ChannelFuture bind(String, int) : ChannelFuture

all call into InetSocketAddress() constructor: http://docs.oracle.com/javase/7/docs/api/java/net/InetSocketAddress.html - "A null address will assign the wildcard address."

Testing this:

            ChannelFuture channelFuture;
            if (this.wsAddress == null || this.wsAddress.equals("0.0.0.0") || this.wsAddress.equals("")) {
                channelFuture = bootstrap.bind(this.wsPort);
            } else {
                channelFuture = bootstrap.bind(this.wsAddress, this.wsPort);
            }

but no difference. Doesn't seem to be a problem in binding but in handling? https://github.com/netty/netty/pull/4770?

deathcap commented 8 years ago

ServerHandler pipeline is:

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline.addLast("codec-http", new HttpServerCodec());
        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
        pipeline.addLast("handler", new HTTPHandler(this.webThread.wsPort));
        pipeline.addLast("websocket", new WebSocketServerProtocolHandler("/server"));
        pipeline.addLast("websocket-handler", new WebSocketHandler(webThread, this.mcAddress, this.mcPort, this.users, this.filter, this.verbose));
    }

first my code runs in HTTPHandler, but none of the `@Override'en methods in HTTPHandler are called when accessing over IPv4 (ok over IPv6).

    protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg)
            throws Exception {
        System.out.println("HTTPHANDLER MESSAGERECEIVED");

    private static void copyStream(InputStream in, OutputStream out) throws IOException {
        System.out.println("HTTPHANDLER COPYSTREAM");

    public void httpRequest(ChannelHandlerContext context, FullHttpRequest request) throws IOException {
        System.out.println("HTTPHANDLER HTTPREQUEST");

    public void sendHttpResponse(ChannelHandlerContext context, FullHttpRequest request, FullHttpResponse response) {
        System.out.println("HTTPHANDLER SENDHTTPRESPONSE");

need to find out where and what is returning the "Not implemented" response before I get it

deathcap commented 8 years ago

https://github.com/netty/netty/search?utf8=✓&q=%22Not+implemented%22 shows there are "501 Not Implemented" (notice capital "I") HttpResponseStatus.NOT_IMPLEMENTED responses, but this is a HTTP/1.1 200 OK with body "Not implemented"

deathcap commented 8 years ago
--- a/src/main/java/deathcap/wsmc/web/WebThread.java
+++ b/src/main/java/deathcap/wsmc/web/WebThread.java
@@ -27,6 +27,7 @@ import io.netty.channel.group.ChannelGroup;
 import io.netty.channel.group.DefaultChannelGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.NetUtil;
 import io.netty.util.ResourceLeakDetector;
 import io.netty.util.concurrent.GlobalEventExecutor;

@@ -72,7 +73,7 @@ public class WebThread extends Thread {
             SocketAddress socketAddress;

             if (this.wsAddress == null || this.wsAddress.equals("")) {
-                socketAddress = new InetSocketAddress((InetAddress) null, this.wsPort);
+                socketAddress = new InetSocketAddress(NetUtil.LOCALHOST4, this.wsPort);
             } else {
                 socketAddress = new InetSocketAddress(this.wsAddress, this.wsPort);
             }

Using NetUtil.LOCALHOST4 (per https://github.com/netty/netty/pull/4770, which was "Cherry-picked into 4.0 (52ba4f4) and 4.1 (3616d9e)" in Netty 13 days ago) correctly allows accessing the server over IPv4 at these URLs: http://127.0.0.1:24444/#testuser:VXVbHahf http://localhost:24444/ http://0.0.0.0:24444/ - but not my local (RFC1918) IP, nor the IPv6 local http://[::1]:24444/ nor the IPv6 global address. What I'm looking for is not a localhost IPv4 but "wildcard IPv4" (and/or wildcard IPv4+IPv6)

deathcap commented 8 years ago
+                    socketAddress = new InetSocketAddress(Inet4Address.getLocalHost(), this.wsPort);

allows using my IPv4 RFC1918 local network address, but not localhost, 127.0.0.1, 0.0.0.0, ::1, anything else. Am I really going to have to listen multiple servers for each interface?

deathcap commented 8 years ago

Turns out "Not implemented" is from wsmc/JavaScript (wsmc.js). Related: https://github.com/deathcap/wsmc/pull/31 [Broken] Update all dependencies (ws/websocket-stream) 🌴

deathcap commented 8 years ago

Always something simple... (InetAddress) null = wildcard works correctly for both IPv4 and IPv6, lo0 and en1. Why I was seeing different behavior is that wsmc.js was erroneously running (user error, nonetheless non-informative error message) but only bound to IPv4 (bug/missing feature?), and wsmc.jar tried to bind everywhere but silently failed on IPv4 since the port was occupied so it only bound to IPv6 (missing error message?).

deathcap commented 8 years ago

Fixed wsmc.js to bind to '' instead of '0.0.0.0' by default (IPv4+IPv6), now wsmc.jar gives a more informative binding error message:

[23:49:41 WARN]: java.net.BindException: Address already in use
[23:49:41 INFO]: Cactus Growth Modifier: 100%
[23:49:41 WARN]:    at sun.nio.ch.Net.bind0(Native Method)
[23:49:41 WARN]:    at sun.nio.ch.Net.bind(Net.java:344)
[23:49:41 WARN]:    at sun.nio.ch.Net.bind(Net.java:336)
[23:49:41 INFO]: Cane Growth Modifier: 100%
[23:49:41 WARN]:    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:199)
[23:49:41 WARN]:    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:104)
[23:49:41 INFO]: Melon Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:464)
[23:49:41 INFO]: Mushroom Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.DefaultChannelPipeline$HeadHandler.bind(DefaultChannelPipeline.java:1032)
[23:49:41 INFO]: Pumpkin Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.ChannelHandlerInvokerUtil.invokeBindNow(ChannelHandlerInvokerUtil.java:99)
[23:49:41 INFO]: Sapling Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.DefaultChannelHandlerInvoker.invokeBind(DefaultChannelHandlerInvoker.java:196)
[23:49:41 INFO]: Wheat Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.DefaultChannelHandlerContext.bind(DefaultChannelHandlerContext.java:366)
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:898)
[23:49:41 INFO]: NetherWart Growth Modifier: 100%
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.AbstractChannel.bind(AbstractChannel.java:189)
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:309)
[23:49:41 INFO]: Entity Activation Range: An 32 / Mo 32 / Mi 16
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:318)
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353)
[23:49:41 WARN]:    at deathcap.wsmc.lib.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:794)
[23:49:41 INFO]: Entity Tracking Range: Pl 48 / An 48 / Mo 48 / Mi 32 / Other 64
[23:49:41 WARN]:    at java.lang.Thread.run(Thread.java:724)
[23:49:41 INFO]: Hopper Transfer: 8 Hopper Check: 8 Hopper Amount: 1