vert-x3 / issues

Apache License 2.0
37 stars 7 forks source link

Pump.pump() only receives part of the response #108

Open kwf2030 opened 8 years ago

kwf2030 commented 8 years ago

Simple socks5 proxy using vertx 3.2.1. It always receive only part of the response and then blocked until timeout. And it had no problems when I used socks codec with netty4.1.

public class ProxyHandler implements Handler<Buffer> {
  private NetSocket socket;
  private ReqType reqType;

  private enum ReqType {
    INIT,
    CMD,
    UNKNOWN
  }

  public ProxyHandler(NetSocket socket) {
    this.socket = socket;
    this.reqType = ReqType.INIT;
  }

  @Override
  public void handle(Buffer buffer) {
    switch (reqType) {
      case INIT:
        reqType = ReqType.CMD;
        if (buffer.getByte(0) != 0x05) {
          socket.close();
          Log.debug("Only supports socks5");
          return;
        }
        Buffer buf = Buffer.buffer(2).appendByte((byte) 0x05).appendByte((byte) 0x00);
        socket.write(buf);
        return;

      case CMD:
        reqType = ReqType.UNKNOWN;
        if (buffer.getByte(1) != (byte) 0x01) {
          socket.close();
          Log.debug("Only supports CONNECT command");
          return;
        }
        byte addrType = buffer.getByte(3);
        if (addrType == 0x01 || addrType == 0x04) {
          //ipv4 or ipv6
          int o = addrType == 0x01 ? 8 : 20;
          byte[] ip = buffer.getBytes(4, o);
          int port = buffer.getUnsignedShort(o);
          try {
            connect(InetAddress.getByAddress(ip).getHostAddress(), port, addrType);
          } catch (UnknownHostException e) {
            socket.close();
            Log.debug(e.getMessage());
          }

        } else if (addrType == 0x03) {
          //domain
          byte len = buffer.getByte(4);
          byte[] domain = buffer.getBytes(5, len + 5);
          int port = buffer.getUnsignedShort(len + 5);
          connect(new String(domain, StandardCharsets.US_ASCII), port, addrType);

        } else {
          socket.close();
          throw new IllegalStateException("Unknown address type");
        }
        break;

      default:
        throw new IllegalStateException("Unknown socks request type");
    }
  }

  private void connect(String host, int port, byte addrType) {
    Vertx v = Context.vertx();
    v.executeBlocking(future -> v.createNetClient().connect(port, host, result -> {
      if (result.succeeded()) {
        NetSocket remote = result.result();
        Buffer buf = Buffer.buffer().appendByte((byte) 0x05)
          .appendByte((byte) 0x00)
          .appendByte((byte) 0x00)
          .appendByte(addrType)
          .appendString(host, "US-ASCII")
          .appendUnsignedShort(port);
        socket.write(buf);
        Pump.pump(socket, remote).start();
        Pump.pump(remote, socket).start();
      } else {
        socket.close();
      }
    }), null);
  }
}
NetServer server = Context.vertx().createNetServer();
server.connectHandler(socket -> {
  socket.handler(new ProxyHandler(socket));
}).listen();

Tested with curl -s -x socks5://127.0.0.1:1080 www.xxx.com, and it printed both the HTTP header and body!!! But nothing printed when using curl -I, how can headers and body mixed togenther?

alexlehm commented 8 years ago

@kwf2030 I think you are missing the size prefix of the domain in the connect reply