Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Using Net::SSH2 with DBI

by diyaz (Beadle)
on Jan 19, 2016 at 19:08 UTC ( [id://1153108]=perlquestion: print w/replies, xml ) Need Help??

diyaz has asked for the wisdom of the Perl Monks concerning the following question:

How can I create an SSH connection while using DBI to connect to an SQL database? Currently I edit my database through HeidiSQL which lets me SSH then TCP/IP to the SQL server, but now I need to start doing some automated stuff with perl.

When I use `Net::SSH2` I can connect no problem, but then when I use DBI I believe it does not go through the SSH tunnel as it gives me a login error.

Do I have to basically run all my DBI commands through a SSH handle? or worse, run them manually through a SSH shell?

Replies are listed 'Best First'.
Re: Using Net::SSH2 with DBI
by Corion (Patriarch) on Jan 19, 2016 at 19:21 UTC

    Depending on how your network setup actually is, most likely the sanest approach is to create an SSH tunnel and then connect DBI to the local end of that tunnel.

    From a quick look through Net::SSH2, it doesn't seem that it readily supports setting up a tunnel. I think you can use the ->tcpip method to forward packets yourself, but that feels like far too much programming.

    Personally, I would simply launch ssh -L local:remote:remoteport or however one sets up an ssh tunnel from the command line, and then direct DBI / DBD::mysql to connect to the local port. Most likely this is what HeidiSQL does as well.

      After a quick search, this is almost exactly what you stated in this post in this thread nearly three years ago :)

      From what I can tell, not much has changed.

        I would really like there to be a nicer/more integrated solution, but I think with libssh2, you have to do the packet forwarding yourself, which means that you will need at least threads or some very clever asynchronous framework to run both the forwarding and DBI queries. And spawning an external process is much simpler than that, at least if you have the ssh executable available.

      thanks i decided to install cygwin and open ssh in shell with perl. hopefully that will work. UPDATE: I apparently do not know how to use "open" to open an SSH connection. I tried:
      open(SSH, "ssh user\@host.com");
      as a simple example, and I have tested that syntax will work in Cygwin except it will prompt for password. I don't think I understood what you had previously.

        I would either set up a passwordless keypair or use ssh-agent to store the password credentials.

Re: Using Net::SSH2 with DBI
by salva (Canon) on Jan 20, 2016 at 12:21 UTC
    I find shocking that it is still not possible to pass an already open socket to the DBD::mysql constructor!

    Because the right way to do connect to a remote DB through a SSH gateway would be to call socketpair, attach the command ssh $remote_host -W${db_host}:${db_port} to one side and then pass the other to the DBD::mysql.

      Here's some skeleton code to try. I haven't tested it much, but it seems to connect alright.

      #! /usr/bin/perl use strict; use warnings; use Socket; use POSIX; sub named_socket_spawn { my $code = shift; ref $code eq 'CODE' or return; my ($serv, $conn); socket($serv, AF_UNIX, SOCK_STREAM, PF_UNSPEC) || die "socket: $!"; my $sname = tmpnam(); bind($serv, sockaddr_un($sname)) || die "bind: $!"; listen($serv, 1) || die "listen: $!"; my $pid = fork() // die "fork: $!"; if ($pid) { close $serv; return $sname; } accept($conn, $serv) || warn "accept: $!"; unlink($sname) || warn "unlink: $!"; open STDIN, "<&", $conn; open STDOUT, ">&", $conn; close $serv; close $conn; exit $code->(); } use DBD::mysql; #my $sqlsock = named_socket_spawn(sub{exec "ssh host -W host:3306"}); my $sqlsock = named_socket_spawn(sub{ exec "nc localhost 3306" }); my $dsn = "DBI:mysql:database=test;mysql_socket=$sqlsock"; my $dbh = DBI->connect($dsn, "test", "hunter5");

      Hm. According to DBD::mysql, there's the mysql_socket specifier to pass the unix socket name. Does this not work?

      So basically, you'd need a small helper sub to handle the tedium of attaching a process to a socket

      my $unixname = named_sock_spawn(sub{ exec "ssh" }); sub named_sock_spawn { socket();bind();listen(); fork() and return $name; accept();dup();dup();$fun->(); }

      The perlipc has an example on unix-domain TCP. But are there any modules to provide named pipe utilities?

        This is only for a socket name unfortunately, not for an in-memory socket structure.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1153108]
Approved by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-19 13:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found