There's enough for everyone

गते गते पारगते पारसंगते बोधि स्वाहा गते गते पारगते पारसंगते बोधि स्वाहा

Puma for raw tcp with ssl

I stumbled on the fact that Puma has a raw tcp mode, also known as Lopez Express. This bypasses rack and provides access to the TCPSocket that’s just connected. Handy, because then puma can handle all the threading etc, and I just get a tcp socket to talk non-http to the client. What!? No http?! Are you mad??

No!! Well, maybe a little…

In fact I need to receive data from a microcontroller board. It doesn’t have sufficient CPU and memory to have an http stack. So we have to use tcp. However, the person implementing it also wants to use ssl. But not http. Yeah, puzzles me too.

I couldn’t find much by way of documentation, so here’s how to do a server for that using Puma:

puma_tcp_ssl.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# for pry-breakpointing
#  workers 1
#  threads 1, 1
workers 3
threads 8,32

require 'openssl'

SSL_CONTEXT = OpenSSL::SSL::SSLContext.new.tap do |ctx|
  key_dir = "/etc/where/your/certs/are"
  ctx.cert = OpenSSL::X509::Certificate.new File.read "#{key_dir}/fairy_zikrit.pem"
  ctx.key = OpenSSL::PKey::RSA.new File.read "#{key_dir}/fairy_zikrit.key"
end

app do |params, raw_socket|
  params['log']["incoming tcp request from #{raw_socket.inspect}"]

  # set up the ssl connection
  socket = OpenSSL::SSL::SSLSocket.new raw_socket, SSL_CONTEXT
  socket.sync_close = true
  socket.accept
  params['log']["incoming ssl request from #{socket.inspect}"]

  # now handle the data
  while !socket.eof?
    line = socket.readline.chomp
    break if line.empty?

    socket.puts "you said #{line}"
  end
end

# raw tcp mode, so puma is just doing workers and threading
tcp_mode
port 8532

And now (obviously after gem install puma) you run it with

1
puma -C puma_tcp_ssl.rb

and you connect to it with

1
openssl s_client -CApath /etc/ssl/certs -connect localhost:3114

Provided your cert and key are correct and you have the CA root certificates in /etc/ssl/certs, that will also verify the cert. Now you say hello, press enter and the server should tell you what you said. And nobody else will know. Muahahaha!

As usual, please tell me if you find mistakes.

Comments