How to establish a SSL enabled TCP/IP Connection in Ruby - ruby

I need to establish a TCP connection with my server which has a SSL enabled port, that I need to access.
I need to send a XML file and get the response from the server.
Before the SSL was enabled, I was able to get the data from the server using the below mentioned code.
require 'socket'
myXML = 'test_xml'
host = 'myhost.com'
port = 12482
socket = TCPSocket.open(host,port) # Connect to server
socket.send(myXML, 0)
response = socket.recvfrom(port)
puts response
socket.close
Now I have a 'certi.pfx' with which I need to establish a connection, Send my_xml data and get the response. How can this be done.
I would also like to know if I have the 'pem' and 'key' file, how can I establish a connection, Send my_xml data and get the response.
Please help.

require 'socket'
require 'openssl'
myXML = 'my_sample_data'
host = 'my_host.com'
port = my_port
socket = TCPSocket.open(host,port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.cert = OpenSSL::X509::Certificate.new(File.open("certificate.crt"))
ssl_context.key = OpenSSL::PKey::RSA.new(File.open("certificate.key"))
ssl_context.ssl_version = :SSLv23
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
ssl_socket.puts(myXML)
while line = ssl_socket.gets
p line
end
ssl_socket.close

Like this:
sock = TCPSocket.new('hostname', 443)
ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
#socket = OpenSSL::SSL::SSLSocket.new(sock, ctx).tap do |socket|
socket.sync_close = true
socket.connect
end

Related

TCPSocket connection reset by peer

require 'socket'
socket = TCPSocket.open('stream-api.betfair.com', '443')
while line = socket.gets
puts line.chop
end
socket.close
I should receive something like {"op":"connection","connectionId":"002-230915140112-174"}
but I receive Connection reset by peer which
means the remote end would have sent a reset packet (RST) to kill the connection without an orderly shutdown (close). In that case you know it was the peer(client).
betfair included a nodejs example and also csharp/java examples
Any help is much appreciated. Thanks!
First thing, you should replace the string '443' by an integer :
TCPSocket.open('stream-api.betfair.com', 443)
Anyway, it seems to be related with the SSL negociation : the following Stackoverflow post gives a quick idea about what would work : How to establish a SSL enabled TCP/IP Connection in Ruby. Using this method, I works.
require 'socket'
require 'openssl'
host = 'stream-api.betfair.com'
port = 443
socket = TCPSocket.open(host,port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.ssl_version = :SSLv23
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
while line = ssl_socket.gets
p line
end
ssl_socket.close
Result :
"{\"op\":\"connection\",\"connectionId\":\"001-151118094105-259478\"}\r\n"
Dealing with SSL/TLS protected connection is sometime quite verbose with Ruby. In the example you gave, in NodeJS, the hint is the first line :
var tls = require('tls');

Ruby send and receive custom TCP packets using PacketFu

I have a server running on port 3000 and a simple ruby program that reads lines from the server
require 'socket'
require 'packetfu'
s = TCPSocket.open('localhost', 3000)
config = PacketFu::Config.new(:iface=> "wlan0").config
pkt = PacketFu::TCPPacket.new(:config => $config , :flavor => "Linux")
while line = s.gets
puts line.chop
end
s.close
Server
require 'socket'
server = TCPServer.open('localhost', 3000)
loop {
client = server.accept
client.close
}
I want to build a simple TCP packet using packetfu that sends a WAKE-UP call and receive ACK from the server. What changes should i make to build this packet and receive the response?

Network chat program!! (Need a little help)

I have been working on a small script that allows communication though the TCPsocket command. I am stuck on a small error in my code. For some reason after running it twice the it stops running the RX loop.
I also worry that while its waiting for me to enter something for the get statement, that it won't be looking for incoming messages...
Any help is greatly appreciated. Thanks in advance guys
require 'socket'
ip = 'localhost'
port = 18000
TX = Thread.new do
loop {
Serv = TCPSocket.open(ip, port)
message = gets.chomp()
Serv.write(message)
Serv.close
}
end
RX = Thread.new do
loop {
server = TCPServer.open(port)
client = server.accept
puts client.gets
}
end
RX
TX.join
You should initialize the server outside the loop. (And to avoid warnings, you should not reassign a constant name like Serv in a loop):
require 'socket'
ip = 'localhost'
port = 18000
TX = Thread.new do
loop {
conn = TCPSocket.open(ip, port)
message = gets.chomp()
conn.write(message)
conn.close
}
end
RX = Thread.new do
server = TCPServer.open(port)
loop {
client = server.accept
puts client.gets
}
end
TX.join
If you want to serve multiple clients simultaneously, take a hint from the second example at http://ruby-doc.org/stdlib-1.9.3/libdoc/socket/rdoc/TCPServer.html and use Thread.start(server.accept) { |client| ... }.

Ruby SSL Client

I've got a SSL Echo Server working fine when I tested with
gnutls-cli --starttls --port 9002 --insecure localhost
My SSL Echo server is as below:
#!/usr/bin/ruby
require 'socket';
require 'openssl';
certfile = 'privkey.pem';
host = "127.0.0.1"
port = 9002;
server = TCPServer.new( host, port );
# Establish an SSL context
sslContext = OpenSSL::SSL::SSLContext.new
sslContext.cert = OpenSSL::X509::Certificate.new(File.open( "myssl.cert.cert" ))
sslContext.key = OpenSSL::PKey::RSA.new(File.open( "myssl.cert.key" ))
# Create SSL server
sslServer = OpenSSL::SSL::SSLServer.new( server, sslContext );
# Don't expect an immidate SSL handshake upon connection.
sslServer.start_immediately = false;
sslSocket = sslServer.accept;
sslSocket.puts( "Toast.." );
# Server loop
while line = sslSocket.gets
line.chomp!;
if "STARTTLS" == line
# Starting TLS
sslSocket.accept;
end
sslSocket.puts( "Got '#{line}'" );
end
sslSocket.close;
My Client is however, not working (which I borrow somewhere in StackOverflow) as below:
#!/usr/bin/env ruby
require "socket"
require "thread"
require "openssl"
host = "127.0.0.1"
port = 9002
socket = TCPSocket.new(host, port)
expectedCert = OpenSSL::X509::Certificate.new(File.open("myssl.cert.cert"))
ssl = OpenSSL::SSL::SSLSocket.new(socket)
ssl.sync_close = true
ssl.connect
if ssl.peer_cert.to_s != expectedCert.to_s
stderrr.puts "Unexpected certificate"
exit(1)
end
Thread.new {
begin
while lineIn = ssl.gets
lineIn = lineIn.chomp
$stdout.puts lineIn
end
rescue
$stderr.puts "Error in input loop: " + $!
end
}
while (lineOut = $stdin.gets)
lineOut = lineOut.chomp
ssl.puts lineOut
end
Error I've got.
./sslclient.rb:13:in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol (OpenSSL::SSL::SSLError)
from ./sslclient.rb:13:in `<main>'
Why is there a error in ssl.connect? Did I miss anything?
On the server side you start with plain text, send a welcome message and expect a starttls command - only then you upgrade to TLS. But on the client side you immediatly try to upgrade to TLS after the TCP connect, e.g. without reading the server hello and without sending the starttls command.

Socksify and SSL for HTTPS request

For a project I need to make an HTTPS call through a Socks5 proxy so I can access the remote API of a customer.
The original code I'm using is this:
url = "/proxyValidate?service=#{migration_station_verification_url}&ticket=#{service_ticket}"
if Rails.env == 'development'
uri = URI.parse(soe_cas_url + url)
Net::HTTP.SOCKSProxy('127.0.0.1', 1080).start(uri.host, uri.port) do |http|
res = http.get(uri.path)
doc = Nokogiri::XML(res)
doc.remove_namespaces!
doc.xpath('//sessionId').first.content
end
else
http = Net::HTTP.new(soe_cas_url)
http.use_ssl = true
req = Net::HTTP::Get.new(url)
res = http.request(req)
doc = Nokogiri::XML(res)
doc.remove_namespaces!
doc.xpath('//sessionId').first.content
end
The goal is to use the proxy only in development environment. When I make the call using the proxy I receive the error:
wrong status line: "<!DOCTYPE
Googling this shows I need to set the use_ssl flag to true, which works outside the development cycle. When using the socksify there is no such mechanism. If I call this inside the do block, I receive an error that the session is already started. Calling it outside the block returns an exception that no such function exists.
Anyone can tell me how to run SSL/HTTPS through the socksify proxy?
EDIT:
I'm currently playing around with pure sockets to get what I want, using the following code:
socket = Socket::TCPSocket.open('127.0.0.1', 1080)
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
ssl_context.ca_file = File.join(Rails.root, 'ssl', 'cacert.pem')
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
request = "GET #{url} HTTP/1.1\r\nAccept: */*\r\nHost: #{soe_cas_url}"
ssl_socket.puts(request)
ssl_socket.puts("")
response = ""
while (line = ssl_socket.gets)
response << line
end
This however fails at the ssl_socket.connect with the following error:
ssl_connect syscall returned=5 errno=0 state=sslv2/v3 read server hello a
I've tried using self-signed certificates, no certificates etc but nothing seems to work. I do know the endpoint relies on self-signed certificates on staging environmnet.

Resources