MQTT TLS session resumption in C - c

I'm using the Eclipse Paho MQTT C client to connect to a mosquitto broker with TLS using openssl. This is part of my code:
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_SSLOptions sslOptions = MQTTClient_SSLOptions_initializer;
MQTTClient_deliveryToken token;
int rc;
MQTTClient_create(&client, ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
/* TLS */
sslOptions.enableServerCertAuth = 0;
sslOptions.trustStore = "ca_rsp.crt";
conn_opts.ssl = &sslOptions;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
Actually every time I reconnect to the broker, the client make a full handshake. I would like to use the TLS session resumption to reduce the overhead. I've search around the web but I haven't found any example of how o implement that in a simple way.
Any suggestion?
Thanks

This came up recently on the mosquitto dev mailing list here https://dev.eclipse.org/mhonarc/lists/mosquitto-dev/msg01606.html
The following excerpt seams to imply it may not be possible just yet with the code as it is.
How can I use Mosquitto / OpenSSL C API to leverage session tickets in an
MQTT C client ?
Not at the moment, this needs code changes that are a bit more
involved - it looks like we need to use SSL_set_session() to apply a
saved session to your client and SSL_CTX_sess_set_new_cb() to save the
session out.
Is there any way I could persist session tickets on the clients, so they
would remain valid across reboot ?
With the above changes, yes.

Make conn_opts.cleansession = 0;
Disabling the cleansession flag in PAHO-client programs enables session resumption.
I have already verified it with wireshark.
With session Resumption, 1st packet transmission
We can see 4 times communication between server and client in 1 image and even certificates are transferred.
With session Resumption ,screenshot taken for 2nd packet transmission
Observe both images carefully , there is only 3 times communication between server and client in2 image, hence the server negotiates not to perform full handshake.
Session resumption time limit is 7200 seconds.
But setting the cleansession flag to 1 will always perform full handshake which means no session resumption.

I feel it was a good decision taken by PAHO people who made clean session flag linked with session resumption because mosquitto client provided in github lacks this inbuilt feature of session resumption.
Go through the specification of MQTT v3.1.1
Or refer MQTT specification in their website

Related

LwIP Clilent can't establish a connection

I want to connect two F746ZG boards so that they can communicate via TCP. I am using the STM implementation of LwIP with the netconn API. The IP address is supplied via DHCP, but it is always the same address. Also, the address matches the expected value. The problem I am facing is that the client seemingly can't establish a connection. I am binding the connection to port 8880. Since I ran into this issue, I have written a debug client that should just periodically send a predefined message to a server. Here is the code for the client:
static void tcpecho_client_thread(void const *arg)
{
struct netconn *xNetConn = NULL;
err_t bind_err, connect_err;
char* b_data = "OK"; // Data to be sent
uint16_t b_len = sizeof ( b_data );
IP4_ADDR(&local_ip, IP_ADDR0_CLIENT, IP_ADDR1_CLIENT, IP_ADDR2_CLIENT, IP_ADDR3_CLIENT);
IP4_ADDR(&pc_ip, IP_ADDR0_PC, IP_ADDR0_PC, IP_ADDR2_PC, IP_ADDR3_PC);
xNetConn = netconn_new ( NETCONN_TCP );
if (xNetConn != NULL){
bind_err = netconn_bind ( xNetConn, &local_ip, TCP_PORT_NETCONN );
if(bind_err == ERR_OK){
// Try to connect to server
for(;;){
connect_err = netconn_connect ( xNetConn, &pc_ip, TCP_PORT_NETCONN);
if (connect_err == ERR_OK){
// We are connected
while(1){
BSP_LED_On(LED1);
netconn_write(xNetConn, b_data, b_len, NETCONN_COPY);
vTaskDelay(1000); // To see the result easily in Comm Operator
}
}
}
}else{
// Failed to bind the connection
BSP_LED_On(LED3);
}
}else{
// Failed to allocate a new connection
BSP_LED_On(LED3);
}
}
When I debug this, netconn_connect never manages to actually connect to something. Since I am able to ping the board and get a response, I am confused, what is going wrong here. I have tried to use Hercules to set up a TCP server on my PC so that the board can connect to that, but that also doesn't work. Using Wireshark, I can see the responses to my ping command coming in, but I don't see anything that would indicate the board trying to connect to my PC.
I have tested the corresponding server on the second board, but that runs fine. I can connect to it with Hercules and send data, so I doubt there is anything fundamentally wrong with the LwIP stack.
What I could guess is that I messed up the netconn_bind, I am not 100% sure what IP you are supposed to bind the connection to. The way it currently is, is how I read the documentation. For the server, I have bound it to IP_ADDR_ANY. Besides that, my implementation mostly matches with the examples you can find online (e.g. LwIP Wiki).
I have figured out the problem. After I delete the netconn_bind call, everything works fine for me.

Camel SMPP custom SMS port

I'm currently trying to send a SMS with Camel SMPP but I'm failing on sending it to a specific destination port.
Actually nothing port related happens on my SMPP server.
Here is my current code in my Processor :
exchange.getOut().setHeader("CamelSmppAlphabet", Alphabet.ALPHA_8_BIT.value());
exchange.getOut().setHeader("CamelSmppDataCoding", 4);
short destport = 5000;
short srcport = 0;
Map<java.lang.Short, java.lang.Short> optParameters = new HashMap<java.lang.Short, java.lang.Short>();
optParameters.put(OptionalParameter.Tag.DESTINATION_PORT.code(), destport);
optParameters.put(OptionalParameter.Tag.SOURCE_PORT.code(), srcport);
exchange.getOut().setHeader("CamelSmppOptionalParameter", optParameters);
Am I doing something wrong ? If so how am I supposed to send my message to a specific destination Port ?
Thanks for your help

C HTTP Server & OpenSSL - Works fine for HTTP - Multiple/rapid/concurrent connections being dropped using HTTPS

I'm writing an HTTP server in C using sockets. It can listen on multiple ports and works on a 1-thread-per-port basis to run listening loops and each loop spawns another thread to deliver a response
The code works perfectly when delivering standard HTTP responses. I have it set up to respond with an HTML page with JavaScript code that just refreshes the browser repeatedly in order to stress test the server. I've tested this with my computer running as the server and 4 other devices spamming it with requests at the same time.
No crashes, no dropped connections and no memory leaks. CPU usage never jumps beyond 5% running on a 2.0 GHz Intel Core 2 Duo in HTTP mode with 4 devices spamming requests.
I just added OpenSSL yesterday so it can deliver secure responses over HTTPS. That went fairly smoothly as it seems that all I had to do with replace some standard socket calls with their OSSL counterparts for secure mode (based on the solution to this question: Turn a simple socket into an SSL socket).
There is one SSL context and SSL struct per connection. It does work but not very reliably. Again, each response happens on its own thread but multiple/rapid/concurrent requests in secure mode are getting dropped seemingly at random, though there are still no crashes or memory leaks in my code.
When a connection is dropped the browser will either say its waiting for a response that never happens (Chrome) or just says the connection was reset (Firefox).
For reference, here is the updated connection creation and closing code.
Connection creation code (main part of the listening loop):
// Note: sslCtx and sslConnection exist
// elsewhere in memory allocated specifically
// for each connection.
struct sockaddr_in clientAddr; // memset-ed to 0 before accept
int clientAddrLength = sizeof(clientAddr);
...
int clientSocketHandle = accept(serverSocketHandle, (struct sockaddr *)&clientAddr, &clientAddrLength);
...
if (useSSL)
{
int use_cert, use_privateKey, accept_result;
sslCtx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_options(sslCtx, SSL_OP_SINGLE_DH_USE);
use_cert = SSL_CTX_use_certificate_file(sslCtx, sslCertificatePath , SSL_FILETYPE_PEM);
use_privateKey = SSL_CTX_use_PrivateKey_file(sslCtx, sslCertificatePath , SSL_FILETYPE_PEM);
sslConnection = SSL_new(sslCtx);
SSL_set_fd(sslConnection, clientSocketHandle);
accept_result = SSL_accept(sslConnection);
}
... // Do other things and spawn request handling thread
Connection closing code:
int recvResult = 0;
if (!useSSL)
{
shutdown(clientSocketHandle, SHUT_WR);
while (TRUE)
{
recvResult = recv(clientSocketHandle, NULL, 0, 0);
if (recvResult <= 0) break;
}
}
else
{
SSL_shutdown(sslConnection);
while (TRUE)
{
recvResult = SSL_read(sslConnection, NULL, 0);
if (recvResult <= 0) break;
}
SSL_free(sslConnection);
SSL_CTX_free(sslCtx);
}
closesocket(clientSocketHandle);
Again, this works 100% perfect for HTTP responses. What could be going wrong for HTTPS responses?
Update
I've updated the code with OpenSSL callbacks for mutli-threaded environments and the server is slightly more reliable using code from an answer to this question: OpenSSL and multi-threads.
I wrote a small command line program to spam the server with HTTPS requests and it is not dropping any connections with 5 multiple instances of it running at the same time. Multiple instances of Firefox also appear not to be dropping any connections.
What is interesting however is that connections are still being dropped with modern WebKit-based browsers. Chrome starts to drop connections at under 30 seconds of spamming, Safari on an iPhone 4 (iOS 5.1) rarely makes it past 3 refreshes before saying the connection was lost, but Safari on an iPad 2 (iOS 5.0) seems to cope the longest but ultimately ends up dropping connections as well.
You should call SSL_accept() in your request handling thread. This will allow your listening thread to process the TCP accept/listen queue more quickly, and reduce the chance of new connections getting a RESET from the TCP stack because of a full accept/listen queue.
SSL handshake is compute intensive. I would guess that your spammer is probably not using SSL session cache, so this causes your server to use the maximum amount of CPU. This will cause it to be CPU starved in regards to servicing the other connections, or new incoming connections.

WMQ Security Exit UserID/PWD passing issue

We are currently implementing a security exit for our SVRCONN channels. This exit will authenticate to our LDAP(AD or UNIX). Our current implementation of the exit is working for only connections coming from MQ EXPLORER.
When we write a code to connect and pass the userID/PWD, the security exit is picking up the user account login on the client machine.
Here is a snippet on how we connect to MQ
Code:
MQCNO ConnectOptions = {MQCNO_DEFAULT};
MQCD ClientConn = {MQCD_CLIENT_CONN_DEFAULT};
MQCSP mqCSP = {MQCSP_DEFAULT};
MQHCONN HConn;
MQLONG CompCode;
MQLONG Reason;
char QMName[MQ_Q_MGR_NAME_LENGTH+1]="QMGRNAME";
char channelName[MQ_CHANNEL_NAME_LENGTH+1]="MY_CHANNEL";
char hostname[1024]="MQSERVER(PORT)";
char UserId[32+1]="MyID";
char Password[32+1]="MyPWD";
strncpy(ClientConn.ConnectionName, hostname, MQ_CONN_NAME_LENGTH);
strncpy(ClientConn.ChannelName, channelName, MQ_CHANNEL_NAME_LENGTH);
mqCSP.AuthenticationType = MQCSP_AUTH_USER_ID_AND_PWD;
mqCSP.Version = MQCSP_VERSION_1;
mqCSP.CSPUserIdPtr = &UserId;
mqCSP.CSPUserIdOffset = 0;
mqCSP.CSPUserIdLength = strlen(UserId);
mqCSP.CSPPasswordPtr = &Password;
mqCSP.CSPPasswordOffset = 0;
mqCSP.CSPPasswordLength = strlen(Password);
ConnectOptions.SecurityParmsPtr = &mqCSP;
ConnectOptions.SecurityParmsOffset = 0;
ConnectOptions.ClientConnPtr = &ClientConn;
ConnectOptions.Version = MQCNO_VERSION_5;
MQCONNX (QMName, &ConnectOptions, &HConn, &CompCode, &Reason);
Then we use this code to retrieve the userID/PWD on the security exit.
Code:
memset (User, 0, pChDef->LongRemoteUserIdLength);
memset (Pass, 0, MQ_PASSWORD_LENGTH);
MakeCString(User,pChDef->LongRemoteUserIdPtr,pChDef->LongRemoteUserIdLength);
MakeCString(Pass,pChDef->RemotePassword,MQ_PASSWORD_LENGTH);
MQ Server->7.1.0.2
Why in the world would you re-invent the wheel when there is a cheap product that does authentication against an LDAP server? If you spent more than a day programming this, you instead could have purchased a license for MQ Authenticate Security Exit and done something else.
MQ only flows the password in plain text. Very easy to grab that password if you are familiar with MQ or just use WireShark since it knows/understands MQ protocol.
MQ uses 2 different styles of flowing the UserID and Password between a client and server: "old" and "new" style. Different platforms support different styles. Some support both directly and some support both indirectly and some platforms do a conversion and flow both at the same time (very weird!).
It is fine if all of your applications can be rebuilt to use MQCONNX by what if the application cannot be rebuilt? Or the application team does not want to do it or the source code is lost. What about 3rd party applications that do not support MQCONNX? What are you going to do?
What about MQ JNDI or CCDT (Client Channel Table Definitions) or the new "MQClient.ini" file? Have you thought about how you are going to handle these implementations?
You are going to easily spend 6 months (i.e. 1000 hours) building a working prototype that covers some of the issues I have highlighted. You are in for a world of hurt. I know, I've been there done that.

Refresh multicast group membership

I have several embedded machines listening and streaming rtp audio data to a multicast group. They are connected to a smart managed switch (Netgear GS108Ev2) which does basic igmp snooping and multicast filtering on its ports, so that the rest of my (W)LAN doesn't get flooded.
At start everything works fine for about 500-520 seconds. After that, they don't receive any more data until they leave and join the group again. I guess the switch is "forgetting" about the join after a timeout.
Is there any way to refresh the group membership, i.e. letting the switch know, that there ist still someone listening, without losing packets?
System info:
Arch: blackfin
# cat /proc/version
Linux version 2.6.28.10-ADI-2009R1-uCBF54x-EMM
(gcc version 4.3.3 (ADI) ) #158 PREEMPT Tue Jun 5 20:05:42 CEST 2012
This is the way multicast / the IGMP protocol works. A client has to join the group periodically by sending a Membership Report or it will be assumed that he has left the group after some short timeout. However, those reports are usually sent only when receiving a Membership Query from the local multicast router. Either your clients don't receive the query or don't respond with a report.
Try to use a tool like wireshark in order to see which IGMP packets are sent through your network.
You need an IGMP querier to send the Membership Queries, as was already explained by scai.
If you can't configure your router to do that, you can use one of your computers. Seeing how running a full multicast routing daemon would be overkill (and I've never done that), I suggest you try to abuse igmpproxy.
First create a dummy upstream interface (this is not persistent!):
ip tap add dev tap6 mode tap
Write igmpproxy.conf:
# Dummy upstream interface.
phyint tap6 upstream ratelimit 0 threshold 1
# Local interface.
phyint eth0 downstream ratelimit 0 threshold 1
# Explicitly disable any other interfaces (yes, it sucks).
phyint NAME disabled
...
Finally start igmpproxy (as root):
igmpproxy -v /path/to/igmpproxy.conf
If your embedded devices are running linux, you need to turn off the reverse packet filter on them or they won't respond to group membership queries. In that case the upstream switch will assume there is no-one listening to that multicast and switch it off.
I had same problem, multicast on wifi was lost after 260 seconds, I solved it with my application by adding AddSourceMembership on socket.
private void StartListner(IPAddress sourceIp, IPAddress multicastGroupIp, IPAddress localIp, int port)
{
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localEndpoint = new IPEndPoint(localIp, port);
socket.Bind(localEndpoint);
byte[] membershipAddresses = new byte[12]; // 3 IPs * 4 bytes (IPv4)
Buffer.BlockCopy(multicastGroupIp.GetAddressBytes(), 0, membershipAddresses, 0, 4);
Buffer.BlockCopy(sourceIp.GetAddressBytes(), 0, membershipAddresses, 4, 4);
Buffer.BlockCopy(localIp.GetAddressBytes(), 0, membershipAddresses, 8, 4);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddSourceMembership, membershipAddresses);
try
{
byte[] b = new byte[1024 * 2];
int length = socket.Receive(b);
}
catch { }
}
catch (Exception ex)
{
logger.Error("Exception: " + ex);
}
}

Resources