Netty (UDP) SSLException : Received close_notify during handskake,close channel - ssl

I want to write an UDP Netty Server/Client with SSL . I did it in the way similar to TCP Netty Server/Client which worked well. But I meet an exception:
javax.net.ssl.SSLException:Received close_notify during handskake,close channel...
My netty is 3.x , SSL configure works well . Here is some code of my Udp Server and Client. Server:
serverBootstrap = new ConnectionlessBootstrap(
new NioDatagramChannelFactory(Executors.newCachedThreadPool(),maxThreads));
serverBootstrap.setOption("receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(8192));
ChannelPipelineFactory fac = null;
try {
ServiceDecoder serviceProcessor = (ServiceDecoder)Class.forName(serviceDecoderName).newInstance();
Class<? extends ChannelPipelineFactory> clazz = (Class<? extends ChannelPipelineFactory>) Class
.forName(msgFactoryName);
Constructor ctor = clazz.getConstructor(ChannelProcessor.class,
ChannelGroup.class, CounterGroup.class, CounterGroupExt.class, String.class,ServiceDecoder.class,
String.class, Integer.class, String.class, String.class, Boolean.class,Integer.class,Boolean.class,Boolean.class,Context.class);
logger.info("Using channel processor:{}", getChannelProcessor().getClass().getName());
fac = (ChannelPipelineFactory) ctor.newInstance(
getChannelProcessor(), allChannels, counterGroup, counterGroupExt, "udp", serviceProcessor,
messageHandlerName, maxMsgLength, topic, attr, filterEmptyMsg, maxConnections, isCompressed,enableSsl,context);
} catch (Exception e) {
logger.error(
"Simple Udp Source start error, fail to construct ChannelPipelineFactory with name {}, ex {}",
msgFactoryName, e);
stop();
throw new FlumeException(e.getMessage());
}
serverBootstrap.setPipelineFactory(fac);
try {
if (host == null) {
nettyChannel = serverBootstrap
.bind(new InetSocketAddress(port));
} else {
nettyChannel = serverBootstrap.bind(new InetSocketAddress(host,
port));
}
Pipeline in Server:
if(enableSsl) {
cp.addLast("ssl", sslInit());
}
if (processor != null) {
try {
Class<? extends SimpleChannelHandler> clazz = (Class<? extends SimpleChannelHandler>) Class
.forName(messageHandlerName);
Constructor<?> ctor = clazz.getConstructor(
ChannelProcessor.class, ServiceDecoder.class, ChannelGroup.class,
CounterGroup.class, CounterGroupExt.class, String.class, String.class,
Boolean.class, Integer.class, Integer.class, Boolean.class);
SimpleChannelHandler messageHandler = (SimpleChannelHandler) ctor
.newInstance(processor, serviceProcessor, allChannels,
counterGroup, counterGroupExt, topic, attr,
filterEmptyMsg, maxMsgLength, maxConnections, isCompressed);
cp.addLast("messageHandler", messageHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
if (this.protocolType.equalsIgnoreCase(ConfigConstants.UDP_PROTOCOL)) {
cp.addLast("execution", executionHandler);
}
client:
private ConnectionlessBootstrap clientBootstrap;
clientBootstrap = new ConnectionlessBootstrap(
new NioDatagramChannelFactory(Executors.newCachedThreadPool()));
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("sslHandler", sslInit());
pipeline.addLast("orderHandler",new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(cores * 2,
1024 * 1024, 1024 * 1024)));
return pipeline;
}
});
Two function to send message in the client:
public void sendMessage(byte[] data) {
ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(data);
sendMessage(buffer);
}
public void sendMessage(ChannelBuffer buffer) {
Random random = new Random();
Channel channel = channelList.get(random.nextInt(channelList.size()));
if(!channel.isConnected()){
channel.close();
ChannelFuture cf = clientBootstrap
.connect(new InetSocketAddress(ip, port));
if(cf.awaitUninterruptibly(3000, TimeUnit.MILLISECONDS)){
channel = cf.getChannel();
}else {
channelList.remove(channel);
return;
}
}
ChannelFuture future = channel.write(buffer);
if(!future.awaitUninterruptibly(3, TimeUnit.SECONDS)){
logger.warn("send failed!{}",future.getCause());
}else {
sendCnt.incrementAndGet();
}
}
I suspect whether UDP Netty Server/Client support SSL. Any tips are appreciated.

UDP does not guarantee the order of packets, as opposed to TCP, since there is no session. Thus, during the SSL negotiation, there could be an issue, depending on the order of the UDP packets.
According to what I read, you might have a look to DTLS which suppose to add a sort of order control in UDP packets, but lot of SSL libraries do not support it.
Since Netty only implements TLS, it may not work with UDP.

Related

What is the most simple Reactor / Netty implementation for SSDP protocol?

I tried a lot of stuff with UdpClient, UdpServer, Spring Integration Ip module, wrapping DatagramSocket receive method to return a Flux, but I simply cannot receive any response from standard SSDP 239.255.255.250:1900.
Bonus points for also sending a packet to SSDP.
For those interested, here's a snippet. I was able to do it via Flux emitter instead of reactor-netty UDP classes.
private static final String SSDP_IP = "239.255.255.250";
private static final int SSDP_PORT = 1900;
private static final int TIMEOUT = 5000;
String request = new String("example");
byte[] receiveData = new byte[1024];
DatagramPacket sendPacket = new DatagramPacket(request.getBytes(),
request.getBytes().length, InetAddress.getByName(SSDP_IP), SSDP_PORT);
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length,
InetAddress.getLocalHost(), SSDP_PORT);
Flux<String> response = Flux.create(emitter -> {
try (DatagramSocket socket = new DatagramSocket()) {
socket.setSoTimeout(TIMEOUT);
socket.send(sendPacket);
while (true) {
socket.receive(receivePacket);
emitter.next(receivePacket.getData());
}
} catch (SocketTimeoutException e) {
emitter.complete();
} catch (IOException e) {
emitter.error(e);
}
})
.map(mapper -> new String(receivePacket.getData(), 0, receivePacket.getLength()))

javax.net.ssl.sslpeerunverifiedexception no peer certificate Error In lifelogApi

We are getting SSL peer unverified error while fetching the access token from Lifelog api. I am able to get the authcode, but when i am trying to get access token, it is giving me SSL peer error. It works fine with few device, but most of the device it is giving SSL error.
private void getAccessToken(final String authCode)
{
final String finalUrl = String.format("https://platform.lifelog.sonymobile.com/oauth/2/token?client_id=%s&client_secret=%s&code=%s",CLIENT_ID,CLIENT_SECRET,authCode);
Thread networkThread = new Thread(new Runnable() {
public void run() {
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(finalUrl);
// Add your data
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("client_id", CLIENT_ID));
nameValuePairs.add(new BasicNameValuePair("client_secret", CLIENT_SECRET));
nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));
nameValuePairs.add(new BasicNameValuePair("code", authCode));
AbstractHttpEntity ent=new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8);
ent.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
post.setEntity(ent);
// Execute HTTP Post Request
HttpResponse response =null;
try {
response = client.execute(post);
Log.d("Response:" , response.toString());
} catch (IOException e) {
e.printStackTrace();
}
String dataObject = response.toString();
JSONObject obj;
if(dataObject != null) {
obj = null;
try {
String json_string = EntityUtils.toString(response.getEntity());
// displayToast(json_string);
obj = new JSONObject(json_string);
SharedPreferences prefs =getSharedPreferences("Myprefs", Context.MODE_PRIVATE);
prefs.edit().putString("Access_token", obj.getString("access_token"));
// prefs.edit().putString(AUTH_REFRESH_TOKEN, obj.getString(AUTH_REFRESH_TOKEN));
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
});
networkThread.start(); }
The problem may be with your use of HttpClient. It looks like Google has removed support for this call in Android 6.0.
http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
You should be able to use HttpsURLConnection instead of Httpclient to access the Lifelog Web Service.
I'm using google-oauth-client, I was able to use on Android 5.x with this initialization for
import com.google.api.client.http.HttpTransport;
private void initializeSocketFactory() {
if (Build.VERSION.SDK_INT >= 23) {
HTTP_TRANSPORT = new NetHttpTransport();
} else {
//Android 5 and bellow needs this SSL Socket factory initialization
try {
SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, null, null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
NetHttpTransport.Builder netTransportBuilder = new NetHttpTransport.Builder();
netTransportBuilder.setSslSocketFactory(socketFactory);
HTTP_TRANSPORT = netTransportBuilder.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Log.e(LOG_TAG, "Problem instantiating cipher for ssl socket", e);
}
}
}
You use HTTP_TRANSPORT to instantiate:
import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;

