Skip to content

Instantly share code, notes, and snippets.

@rennex
Last active March 13, 2022 22:26
Show Gist options
  • Save rennex/2658d08f6991889d688a91bfca384852 to your computer and use it in GitHub Desktop.
Save rennex/2658d08f6991889d688a91bfca384852 to your computer and use it in GitHub Desktop.
Line-oriented bouncer between TLS server and Unix socket
require "socket"
require "openssl"
unless ARGV.size == 3
puts "Usage: #$0 <serverhost> <serverport> <listensocketpath>"
exit
end
class NanoBouncer
def initialize(args)
@host, @port, @path = args
end
def log(txt)
STDERR.puts "[#{Time.now}] #{txt}"
end
def run
@sock = TCPSocket.new(@host, @port.to_i)
File.delete(@path) if File.socket?(@path)
serv = UNIXServer.new(@path)
unless ENV["NO_TLS"]
ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
sslsock = OpenSSL::SSL::SSLSocket.new(@sock, ctx)
sslsock.sync_close = true
sslsock.connect
@sock = sslsock
end
log "Connected, waiting for clients..."
thread = nil
loop do
s = serv.accept
if thread
log "Disconnecting old client because of a new connection"
thread.kill rescue nil
@t.kill rescue nil
end
thread = Thread.new { serve_client(s) }
end
end
def serve_client(client)
remote = client.remote_address.inspect_sockaddr.inspect
log "Serving new client #{remote}"
@t = Thread.new { loop { client.puts(@sock.gets) } }
loop { @sock.puts(client.gets) }
@t.join
rescue => e
log "Error serving client #{remote}: #{e.class}: #{e}"
@t.kill rescue nil
end
end
NanoBouncer.new(ARGV).run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment