I'm connecting to a remote MySQL server (on the default port 3306) using the C API call mysql_real_connect().
How can I discover which TCP port is used on the client host?
Is it possible to specify the port that I wish to use?
1
You can use lsof.
Type following in your shell:
$ lsof | grep TCP
And then look for the port on which your mysql server is listening.
You can also make use of netstat.
Details can be found by man netstat.
2
As far as I know, you can not.
the MYSQL structure has an FD buried in it (for me at least; tested on centos7 with mariadb 5.5.58).
you can use that to find the local address and port
struct sockaddr_in laddr;
socklen_t sb = sizeof(laddr);
if (getsockname(mysql.net.fd, (sockaddr*)&laddr, &sb) == -1)
printf("getsockname() failed, err %s\n",strerror(errno));
else
printf("local address [%x] port [%u]",ntohl(laddr.sin_addr.s_addr),ntohs(laddr.sin_port));
Related
I try to connect 2 docker containers to each other via socat.
Inside of the web container, I'll use socat to bind the external mysql-container to Port 3306.
I do use this command line:
socat TCP:$MYSQL_CONTAINER_IP:$MYSQL_CONTAINER_PORT,fork,reuseaddr,unlink-early,user=root,group=root,mode=777 UNIX-LISTEN:$MY_SOCKET &
While $MYSQL_CONTAINER_IP = 172.17.0.2
and $MYSQL_CONTAINER_PORT = 3306
$MY_SOCKET is set via:
MY_SOCKET=$(mysql_config --socket)
and result in /var/run/mysqld/mysqld.sock
But if I run this command, I got this:
2022/05/29 06:43:54 socat[10267] E bind(6, {AF=1 "/var/run/mysqld/mysqld.sock"}, 29): No such file or directory
The Web-Docker-Container is debian:buster (Debian buster [10]),
The MySql Container is Debian wheezy:latest
Any Idea, why I got the above noticed error-message?
The error message sounds like directory /var/run/mysqld/ does not exist in the environment where Socat is run. I'd recommend to check this.
However, the Socat command line you constructed, with the fork option on the TCP address, will try every second to establish another connection to the MySQL server, and from the second connection (and sub process) on the UNIX bind will fail.
For typical forwarder uses, you should have the listener with fork as the first address, and the connector (here TCP:) as second address.
I'm a beginner in both docker and mysql, and I use below command to run a mysql container
docker container run --publish 3306:3306 --name mysqlDB -d --env MYSQL_RANDOM_ROOT_PASSWORD=yes mysql
Now it run successfully and in order to grab the generated password, I run below command
docker container logs [containerID]
Within the logs I can find my GENERATED ROOT PASSWORD, but as I try to read the logs I noticed the below log
[System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/var/run/mysqld/mysqlx.sock' bind-address: '::' port: 33060
May I know what is this means? Is there by any chance I opened a port 33060? And how do I verify it?
This seems to be a MySQL plugin that adds document-oriented APIs to MySQL. Here you can find some more info: https://www.percona.com/blog/2019/01/07/understanding-mysql-x-all-flavors/
That port number seems to be unrelated to your bindings, that's just adefault port number for that plugin.
Also, that port number is not exposed, so, there is nothing to fear, attack surface is still the same.
And if you want to disable that thing, here are the instructions: https://dev.mysql.com/doc/refman/8.0/en/x-plugin-disabling.html (command line option is probably your best bet -- considering docker environment).
To make sure port is not exposed you can run container and do docker ps, you'll see something like this:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43dd96119ded lb_geo-api "/bin/sh -c 'exec sh…" 6 months ago Up 7 days 80/tcp, 0.0.0.0:4203->8080/tcp lb_geo-api_1_a86ebad528fc
Last column -- "PORTS" -- is the list of ports and their bindings on your host:
80/tcp -- port 80 can is exposed from inside container but not mapped to host port, so, nobody from outside can connect there
0.0.0.0:4203->8080/tcp -- port 8080 is exposed and is mapped to port 4203 on all network adapters, and it can be connected from outside
So, if there is no port 33060 in your output, or if it is there but not mapped -- you're safe. In any case only you can map it when you start the container, so, if you did not do that, then it is not mapped.
I was surprised by a MySQL log entry equivalent to yours, #Isaac, which led me to your question, although I'm not working with Docker. Here is what I think I've learned and what I've done.
MySQL's "X plugin" extends MySQL to be able to function as a document store. See MySQL manual section on server plugins, manual section on document store features, and April 2018 document store availability announcement.
By default, for its X plugin features, MySQL listens on port 33060, bound to all IP addresses. See manual section on X plugin options and system variables (indicating default values for "mysqlx_port" and "mysqlx_bind_address"), and X plugin option and variable reference. For its traditional features, MySQL still uses port 3306 by default.
I believe the default X plugin port and network address are what are reflected in the log entry you posted. In particular, I believe the excerpt X Plugin ... bind-address: '::' indicates MySQL's default wildcard ip address binding for X plugin connections.
If you'd like to use the X plugin features but refrain from listening to all IP addresses for them, you can specify the address(es) to which it listens for TCP/IP connections with the mysqlx_bind_address option. The command line format would be
--mysqlx-bind-address=addr
Alternatively, you could set that system variable in a MySQL option file, like this for example:
[mysqld]
<... other mysqld option group settings>
mysqlx_bind_address = 127.0.0.1
The MySQL manual provides helpful general information about specifying options on the command line or in an option file. Here is some information about setting MySQL options in a Docker container, although I have never tried it.
It seems there are distinct settings for the network addresses listened to by MySQL's X-plugin-enabled features and MySQL's traditional features. You set the network address(es) for the traditional features with the bind_address option. So if you want to limit both sets of features to listening for TCP/IP connections from localhost, you could, for example, put this in your MySQL options file, which is what I've just tried in mine:
[mysqld]
bind_address = 127.0.0.1
mysqlx_bind_address = 127.0.0.1
In contrast, it appears, you could set a single system variable -- skip_networking -- to permit only local, non-TCP/IP connections (e.g., Unix sockets, or Windows named pipes or shared memory) for both traditional and X Plugin features.
If you don't want to use the X plugin features at all, you could disable them as #alx suggested.
To verify which network addresses and ports MySQL is listening on, you have a variety of options. In my non-docker Linux environment, I found
netstat -l | grep tcp
and
sudo lsof -i | grep mysql
helpful.
You have published your port. That --publish 3306:3306 actually publishes your container port to host port and now your host port 3306 is occupied by mysql. If you do not want that you can just remove --published 3306:3306 and container port will not be bound to host port.
I am trying to troubleshoot a C program that connects to a local SQL database and then runs a series of commands. Should be SQL Coding 101... but I'm missing something fundamental. I'm working in a Linux container, which supports both the SQL server and is where my C program runs.
Some basics: Here's the Linux version:
root#1234567890:/home/me# uname -mrs
Linux 4.4.0-64-generic x86_64
root#1234567890:/home/me#
I have my SQL server running, installed from the instructions here. The service is up, and I can manually query it with SQLCMD:
root#1234567890:/home/me#
root#1234567890:/home/me# ps -ef | grep sql
root 1 0 0 15:45 ? 00:00:00 /opt/mssql/bin/sqlservr
root 8 1 0 15:45 ? 00:01:25 /opt/mssql/bin/sqlservr
root 13988 13639 0 18:38 pts/2 00:00:00 grep --color=auto sql
root#1234567890:/home/me#
root#1234567890:/home/me#
root#1234567890:/home/me# /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Password01'
1> SELECT ##servername;
2> go
--------------------------------------------------------------------------------------------------------------------------------
abc123456789
(1 rows affected)
1>
Not sure why there are two instances of "sqlservr", but overall, the above is promising. Back when I set up the SQL server, I let it pick the default TCP port, 1433, and it looks like the service is listening there:
root#1234567890:/home/me# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.11:40962 *:* LISTEN
tcp 0 0 *:1433 *:* LISTEN
udp 0 0 127.0.0.11:60893 *:*
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
root#1234567890:/home/me#
Some Networking 101 troubleshooting here:
root#1234567890:/home/me# telnet 127.0.0.1 1433
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^C
Connection closed by foreign host.
root#1234567890:/home/me#
Hmm. If my SQL server was listening on this port, would this be the response I would expect to see here? Not sure.
Now to my C code. I have the "mysqlclient" library in on my machine and it seems to be running just fine. Here's the code:
/* sqlToy.c */
#include <stdio.h>
#include "/usr/include/mysql/mysql.h"
/* Adapted from:
https://www.youth4work.com/Talent/C-Language/Forum/118317-how-do-link-database-with-in-a-c-program
*/
int main() {
MYSQL mysql;
printf("...attempting initization... ");
if(mysql_init(&mysql)==NULL) {
printf("\nInitialization error\n");
return 0;
} else {
printf("Initilization successful!\n");
}
printf("...attempting connection... ");
if(mysql_real_connect(&mysql, "localhost", "sa", "Password01", NULL, 1433, NULL, 0) == NULL){
printf("Connection error\n");
return 0;
}
mysql_close(&mysql);
return 1;
}
Here's program compilation and the output:
root#1234567890:/home/me# gcc -Wall sqlToy.c -lmysqlclient
root#1234567890:/home/me# ./a.out
...attempting initization... Initilization successful!
...attempting connection... Connection error
root#1234567890:/home/me#
The "Connection error" message pops up IMMEDIATELY, with no waiting.
I also note that when I do a "tail -f /var/opt/mssql/log/errorlog", I never see an error message when my program runs. Which makes me wonder if the C program's request is reaching the SQL server at all.
I suspect there are one of two possibilities going on here:
(A) The mysql_real_connect() command in the C code is wrong, I'm using the wrong options, the wrong flags, etc. And a failed login is not logged in /var/opt/mssql/log/errorlog.
(B) Although it looks like everything is good to go, there's some network problem. ie, the SQL server really isn't listening on 1433, something like that.
Any ideas? Thanks...
Transferring comment into an answer.
I would expect to use the MySQL client libraries (functions such as mysql_init() in your code) to connect to a MySQL database server. Similarly, I'd expect to use the SQL Server client libraries (probably ODBC plus the SQL Server driver) to connect to SQL Server.
Expecting the MySQL client library to connect to an SQL Server database is at least 'not obviously correct'. Having looked briefly at the MySQL C API documentation, I think that it is 'obviously not correct'. So, if you want to connect to SQL Server, you should probably use ODBC (and the SQL Server driver).
There's an ODBC driver for MySQL too; if you do need to connect to both SQL Server and MySQL in the same program, it might be sensible to use ODBC for both.
Generalizing, most DBMS provide several methods of connecting to the database server. For Java code, there is likely a JDBC driver; for .NET code, there might be a .NET driver, or it might use ODBC under the covers. For most other languages, the usual technique is to choose between an ODBC driver for the DBMS or the DBMS's native connectivity, which goes by many different names. You need to match the client code libraries with the database server you want to connect to. Expecting an Oracle driver to connect to DB2 is not plausible; expecting a MySQL driver to connect to SQL Server is not plausible. There may be techniques that allow such inter-connectivity, but they require great care. The ODBC infrastructure has a common, driver independent layer (driver manager) and a unique-per-DBMS, driver dependent layer. You can sometimes write code using ODBC and arrange to connect to different DBMS by having different drivers loaded concurrently.
Basically, I am trying to connect to a MySQL Database using Connector C drivers for MySQL. I am writing the code in Netbeans on a Linux system. But here is the mystery: I can connect to my database in Debug Mode, but not Release Mode??? I am using Netbeans as my IDE on Linux, and I set up all the libraries and include folders using the dropdown under project properties so it applies the properties to both the Debug Configuration and Release Configuration, and yet it will connect to the database when I execute in Debug, but not when I execute in Run - ??? I simplified the code to show you the actual connection code:
int readDB(void) {
MYSQL *mysql = NULL;
char *server = "localhost";
char *user = "root";
char *password = "";
char *database = "myDB";
int port = 3306;
mysql = mysql_init(mysql);
if (!mysql) {
puts("Init failed, out of memory?");
return EXIT_FAILURE;
} else {
puts("SUCCESS!\n");
}
if (!mysql_real_connect(mysql,server,user,password,database,port,NULL,0)) {
puts("Connect failed\n");
}
return 1;
}
So when I run it in Debug, it prints "SUCCESS" and nothing else. When I run it, it prints "SUCCESS" followed by "Connect failed". I am at a loss. Could this be a problem with the IDE? Is there another IDE for C that works well on Linux that I should consider? Or am I missing something quite obvious?
Update:
calling mysql_error() revealed
"Can't connect to local MySQL server through socket '/tmp/mysql.sock'
(2)"
When using a mysql client library in most languages including C, if the hostname is specified as localhost the client library will attempt to connect through a unix domain socket. You can force connection using TCP/IP by specifying the hostname as 127.0.0.1
Yes they are one and the same but
If unix_socket is not NULL, the string specifies the socket or named
pipe to use. Note that the host parameter determines the type of the
connection.
Alternatively you can examine your mysql configuration to find out where the socket has been created when the server starts and use that as the unix_socket parameter.
Third alternative is to change your server configuration to create the socket on /tmp/
I have the following problem.
Background:
I want to connect to a MySQL database and download tables into R.
The database (the MySQL prompt) can only be accessed via SSH tunnel to another server.
I am using Mac OSX El Capitan on a MacBook Pro (2015).
Problem:
From the 'terminal', I can easily SSH to the server, and thereon enter the MySQL prompt and run the queries I need.
I cannot, however, perform the latter tasks from within RStudio.
The code I tried is:
> system('ssh -f <server_user>#<server_ip> -N sleep 20')
> db <- dbConnect(MySQL(), host="hostname", user="username", pwd="password", dbname="databasename", port=3306)
> sql1 <- paste("SELECT * FROM databasename.tablename", sep="")
> results <- dbGetQuery(con, sql1)
> dbDisconnect(con)
While I can see from ps -A | grep ssh that the ssh process is running (for the 20 seconds I want it to), and in R the command executed normally (not waiting for more input), I cannot connect to the relevant database. The error message was something to effect of "could not connect", and RStudio hangs for at least a minute before the error appears.
The questions:
How does one
(1) Use SSH in conjunction with
(2) MySQL on the remote server to
(3) load tables directly into an R data frame?
Thanks.
You should use something which is called port forwarding. Some details are here (https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding)
For example, say you wanted to connect from your laptop to http://www.ubuntuforums.org using an SSH tunnel. You would use source port number 8080 (the alternate http port), destination port 80 (the http port), and destination server www.ubuntuforums.org. :
ssh -L 8080:www.ubuntuforums.org:80 <host>
Where <host> should be replaced by the name of your laptop.
This is done for whole computer so you dont need to do this from r studio.
Offcourse you need to forward your port to 3036. But you need special privilige on the server. Because on most hosting you can only connect from localhost (for example from php)