Run MySQL query over multiple SSH tunnels? - ruby

I have a situation somewhat similar to "How to create a ssh tunnel in ruby and then connect to mysql server on the remote host."
From my local machine, I want to run a query against a production MySQL database host.
My local machine cannot directly connect to the database host. However, if I SSH to a gateway machine, I can run the MySQL client and connect to the database host.
I'm trying to figure out how to programmatically to run a query from my machine that is forwarded to the gateway machine, which forwards it to the database server, and have results returned. Basically I want to have LOCAL => GATEWAY => DB_HOST forwarding.
I have a hacky solution that runs ssh.exec and MySQL on the command line, shown below, but, I'm trying to find a way that does port forwarding twice.
I tried, but haven't been successful so far.
require 'rubygems'
require 'mysql2'
require 'net/ssh/gateway'
gateway = Net::SSH::Gateway.new(
$gateway_host, $gateway_user,:password => $gateway_pass)
# This works
ssh = gateway.ssh($db_host, $db_login_user)
data = ssh.exec!("mysql -u#{$db_user} -p#{$db_pass} #{$db_name} -e '#{$sql_query}'")
puts "#{data.class} is the class type"
puts data
# Want to do something like this with port forwarding
# client = Mysql2::Client.new(:host => $db_host,
# :username => $db_user,
# :password => $db_pass,
# :database => $db_name,
# :port => port)
# results = client.query($sql_query)
puts "end stuff"
ssh.close
Any suggestions?

Your diagram lays it out fairly well, you would need a tunnel from the Gateway to the Db_Host; and a second tunnel from your local machine to the gateway. The two tunnels would effectively connect your local machine to the db_host by way of the gateway.
Here's a reference specific to tunneling MySQL over SSH

Related

Cannot connect from local machine to TCP server on AWS EC2 (Ubuntu)

I've coded up a basic TCP server/client, taking code from the first example on https://docs.python.org/3/library/socket.html#example
# Echo server program
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
# Echo client program
import socket
HOST = '1.2.3.4' # The remote host (I change this with my box's IP)
PORT = 50007 # The same port as used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
NOTE: I'm using my actual EC2 IP not 1.2.3.4
If I run the client on my local machine and the server on a remote box (hosted by vultr) it works.
But if host the server on an AWS EC2 instance, it doesn't.
I've gone into the Security Group for the EC2 instance, and added inbound+outbound "Custom TCP+UDP" rules. I've tried allowing the specific port the server is using, as well as putting 0-65535.
If I run a client on the same EC2 instance, that works.
I can't think what else to try.
Is anyone able to get this working on EC2?
I was using my AMI's private IP (which I use to ssh into the box).
I needed to use the PUBLIC IP.
It seems on vultr they are the same, which is why it worked.

How to proxy net-sftp?

I'm using net-sftp which relies on the net-ssh gem.
I'm trying to connect to a remote log service via SFTP, and it requires IP whitelisting. All my current servers have dynamic IPs.
I'm trying to set up a static, secure, proxy server in Google Cloud. I don't really understand all the differences between all the types of proxying, but net-ssh appears to support...
socks4
socks5
'jump' proxy
I looked into setting up a socks5 proxy with Dante but it appears a bit overkill just to relay the SFTP connection through it, not to mention I think it sends passwords in plain text.
How would I go about proxying net-sftp through some server in the easiest way?
The easiest way would be to setup a Jump-host server that can reach the target servers and then connecting to the target server by letting the Jump-host server proxy your connection through.
SSH makes it trivially easy:
ssh -J user#jump-host myuser#target-host
In your .ssh/config you can do the following:
### First jump-host. Directly reachable
Host jump-host
HostName jum-phost.example.org
### Host to jump to via jump-host.example.org
Host target-host
HostName target-host.example.org
ProxyJump jump-host
This will allow you to use net-ssh as usual. If you dont want to change the config file then you will have to use 'net/ssh/proxy/jump':
require 'net/ssh/proxy/jump'
proxy = Net::SSH::Proxy::Jump.new('user#proxy')
Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
...
end
See this article for more info on Jump Hosts.

Remote Redis Server from Resque Standalone

