I am developing a test app to understand how to do SSH tunnelling to connect to a MySQL Database in C++.
I am using the libssh2 library and I am using an example from https://www.libssh2.org/examples/direct_tcpip.html but I am not 100% sure whether or not this is the correct thing to use.
I've pretty much copied the example but when connecting to MySQL on my socket, MySQL throws:
Errro 2013 (HY000): Lost connection to mysql server at 'reading communication packet', system error: 0
When I connect to mysql using mysql -uroot -p -P2222 my app reads data on the channel using the following:
int len = libssh2_channel_read(channel, buf, sizeof(len));
and the buf contains SSH-2.0- and then this is written to the forwarding socket as follows:
wr = 0;
while (wr < len)
{
i = send(forward_socket, buf + wr, len - wr, 0);
if (i <= 0)
{
perror("write");
return EXIT_FAILURE;
}
wr += i;
}
As soon as the send is done, I instantly get the mysql error. I assume it is because I am sending SSH-2.0- to MySQL which MySQL isn't expecting so its closing the connection but I can't see what's wrong, and I can't find for certain whether or not libssh2 direct_tcpip is the correct thing to use.
Finally, managed to figure out what to do, with lots of trial and error and hair pulling managed it.
Using the example from https://www.libssh2.org/examples/direct_tcpip.html but I was setting the variables with the wrong value.
Basically, in the example it has
const char *remote_desthost = "localhost"; /* resolved by the server */
unsigned int remote_destport = 22;
Because of remote_destport in the example being 22, I thought this was the SSH connection details so I set this to be my SSH settings.
It turns out this is where the connection gets forwarded to from the SSH session so I changed it to be
const char *remote_desthost = "localhost"; /* resolved by the server */
unsigned int remote_destport = 3306;
So now I can run my app from my laptop, which connects to my SSH server for my web server and then on my laptop run in the command
mysql -uroot -p -P2222 and I connect to the database on my webserver through the SSH tunnel.
I think you have misunderstood what SSH Tunnelling is.
SSH Tunnelling is nothing more than a Client Socket to Server Socket Mapping E.G a Firewalled Network port.
And to show that this is how it works. i used my personal web server and connected to a MySQL server that does not allow any external connections to it so connections from localhost only.
To Setup a SSH Tunnel using LibSSH2 follow the code at http://api.libssh.org/master/libssh_tutor_forwarding.html under heading Doing direct port forwarding with libssh
If you don't want to expose the mapping to a port on your client machine you don't necessarily have to you could manually send data down the channel and read it however if there is any form of encryption or text encoding that does not match your on the channel to mysql you will send invalid data to it.
So once you have SSH Tunnelling created then you use it as a standard network connection to the port you have Tunnelled to talk to the service if you wish to do this in C++ use the MySQL C++ Connector and once the tunnel is create connect using the C++ Connector.
If you wish to allows your application to talk to MySQL though the SSH channel without exposing it to a network port, you probably gonna have to mess with the source code for the C++ MySQL Connector. A lot, more work that you think it is you would be going though the entire connector and any writing and reading it does via the Network Socket and replace it with code to go though your SSH Tunnel Channel.
Related
I'm new in work with interprocess communication. I need you help and clear explanation. I have 2 applications. One of them is a service and one is a client. I've used QT/C++ to write them. When they are working on the one local PC - all is good. But I need to separate them.
So, I have a service on the PC with IP 192.30.82.101.
I connect it to bus using next code:
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerObject("/my/service/MyService", mySvc);
connection.registerService("my.service.MyService");
Also I have a client on the another PC with IP 192.30.82.40.
I connect my client using the next code:
QDBusServiceWatcher serviceWatcher = new QDBusServiceWatcher();
serviceWatcher->setConnection(QDBusConnection::sessionBus());
serviceWatcher->addWatchedService("my.service.MyService");
.....
myServiceProxy = new local::MyService("my.service.MyService",
"/my/service/MyService", QDBusConnection::sessionBus(), this);
I need to connect my client on the PC with IP 192.30.82.40 to the service on the PC 192.30.82.101. I don't know how to do this. I've found a few topics on the forum but I still don't understand what to do.
So, what I have found:
On the PC where is my service I have to add additional lines to /etc/dbus-1/session.conf:
<listen>tcp:host=<host>,port=<port></listen>
<listen>unix:tmpdir=/tmp</listen>
<auth>ANONYMOUS</auth>
<allow_anonymous/>
Here I have a question: Which IP address I have to use here (server or client)? Which port is used for DBUS (is it default port or how I can check it)? I have tried to set an IP address of my client PC, my service PC and different ports, and port 0, but I've got an error: Failed to bind socket "172.30.82.40:0": Cannot assign requested address.
On the client side I have to set DBUS_SESSION_BUS_ADDRESS with the same address: export DBUS_SESSION_BUS_ADDRESS=tcp:host=<host>,port=<port>.
I've tried to do this with different ports, with 0 port, because this means - use any free port. But I cannot start bus daemon with any port+IP configuration.
Also I've tried to connect client QDBusServiceWatcher to bus using the next code:
serviceWatcher->setConnection(QDBusConnection::connectToBus("tcp:host=<host>,port=<port>", "session"));
It was not successful.
I have no idea how to connect them to each other.
Can anybody, please, explain me how it should be, how does it work?
I want to clearly understanding how does it work?
I will be very grateful for any help. I hope for your kindness.
UPDATE
I have found how to connect my client to DBus bus via TCP:
On the PC where is my service I have to add additional lines to /etc/dbus-1/session.conf:
<listen>tcp:host=localhost,bind=*,port=6667,family=ipv4</listen>
<listen>unix:tmpdir=/tmp</listen>
<auth>ANONYMOUS</auth>
<allow_anonymous/>
Here we should add PORT. We can find it in dbus config file.
On the client side I have to set DBUS_SESSION_BUS_ADDRESS with corresponding address (IP of PC where is service):
export DBUS_SESSION_BUS_ADDRESS=tcp:host=192.50.88.10,port=6667,family=ipv4.
Thats all. We can check it just started dbus-monitor.
But now I have another issue: how to connect my client to my service?
I need to do something more to connect to my service.
I guess that this is something like:
QDBusConnection::connectToBus("tcp:host=<host>,port=<port>","connectionName");
I've tried to connect with any random name, but this is not correct.
So, my question is - where I can get correct connection name?
Correct answer to my question is:
On the PC where is one application add additional lines to
/etc/dbus-1/session.conf:
<listen>tcp:host=localhost,bind=*,port=6667,family=ipv4</listen>
<listen>unix:tmpdir=/tmp</listen>
<auth>ANONYMOUS</auth>
<allow_anonymous/>
Correct port you can find in dbus config file.
On the client side It's needed to set DBUS_SESSION_BUS_ADDRESS with
corresponding address (IP of PC where is service):
export DBUS_SESSION_BUS_ADDRESS=tcp:host=192.50.88.10,port=6667,family=ipv4.
To connect to session where is alive your remote app use the next
connection string:
DBusConnection::connectToBus("tcp:host=192.50.88.10,port=6667", "qt_default_session_bus"));
How to know session name? I've added log in my service:
qDebug() << "Connection name: " << connection.name();
Then started app, copy printed name and set it in my client.
Now it works!
I writing a c++ program that should connect to a mysql database.
it works successfully when I use the local database, but I get an error
"Can't connect to mysql database on '192.168.0.111' (111)"
when I try to connect to a database on another computer.
this is the function that test my connection:
void addb()
{
string mainServer="192.168.0.111";
string mainDbUser="root";
string mainDbPass="111";
MYSQL *connect; //database connection variable
connect=mysql_init(NULL);
if(!connect)
cout<<"Couldn't initiate connector\n";
if (mysql_real_connect(connect, mainServer.c_str(), mainDbUser.c_str(), mainDbPass.c_str(), "main" ,0,NULL,0))
{
cout<<" done\n";
}
else
{
cout<<mysql_error(connect)<<endl;
}
mysql_close (connect);
}
both computers are running Linux Mint OS.
I tried disabling my firewall on the second computer but i got the same problem.
note: I can access the database using phpmyadmin with my web browser.
Make sure the firewall allows MySQL port on the DB machine.
Make sure in the my.cnf the database is loaded with you have the proper network configuration (to listen to the public IP).
From the error message - I would suspect it is a firewall issue - so make sure the DB machine firewall allows incoming communication (and specifically - that SELinux enables it in addition to the firewall) and that the sending machine allows outgoing communication to this machine.
I can run my Qt DBus test by connecting to the session bus:
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerService(...)
....
TestserviceInterface testserviceInterface( .... , connection, &a);
But can I connect to this DBus from a different computer. I know I can do something like this:
connection = QDBusConnection::connectToPeer("tcp:host=127.0.0.1,port=45000", Testservice::ServiceName);
But how would I obtain the port? Whatever I have tried, there seems to be no connection. Or am I at the wrong path here and need to us Peer 2 Peer DBus instead of the session bus?
I am almost sure the service name is correct, as I can see it qdbusviewer. When I use dbus-monitor the output does not mean a lot to me, I cannot see any port, etc.
Any idea how I would be able to connect from another computer?
PS: I am aware that there is something like gabriel for tunnelling via SSH (http://gabriel.sourceforge.net/howto.html). This is not what I am up to, I am looking for a "direct connection".
Session bus daemon usually listens unix socket /var/run/dbus/system_bus_socket ( check your /usr/local/etc/dbus-1/session.conf config ) which means that you can't access it remotely via tcp. Start some kind of port forwarding on computer where bus daemon is running (using socat for example) or configure it to listen tcp.
You can use SSH to create a tunnel for DBus.
ssh -nNT -L ./dbus_on_local:/var/run/dbus/system_bus_socket user#remote
Explanation
This will create a local "file" (unix domain socket) dbus_on_local that you can connect to.
I have client server application that works with Firebird server. Everytime when clients connect to the server they(client apps) don't check if there is a network connection to the server so at this time my application sometimes freezes when the server computer is switched off or service has stopped, so first of all I need to check connection if remote host is switched on or at some port anything listening....
Before establishing the connection I need to check it and make sure server and service is running using Indy components.
Any ideas? also I can use IcmpClient to ping remote host and then establish connection but which is the most optimal way ?
If you just want to check if the server computer can be reached, you could do a "ping" to check that. However, if you want to check if a specific TCP port is open, then the only way to find that out is to actually do a proper connect, which leads to the "freezing" program while the connection times out if there is no-one listening on that port.
I have an application which connects a remote database server.
If mysql server stops for a reason and stars succesfully after that, my application cannot detect server status quickly. It takes nearly 20 seconds to reconnect to the database server. So my gui freezes. I do not want a gui freeze for 20 seconds
So far I tried
mysql_ping
mysql_real_connect
functions
MYSQL_OPT_RECONNECT
MYSQL_OPT_CONNECT_TIMEOUT
options
My enviroment is not multi-threaded. So
how to do a faster detection?
If you do networking synchronously, be prepared for freezes. For this very reason it makes sense to do data-manipulation in a separate thread.
You could try telnet to the mysql port (usually 3306). If you get a connection refused, mysql isn't listening.
Working.
root#XXXXXX:~# telnet localhost 3306
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
L
5.6.4-m7)#m#_8:W�hP5YBzaXs[MOmysql_native_password
Down.
root#XXXXXX:~# telnet localhost 3306
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
The refused message is almost instant.
As already discussed by others, i won't talk about using multiple threads or processes. Can you connect to your mysql server on tcp? That way in most scenario's you would receive a tcp fin immediately to indicate a closed connection, though at times this might not be the case even. But most robust applications do a proper close.
shell> mysql --protocol=TCP
MYSQL how to specify protocol
If server doesn't accept it, i believe it can be enabled from config settings.
However, this does not address scenarios such as server suddenly gets off the network, or you client's connection is down etc.