当前位置:网站首页>MySQL source code reading (II) login connection debugging

MySQL source code reading (II) login connection debugging

2022-06-25 09:46:00 InfoQ

brief introduction

In the previous article, we have successfully run the source code locally , Next we need to connect to our database , Make certain preparations for the following work

Use docker Container trying to connect

We use docker The container is used to start the connection to the successful operation in our last article MySQL The server , But it didn't work , No connection succeeded

The following error , We used to see it all the time

PS C:\Users\lw> docker run -ti mysql mysql -h 192.168.1.4 -P 3306 -u root -p
Enter password:
ERROR 1130 (HY000): Host 'DESKTOP-8U69O9P' is not allowed to connect to this MySQL server

We use : is not allowed  Go to the global search code , Find the code below , By making a breakpoint , Also came to this step

Successfully found the code entry

bool acl_check_host(const char *host, const char *ip)
{
 mysql_mutex_lock(&acl_cache->lock);
 if (allow_all_hosts)
 {
 
 mysql_mutex_unlock(&acl_cache->lock);
 return 0;
 }

 if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
 (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
 {
 mysql_mutex_unlock(&acl_cache->lock);
 return 0; // Found host
 }
 for (ACL_HOST_AND_IP *acl= acl_wild_hosts->begin();
 acl != acl_wild_hosts->end(); ++acl)
 {
 if (acl->compare_hostname(host, ip))
 {
 mysql_mutex_unlock(&acl_cache->lock);
 return 0; // Host ok
 }
 }
 mysql_mutex_unlock(&acl_cache->lock);
 if (ip != NULL)
 {
 /* Increment HOST_CACHE.COUNT_HOST_ACL_ERRORS. */
 Host_errors errors;
 errors.m_host_acl= 1;
 inc_host_errors(ip, &errors);
 }
 return 1; // Host is not allowed
}

By debugging , We found that acl_wild_hosts There is no value in it , Lead to ip==null, thus host No match , Connection is not allowed

We didn't find... In the current file acl_wild_hosts, You can only search through the entire solution , We navigate to the following code :

static void init_check_host(void)
{
 DBUG_ENTER("init_check_host");
 if (acl_wild_hosts != NULL)
 acl_wild_hosts->clear();
 else
 acl_wild_hosts=
 new Prealloced_array<ACL_HOST_AND_IP, ACL_PREALLOC_SIZE>(key_memory_acl_mem);

 size_t acl_users_size= acl_users ? acl_users->size() : 0;

 (void) my_hash_init(&acl_check_hosts,system_charset_info,
 acl_users_size, 0, 0,
 (my_hash_get_key) check_get_key, 0, 0,
 key_memory_acl_mem);
 if (acl_users_size && !allow_all_hosts)
 {
 for (ACL_USER *acl_user= acl_users->begin();
 acl_user != acl_users->end(); ++acl_user)
 {
 if (acl_user->host.has_wildcard())
 { // Has wildcard
 ACL_HOST_AND_IP *acl= NULL;
 for (acl= acl_wild_hosts->begin(); acl != acl_wild_hosts->end(); ++acl)
 { // Check if host already exists
 if (!my_strcasecmp(system_charset_info,
 acl_user->host.get_host(), acl->get_host()))
 break; // already stored
 }
 if (acl == acl_wild_hosts->end()) // If new
 acl_wild_hosts->push_back(acl_user->host);
 }
 else if (!my_hash_search(&acl_check_hosts,(uchar*)
 acl_user->host.get_host(),
 acl_user->host.get_host_len()))
 {
 if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
 { // End of memory
 allow_all_hosts=1; // Should never happen
 DBUG_VOID_RETURN;
 }
 }
 }
 }
 acl_wild_hosts->shrink_to_fit();
 freeze_size(&acl_check_hosts.array);
 DBUG_VOID_RETURN;
}

From the name and function , This is acl_check_hosts Initialization related code of

among acl_users Debug through breakpoints , There are three users :

  • root: Our frequently used initial users
  • mysql.session:  I haven't seen this yet
  • mysql.sys:  I haven't seen this either

This function looks like , There are roughly two places that can lead to acl_check_hosts An increase in :

(void) my_hash_init(&acl_check_hosts,system_charset_info,
 acl_users_size, 0, 0,
 (my_hash_get_key) check_get_key, 0, 0,
 key_memory_acl_mem);

The above one is initialization , No new parameters were found from the parameters

The following code is an obvious addition , But under commissioning , The code can't go into this logic

if (acl == acl_wild_hosts->end()) // If new
 acl_wild_hosts->push_back(acl_user->host);

And the first step that can't go on is

if (acl_user->host.has_wildcard())

bool has_wildcard()
 {
 return (strchr(hostname,wild_many) ||
 strchr(hostname,wild_one) || ip_mask );
 }

strchr Is a string search function : This function returns the string  str  The first occurrence of the character  c  The location of , If the character is not found, returns  NULL.

Among them wild_many We are familiar with %, and wild_one yes &quot;_&quot;, and hostname yes localhost, So there's no match for

Can't go on , Then we can only see acl_user The relevant code of

Very lucky , In the current file , We found it acl_users Initialization function for :

static my_bool acl_load(THD *thd, TABLE_LIST *tables)

//  The function code is too long , First paste a key
acl_users->push_back(user);

and host The initialization of is in this step :

user.host.update_hostname(get_field(&global_acl_memory,
 table->field[table_schema->host_idx()]));

It looks like reading some data from the table , There is a big nod , I can't move it , Look not to understand ( Beyond the cognitive load , We can't dig any more , You can only jump up first )

