I have an issue using NettyJaxrsServer with SSL. The first request succeed and subsequent ones timeout. Typically, if I use curl to send an HTTPS request, only the first call passes. I checked with wireshark to see what is happening. The server performs the handshake only for the first request. For the second request the client sends a "Hello" message, and the server do not continue the handshake. It seems like the server is keeping an SSL session even after the client disconnection.
I verified the code and for each client connection, a new SSLHandler is inserted in the client pipeline but using the same SSLEngine.
final SSLEngine engine = sslContext.createSSLEngine();
engine.setUseClientMode(false);
bootstrap.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst(new SslHandler(engine));
ch.pipeline().addLast(channelHandlers.toArray(new ChannelHandler[channelHandlers.size()]));
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new HttpObjectAggregator(maxRequestSize));
ch.pipeline().addLast(new HttpResponseEncoder());
ch.pipeline().addLast(new RestEasyHttpRequestDecoder(dispatcher.getDispatcher(), root, RestEasyHttpRequestDecoder.Protocol.HTTPS));
ch.pipeline().addLast(new RestEasyHttpResponseEncoder());
ch.pipeline().addLast(eventExecutor, new RequestHandler(dispatcher));
}
})
.option(ChannelOption.SO_BACKLOG, backlog)
.childOption(ChannelOption.SO_KEEPALIVE, true);
From Netty documentation, I understand that a new SSLEngine should be used for each new client connection:
Restarting the session
To restart the SSL session, you must remove the existing closed SslHandler from the ChannelPipeline, insert a new SslHandler with a new SSLEngine into the pipeline, and start the handshake process as described in the first section.
Can someone explain this behavior? or is this a bug in Netty resteasy server?
Used version: resteasy-netty4 3.0.11.Final
Related
I'm trying to code a high performance reverse proxy server using Netty 4.1.
I based my code on an Java adaptation of Feng-Zihao/protox and the Netty Proxy Example.
I first had some trouble handling 100-CONTINUE but adding the HttpObjectAggregator into my pipeline kinda solved that.
serverBootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new HttpResponseEncoder());
ch.pipeline().addLast(new HttpObjectAggregator(1048576));
ch.pipeline().addLast(new FrontendHandler());
}
})
// .option(ChannelOption.SO_REUSEADDR, true)
// .option(ChannelOption.SO_BACKLOG, 128)
// .childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.AUTO_READ, false)
.bind(port).sync();
On the client side, the request hangs indefinitely.
The thing is, AUTO_READ being at false seems to prevent the HttpObjectAggregator to do his work and my FrontendHandler only ever receives the channelActive event but never the channelRead.
It seems though that I need that to make sure I don't get into some race condition between the reads and the remote peer connection.
FYI, my goal in the end is to choose to forward or not the request based on a filter (probably a new handler right before my FrontendHandler) that will need to read the full http content.
Am I missing something here ?
Turn on auto read when your outbound channel becomes active, and have your FrontendHandler turn it off while processing each message. Then turn it on again when you are ready to handle another message.
This will let HttpObjectAggregator keep reading as many messages as it needs to in order to create a FullHttpMessage, and then stop sending it messages while your FrontendHandler is processing or waiting on some client write to invoke a listener.
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.channel().config().setAutoRead(false);
...
// This call should probably be in some event listener
ctx.channel().config().setAutoRead(true);
Here is my probelm: I have an Android application that communicates with an API on a specific server, which has the IP address IP_Server, through HTTP messages and using SSL. I want to impersonate the API and receive the messages from the application (from one of my smartphone) on my computer and respond to them as I want (according to the API protocol). To do so, in my router, I redirect the route for the IP_Server to my local network and I assign the IP_Server IP address to my computer. Then, I run a Java Server that listens on the port 443 using SSLSocket. At this stage, I receive the connection request when the application wants to communicate. However, the handshake fails. I think that it’s a certificate problem but I’m not sure and I don’t know how to resolve this issue.
public static void startServer() throws Exception
{
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(443);
while (running)
{
// Listen.
SSLSocket clientSocket = (SSLSocket)sslserversocket.accept();
System.out.println("Connection accepted from:" +
clientSocket.toString());
clientSocket.startHandshake(); // This line causes a timeout.
// Handle the request.
threadPool.execute(new ServerThread(clientSocket));
}
}
Thanks for your help!
I'm writing a game server in Java, and I'm using Netty 3.6.2. The game servers should accept no HTTP requests, as they simply handle game client data (which is purely bytes over TCP). When I load http://server-ip:game-servers-port in Chrome, I download a file with the game's handshake packet (which should not happen).
I bind to the game server's port like so:
ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
clientAcceptor = new ServerBootstrap(factory);
clientAcceptor.setOption("child.tcpNoDelay", true);
clientAcceptor.setOption("child.keepAlive", false);
clientAcceptor.setPipelineFactory(() -> Channels.pipeline(new PacketDecoder(), new ClientHandler()));
clientAcceptor.bind(new InetSocketAddress(Configurations.CHANNEL_GAME_PORT));
And I process requests in a SimpleChannelHandler, like so
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
// Encryption key code.
Packets.sendHello(ctx.getChannel(), ivRecv, ivSend);
ctx.getChannel().setAttachment(client);
}
How can I go about deciphering if an incoming request is using the HTTP protocol?
Edit: I should also say, it should also block any FTP, WebSocket, etc. protocol (essentially anything that isn't the game's protocol) on channel connect.
You can't expect to be able to disable HTTP requests if the first thing you do with an accepted connection is to send something.
Have the client do the first send in the handshake. Have the server start by doing a receive, and if it isn't the correct initial handshake packet, close the connection.
I have the read the netty proxy server example. However I would like to know how to implement a client to talk to the proxy. The solution I am implementing is a server and it needs to connect to a socket server whenever a client connect to the server.So each client connected to the server will be able to send/receive data from another server.
I need help to inplement such architecture with netty because the server side is built on netty.
It seems what you want to implement can be pretty much answered by the Netty proxy example
The code segment below shows how you can connect to the remote server once a new client channel is opened.
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
// Suspend incoming traffic until connected to the remote host.
final Channel inboundChannel = e.getChannel();
inboundChannel.setReadable(false);
// Start the connection attempt.
ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort));
outboundChannel = f.getChannel();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// Connection attempt succeeded:
// Begin to accept incoming traffic.
inboundChannel.setReadable(true);
} else {
// Close the connection if the connection attempt has failed.
inboundChannel.close();
}
}
});
}
Once connected to the remote server, whatever the client sends (via inbound channel) is forwarded to the remote server (outbound channel).
I suggest you to follow and implement the proxy example if you haven't done it so already.
I'm using Netty with Java trying to configure a TCP client. Everything is working so far, except that I'm connecting on port 1050 but when I call messageEvent.getRemoteAddress() on messageReceived() method of the handler, I'm getting the port 1500. I changed the port to 1049 but I'm still receiving 1500. This is Netty's problem or can it be the server's problem?
My hardware setup here is: this netty client running on a Java server, and several access control equipments spread through the area here. The equipments act as tcp servers and the netty as the client, that process everything the server sends and just reply to them.
The tcp server initialization is this:
private ChannelFactory fabrica;
private ServerBootstrap bootstrap;
public void iniciarServidorTCP() {
fabrica = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
bootstrap = new ServerBootstrap(fabrica);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoderDeMensagem", new MensagemDecoderTCP());
pipeline.addLast("handlerGerente", new GerenteTCP());
pipeline.addLast("encoder de mensagem", new MensagemEncoderTCP());
return pipeline;
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.reuseAddress", true);
bootstrap.bind(new InetSocketAddress(1050));
}
Any idea why I'm getting 1500 instead of 1050? Could it be a problem with the equipment?
Every TCP connection has a source port and a destination port. When you connect to a server, the server sees the destination port as its well-known address. The client picks the source port. On either end, getting the "remote address" gets the other side's address. So when you call get remote address on the server, you get the client's address, not the server's.
Imagine you have a server with one IP address and one well-known port. Now, say you have a client machine with one IP address. If it make's four connections to the server, how can either end tell those connections apart? The answer is that the client port is different.