TCP Server configuration in Mule - writing into client socket

I am trying to create a mule flow with a TCP inbound endpoint which is a TCP server that listens to a port. When a successful client connection is identified, before receiving any request from the client, I need to write a message into the socket (which lets the client know that I am listening), only after which the client sends me further requests. This is how I do it with a sample java program :
import java.net.*;
import java.io.*;
public class TCPServer
{
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4445);
}
catch (IOException e)
{
System.err.println("Could not listen on port: 4445.");
System.exit(1);
}
Socket clientSocket = null;
System.out.println ("Waiting for connection.....");
try {
clientSocket = serverSocket.accept();
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
System.out.println ("Connection successful");
System.out.println ("Sending output message - .....");
//Sending a message to the client to indicate that the server is active
PrintStream pingStream = new PrintStream(clientSocket.getOutputStream());
pingStream.print("Server listening");
pingStream.flush();
//Now start listening for messages
System.out.println ("Waiting for incoming message - .....");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
{
System.out.println ("Server: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
}
I have tried to use Mule's TCP inbound endpoint as a server, but I am not able to see how I can identify a successful connection from the client, inorder to trigger the outbound message. The flow gets triggered only when a message is sent across from the client. Is there a way I can extend the functionality of the Mule TCP connector and have a listener which could do the above requirement?
Based on the answer provided, this is how I implemented this -
public class TCPMuleOut extends TcpMessageReceiver {
boolean InitConnection = false;
Socket clientSocket = null;
public TCPMuleOut(Connector connector, FlowConstruct flowConstruct,
InboundEndpoint endpoint) throws CreateException {
super(connector, flowConstruct, endpoint);
}
protected Work createWork(Socket socket) throws IOException {
return new MyTcpWorker(socket, this);
}
protected class MyTcpWorker extends TcpMessageReceiver.TcpWorker {
public MyTcpWorker(Socket socket, AbstractMessageReceiver receiver)
throws IOException {
super(socket, receiver);
// TODO Auto-generated constructor stub
}
#Override
protected Object getNextMessage(Object resource) throws Exception {
if (InitConnection == false) {
clientSocket = this.socket;
logger.debug("Sending logon message");
PrintStream pingStream = new PrintStream(
clientSocket.getOutputStream());
pingStream.print("Log on message");
pingStream.flush();
InitConnection = true;
}
long keepAliveTimeout = ((TcpConnector) connector)
.getKeepAliveTimeout();
Object readMsg = null;
try {
// Create a monitor if expiry was set
if (keepAliveTimeout > 0) {
((TcpConnector) connector).getKeepAliveMonitor()
.addExpirable(keepAliveTimeout,
TimeUnit.MILLISECONDS, this);
}
readMsg = protocol.read(dataIn);
// There was some action so we can clear the monitor
((TcpConnector) connector).getKeepAliveMonitor()
.removeExpirable(this);
if (dataIn.isStreaming()) {
}
return readMsg;
} catch (SocketTimeoutException e) {
((TcpConnector) connector).getKeepAliveMonitor()
.removeExpirable(this);
System.out.println("Socket timeout");
} finally {
if (readMsg == null) {
// Protocols can return a null object, which means we're
// done
// reading messages for now and can mark the stream for
// closing later.
// Also, exceptions can be thrown, in which case we're done
// reading.
dataIn.close();
InitConnection = false;
logger.debug("Client closed");
}
}
return null;
}
}
}
And the TCP connector is as below:
<tcp:connector name="TCP" doc:name="TCP connector"
clientSoTimeout="100000" receiveBacklog="0" receiveBufferSize="0"
sendBufferSize="0" serverSoTimeout="100000" socketSoLinger="0"
validateConnections="true" keepAlive="true">
<receiver-threading-profile
maxThreadsActive="5" maxThreadsIdle="5" />
<reconnect-forever />
<service-overrides messageReceiver="TCPMuleOut" />
<tcp:direct-protocol payloadOnly="true" />
</tcp:connector>
What you're trying to do is a little difficult to accomplish but not impossible. The messages are received by the org.mule.transport.tcp.TcpMessageReceiver class, and this class always consumes the data in the input stream to create the message that injects in the flow.
However, you could extend that receiver and instruct the TCP module to use yours by adding a service-overrides tag in your flow's tcp connector (documented here) and replacing the messageReceiver element.
In your extended receiver you should change the TcpWorker.getNextMessage method in order to send the ack message before read from the input stream.
HTH, Marcos.

SSL Server in Java - javax.net.ssl.SSLException

I am trying to create a server using SSL but I keep getting the following error:
"Server aborted:javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled."
I am not sure if I am creating the certificates correctly. Here is my code.
I am converting an old TCP Server to an SSL Server
// SSL Server
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocketFactory;
public class SSL_Server {
public static void main(String[] args) {
int port = 2018;
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = null;
System.out.println("SSL_Server started");
System.setProperty("javax.net.ssl.keyStore","mySrvKeystore");
System.setProperty("javax.net.ssl.keyStorePassword","123456");
final ExecutorService threadPool = Executors.newCachedThreadPool();
try {
ssocket = ssocketFactory.createServerSocket(port);
InetAddress myIP =InetAddress.getLocalHost();
System.out.println(myIP.getHostAddress());
while(true){
Socket aClient = ssocket.accept();
//create a new thread for every client
threadPool.submit(new SSL_ClientHandler(aClient));
}
}
catch(Exception e) {
System.err.println("Server aborted:" + e);
} finally {
try{
ssocket.close();
} catch (Exception e){
System.err.println("could not close connection properly" + e);
}
}
System.out.println("connection was closed successfully");
}
}
System.setProperty("javax.net.ssl. keyStore","mySrvKeystore"); System.setProperty("javax.net.ssl. keyStorePassword","123456");
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = null;
System.out.println("SSL_Server started");
You should set the properties that configure the default SSLContext (and thus the default SSLServerSocketFactory) before getting it, since it will configure it then.
System.setProperty("javax.net.ssl.keyStore","mySrvKeystore");
System.setProperty("javax.net.ssl.keyStorePassword","123456");
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = null;
System.out.println("SSL_Server started");

How can I use WCF instead of manual C# using tcplistenr?

I have the following code and was wondering if there is a benefit to moving this to WCF?
Basically, I am listening for smtp messages over some port and use thread pooling to parse each tcp connection asynchronously.
static void Main(string[] args)
{
try
{
TcpListener listener = new TcpListener(IPAddress.Any, 8000);
TcpClient client;
listener.Start();
while (true) // Add your exit flag here
{
client = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ThreadProc, client);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}//Main
private static void ThreadProc(object obj)
{
var client = (TcpClient)obj;
// Do your work here...
NetworkStream ns = client.GetStream();
using (StreamWriter writer = new StreamWriter(ns))
{
writer.WriteLine("220 SMTP server ready.");
writer.Flush();
using (StreamReader reader = new StreamReader(ns))
{
//parse + persist smtp message here...
}
}
}//ThreadProc