Use mysql workbench Connect

To avoid sticking all the time , Let's install one locally mysql workbench, And then use localhost Domain name and root Users connect

If you forget the initial password , Want to initialize again , You may encounter the following error :

2022-06-25T00:28:59.791538Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.

We put the source code in the root directory : release/sql/data  Just delete the folder

The first time the link is used, the password needs to be reset , After reset , On the link

Then we execute the following script , give root other ip Connection permission of

SET SQL_SAFE_UPDATES = 0;
use mysql;
update user set host='%' where user='root';
flush privileges;

Before we run the above SQL When , User initialization and host Initialization of detection , Do it all over again

Again using mysql Connect containers

Then we run the command again to connect

docker run -ti mysql mysql -h 192.168.1.4 -P 3306 -u root -p

By debugging , We find that now it is direct :allow_all_hosts  Directly allow access to

bool acl_check_host(const char *host, const char *ip)
{
 mysql_mutex_lock(&acl_cache->lock);
 if (allow_all_hosts)
 {
 
 mysql_mutex_unlock(&acl_cache->lock);
 return 0;
 }
 ......
}

By checking that the code is set here , But I don't understand it very well , Leave it for later , I feel a little dizzy today

static void init_check_host(void)
{
......
 if (acl_users_size && !allow_all_hosts)
 {
 {
 if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
 { // End of memory
 //  Here, you can directly set
 allow_all_hosts=1; // Should never happen
 DBUG_VOID_RETURN;
 }
 }
 }
 }
......
}

Then we successfully visited

summary

Today, I went through the login authentication code , Yes MySQL Have a preliminary understanding of connection authentication , But there are still many details that are not clear

Use docker After the container is successfully connected , We have been debug down , Found out tcp Connected listener handler :

extern &quot;C&quot; void *handle_connection(void *arg)
{
 //  Connection preparation , Today's host Detection and user authentication are performed in this function
 if (thd_prepare_connection(thd))
 handler_manager->inc_aborted_connects();
 else
 {
 while (thd_connection_alive(thd))
 {
 //  You can tell from the name that it is the handler of a specific command , Hey , Found the function entry of the next article
 if (do_command(thd))
 break;
 }
 end_connection(thd);
 }
 close_connection(thd, 0, false, false);
 ······
}

Reference link

  • MySQL error code: 1175 during UPDATE in MySQL Workbench
  • MySQL After initializing the database, modify root User password and use specified host Sign in
  • C  Library function  - strchr()
原网站

版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206250932232756.html