I want to run Resque workers on different servers, getting jobs from one Redis server. I know how to configure it in a Rails application, but the problem is I am using standalone Resque (https://github.com/dcestari/resque-standalone-sample) on every Server.
So my question is, how can I do this without installing a Rails application and is it possible?
Thank you!
You'll need to tell Resque where Redis lives:
Resque.configure do |config|
# Set the redis connection. Takes any of:
# String - a redis url string (e.g., 'redis://host:port')
# String - 'hostname:port[:db][/namespace]'
# Redis - a redis connection that will be namespaced :resque
# Redis::Namespace - a namespaced redis connection that will be used as-is
# Redis::Distributed - a distributed redis connection that will be used as-is
# Hash - a redis connection hash (e.g. {:host => 'localhost', :port => 6379, :db => 0})
config.redis = 'redis://someserverip:port:db/namespace'
end

Ruby TCPServer always delay on dns reverse lookup? - how to disable?

I created a TCPServer with ruby gserver.
Everytime I connect remotly to the server, it takes 2-4 seconds until connection is established.
This is only happen if I connect from remote machine.
Connection from same machine has running the service will send immidiate response.
For the connection on same machine there is no difference if I connect via localhost or via the machines ip.
I think delay depends on reverse lookup but can not localize why.
in gserver.rb it is line 263
client = #tcpServer.accept
Here the delay occurs, I do not know what is in this method.
I added all machines which are used during tests to the local hosts file. But that changed nothing.
Same happens when using Webrick, I tried to set also
BasicSocket.do_not_reverse_lookup = true
as well as direct on the resulting server socket
Socket.do_not_reverse_lookup = true
as well as on client connection socket
client.do_not_reverse_lookup = true
But that also changed nothing on delay.
Whenever connection is established, the values of remote_host and remote_ip are resolved and as defined in hosts file.
I tried that running ruby 2.2.1 on ubuntu 14.04 as well as ruby 1.9.3 running debian wheezy.
Same behavior - (long) delay on connecting service.
Q: How to fix that / disable lookup on TCPServer?
The problem depends on my client machine where I run on MAC OSX Mav.
The used telnet client tries to open IPv6 connection and afterwards IPv4.
To solve the delay, just open connection with
telnet -4 my-server 3333
I have build a small connect echo servive where you can check resolves and timings.
If you change NO_REVERSE_LOOKUP you will get IPs or ADDRESSes and if not resolveable, different response times.
require 'socket'
NO_REVERSE_LOOKUP = true
CONNECT_PORT = 3333
puts "#{Time.now} Starting service on port: #{CONNECT_PORT}"
# the full hell - just to test if anything meets what we want
TCPServer.do_not_reverse_lookup = NO_REVERSE_LOOKUP
BasicSocket.do_not_reverse_lookup = NO_REVERSE_LOOKUP
Socket.do_not_reverse_lookup = NO_REVERSE_LOOKUP
srv = TCPServer.open(CONNECT_PORT)
puts "#{Time.now} Waiting for client"
client = srv.accept
puts "#{Time.now} Client connected"
client.do_not_reverse_lookup = NO_REVERSE_LOOKUP
client.print "Hello connected\n"
# in case that we disabled reverse lookup, we should only receive IP Adresses
puts "#{Time.now} Getting server address infos"
puts "SERVER INFO:"
puts NO_REVERSE_LOOKUP ? client.addr(:numeric) : client.addr(:hostname)
puts ""
puts "#{Time.now} Getting remote client infos"
puts "REMOTE INFO:"
puts NO_REVERSE_LOOKUP ? client.peeraddr(:numeric) : client.peeraddr(:hostname)
###
puts "#{Time.now} Closing connection"
client.close
puts "#{Time.now} End"
Thanks to drbrain from #ruby-lang irc for pointing me to the IPv6 problem.

Net::SSH forward not working

I want to forward a port via Net::SSH like this:
ssh = Net::SSH.start('host', 'user', config: true)
ssh.forward.local(3333, 'localhost', 80)
ssh.loop
which to my understanding translates to the equivalent of:
ssh user#host -L 3333:localhost:80
With the command line version I can send an HTTP request to localhost:3333 and get an answer from localhost:80 on the remote host. With the Ruby version I don't get any answer.
Any ideas why?
Edit:
I tried net-ssh-gateway and it works. Looking at its code, I can't really see what's different there in terms of what it does to establish the connection.

Resources