Equal Insurance Evaluation: Detailed Explanation of Centos Timeout Exit

1. Description

**The timeout exit configuration of the host needs to be queried in the evaluation of the equal protection evaluation host. In Centos, there are mainly two ways to achieve the timeout exit function. In fact, there is a lot of information in this area, but there are still some places that are not clear (a parameter of sshd_config), so one of the purposes of this article is to clarify those issues. **

Note: I am using Centos6

In addition, this article also mentions a note about query configuration in Linux system by the way.

2. Set TMOUT mode

This is a more general and simple way. By setting TMOUT, you can at least work for local tty login and remote ssh login users, but it should be invalid for the graphical interface. Of course, enter the graphical interface and open the terminal again. The terminal is also functional.

2.1. Method to realize

Add the export TMOUT=900 statement at the end of the /etc/profile, ~/.bashrc, ~/.bash_profile and other files (in seconds), and then it will take effect without logging in again, and you need to use the source command to parse The above file.

In the above file, /etc/profile has an effect for all users, while ~/.bashrc and ~/.bash_profile have an effect only for the current user, which can actually be seen from the file location.

2.2. Specific query method

From the above, we can know that in theory, TMOUT can be configured in several places, but generally it should be set in the file /etc/profile for all users, and there may be very few individual users who configure the timeout time separately.

So directly check the content of the /etc/profile file, and then use the echo $TMOUT statement to see what the TMOUT variable is in the running environment.

2.3. Points to note for configuration queries

Let me say a little more here. When checking the configuration, it is best to check the configuration file and actual situation together for the Linux system.

Why do you want to check together?

Because the configuration file does not mean that it is effective. For example, after the modification of /etc/profile, you need to use the source command to take effect. In addition, even if the configuration in the configuration file is effective, it may not be equivalent to the actual implementation of the rules.

For example, iptables rules can be dynamically modified with commands. Of course, if you do not use command persistence (that is, save the current rules in the iptables configuration file), restart the iptables service for those temporary rules.

So in the same way, nothing is written in the configuration file, which does not mean that there are no rules in the current running environment. For example, the rules of iptables can be added temporarily with commands.

So if you want to have a more comprehensive understanding of the situation during the evaluation, it is best to check together.

Three, modify the sshd_config file method

Generally speaking, the remote management of linux servers is through the ssh protocol, so configuring the sshd_config file is also a method, although it is only valid for all users who log in through ssh.

Remember that you need to restart after modifying the sshd_config file to take effect.

There are two parameters in the sshd_config file, ClientAliveInterval and ClientAliveCountMax.

It doesn't seem to be clear on the Internet here that depending on whether the value of ClientAliveCountMax is 0, there will be two effects.

3.1. The value of ClientAliveCountMax is 0

In this case, it is the effect that we want to automatically exit when the operation times out, that is, when the client has not operated for a long time, the server will directly disconnect the ssh connection.

This "how long" is of course determined by the value of ClientAliveInterval, and its unit is seconds.

For example, ClientAliveInterval is 600 and ClientAliveCountMax is 0, which means that if the terminal does not operate within 600 seconds, the ssh connection will be disconnected.

3.2. The value of ClientAliveCountMax is greater than 0

In this case, the effect is different from what we want:

ClientAliveInterval: specifies the time interval for the server to request messages from the client, the default value is 0;
ClientAliveCountMax: Specify the maximum number of times that the client does not respond after this request is sent by the server (but the Internet generally says how many times the server sends this message to the client, I don't think it is right), the default value is 3.

If ClientAliveInterval is 60 and ClientAliveCountMax is 1, on the surface, it means that if the client does not respond within 60s, the server will send a request to the client to determine whether it exists or not. If it is once, it means there is no response in 60 seconds. Any reply will disconnect.

So at first glance, there is no difference from ClientAliveCountMax when the value is 0, or it will not be disconnected automatically after 60 seconds without operation.

But in fact it's not the same at all, because when the server sends a request to the client to determine whether it still exists, the client should automatically reply. At the same time, ClientAliveCountMax does not mean how many such messages will be sent. Times, or it seems to have nothing to do with this at all. It should refer to the maximum number of non-response times by the client after the server sends this request, and it must be continuous, because from the source code (see below ), as long as there is a normal response, this count will be cleared.

In other words, the judgment here should be whether there is a problem with the network on the client side, such as disconnection.

Because as long as the network is normal, the client side will always automatically reply to the request sent by the server side, this count will never reach the limited threshold of 1, and will never automatically exit (ideally), and whether you have done so Operation has nothing to do...

I tested it myself and set ClientAliveInterval to 60 and ClientAliveCountMax to 1, and then I didn't operate it, and at the same time I turned off the keep alive option in xshell:

The result is that it will not automatically exit after 60 seconds...

Then I set both ClientAliveInterval and ClientAliveCountMax to 1. The result is that the server sends a message every 1 second (the arrow will be on when there is a message transmission):

If, according to the online explanation, this kind of message is sent at most once to end the conversation, the explanation will not make sense at all. This has been sent to me countless times...

I ran to see the explanation in the man, but I didn't see why:

ClientAliveCountMax
    Sets the number of client alive messages(see below) which may be sent without sshd(8) receiving any messages back from the client. If this threshold is reached while client alive messages are being sent, sshd will disconnect the client, terminating the session. It is important to note that the use of client alive messages is very different fromTCPKeepAlive(below). The client alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by TCPKeepAlive is spoofable.  The client alive mechanism is valuable when the client or server depend on knowing when a connection has become inactive. The default value is 3\. If ClientAliveInterval(see below) is set to 15, and ClientAliveCountMax is left at the default, unresponsive SSH clients will be disconnected after approximately 45 seconds. This option applies to protocol version 2 only.

ClientAliveInterval
   Sets a timeout interval in seconds after which if no data has been received from the client,sshd(8) will send a message through the encrypted channel to request a response from the client. The default is 0, indicating that these messages will not be sent to the client. This option applies to protocol version 2 only.

3.3. Source code explanation

So I went to look through the source code, but I am not familiar with the C language, I can only guess about it (please forgive me if there are errors):

There is such a paragraph in the wait_until_can_do_something function:

/* Wait for something to happen, or the timeout to expire. */
 ret =select((*maxfdp)+1,*readsetp,*writesetp, NULL, tvp);if(ret ==-1){memset(*readsetp,0,*nallocp);memset(*writesetp,0,*nallocp);if(errno != EINTR)error("select: %.100s",strerror(errno));}else{if(ret ==0&& client_alive_scheduled)client_alive_check();if(!compat20 && program_alive_scheduled && fdin_is_tty){if(!fdout_eof)FD_SET(fdout,*readsetp);if(!fderr_eof)FD_SET(fderr,*readsetp);}}

The select function definition inside is like this:

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout);

It can monitor the changes of the file descriptor we need to monitor-read and write or abnormal, its last parameter timeval*timeout is a timeout period, if the value of timeout is greater than 0, this is the waiting timeout period, namely select Blocked within the timeout period, and returns when an event arrives within the timeout period, otherwise it must return anyway after the timeout period.

If the value of timeout is null, it means that the select is placed in a blocking state, and it must wait until a file descriptor in the monitoring file descriptor set changes.

The return value of -1 means an abnormality, and a value of 0 means that the monitored files are neither writable nor readable within the timeout period. In other words, a value of 0 means that there is no operation on the client.

In the code, under certain conditions, the value of this timeout is the value of ClientAliveInterval we set (if the set value is greater than 0), if ClientAliveInterval is 0, the value of timeout is null according to some conditions.

Then according to the value of client_alive_scheduled, it is possible to call client_alive_check(), but if you use the ssh2 protocol and then set ClientAliveInterval, the value of client_alive_scheduled should be 1. The code is as follows:

if(compat20 &&
  max_time_milliseconds ==0&& options.client_alive_interval){
  client_alive_scheduled =1;
  max_time_milliseconds = options.client_alive_interval *1000;}

The definition of client_alive_check is as follows:

staticvoidclient_alive_check(void){
 int channel_id;/* timeout, check to see how many we have had */if(packet_inc_alive_timeouts()> options.client_alive_count_max){logit("Timeout, client not responding.");cleanup_exit(255);}/*
  * send a bogus global/channel request with "wantreply",
  * we should get back a failure
  * /if((channel_id =channel_find_open())==-1){packet_start(SSH2_MSG_GLOBAL_REQUEST);packet_put_cstring("[email protected]");packet_put_char(1);/* boolean: want reply */}else{channel_request_start(channel_id,"[email protected]",1);}packet_send();}

It can be seen that if packet_inc_alive_timeouts() is greater than options.client_alive_count_max, it is over.

The definition of packet_inc_alive_timeouts is very simple, that is, the accumulated timeouts
Add 1 and return.

intpacket_inc_alive_timeouts(void){return++active_state->keep_alive_timeouts;}

Therefore, if the set ClientAliveCountMax is 0, it will end directly here (0+1>0), and the following code for sending the request will not be executed.

If (channel_id = channel_find_open()) is not -1, it should mean that the channel is OK, then it will execute:

channel_request_start(channel_id,"[email protected]",1);

There is such a sentence in channel_request_start:

packet_start(SSH2_MSG_CHANNEL_REQUEST);

And SSH2_MSG_CHANNEL_REQUEST should be bound to a function

dispatch_set(SSH2_MSG_CHANNEL_REQUEST,&server_input_channel_req);

So the server_input_channel_req function will be called. The server_input_channel_req function has such a paragraph:

reply =packet_get_char();

…………

if(reply){packet_start(success ?
   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);packet_put_int(c->remote_id);packet_send();}

Here another function will be called according to the value of success. In fact, it seems that the function called is the same:

dispatch_set(SSH2_MSG_CHANNEL_SUCCESS,&server_input_keep_alive);dispatch_set(SSH2_MSG_CHANNEL_FAILURE,&server_input_keep_alive);dispatch_set(SSH2_MSG_REQUEST_SUCCESS,&server_input_keep_alive);dispatch_set(SSH2_MSG_REQUEST_FAILURE,&server_input_keep_alive);

Both are server_input_keep_alive functions, the meaning of this function is very simple:

staticvoidserver_input_keep_alive(int type, u_int32_t seq,void*ctxt){debug("Got %d/%u for keepalive", type, seq);/*
  * reset timeout, since we got a sane answer from the client.
  * even if this was generated by something other than
  * the bogus CHANNEL_REQUEST we send for keepalives.
  * /packet_set_alive_timeouts(0);}

packet_set_alive_timeouts(0) is to set the value of active_state->keep_alive_timeouts to 0, which is to reset the count.

So for a while, the meaning of these codes should probably be like this. If the client does not respond within the specified time, it will first determine whether the number of non-responses exceeds the set value, and if it exceeds, it will end.

If it is not exceeded, add 1 to the number of times, and then send a request to see if the client is still there. If the client's network is normal (should automatically reply), the client will reply, so reset the unresponsive count.

Fourth, the difference between the two methods

The TMOUT mode can work for all users logging in through local tty or remote ssh, while modifying sshd_config is only for users logging in using ssh.

Another point is that TMOUT judges whether you are operating. It seems to see if you have typed any characters and then press Enter to execute. If you enter the correct command and press Enter to execute the command, it doesn't matter. Enter meaningless characters and hit Enter and no executable commands are found, so that counts. It doesn't count as long as you input a character without hitting Enter, and if you are in an idle state, you will be logged out after timeout.

And ssh is based on the network to judge, as long as the client sends information to the server, it is considered to be operating.

These are also some subtle differences between the two.

***This article original author: from where to where, rather than on paper belong FreeBuf original incentive program without permission prohibited reproduced **

Recommended Posts

Equal Insurance Evaluation: Detailed Explanation of Centos Timeout Exit
Detailed explanation of building Hadoop environment on CentOS 6.5
Detailed explanation of Centos 7 system virtual machine bridging mode
Detailed explanation of CentOS7 network setting tutorial in vmware
Detailed explanation of Spark installation and configuration tutorial under centOS7
Detailed explanation of python backtracking template
Detailed explanation of python sequence types
Detailed explanation of ubuntu using gpg2
CentOS 8 installation of MariaDB detailed tutorial
Detailed use of nmcli in CentOS8
Detailed examples of Centos6 network configuration
Centos 7 RAID 5 detailed explanation and configuration
Detailed explanation of Python IO port multiplexing
Detailed explanation of Python guessing algorithm problems
Centos7 installation and deployment of Airflow detailed
CentOS7 fully automatic installation CD production detailed explanation
Detailed explanation of the principle of Python super() method
Detailed explanation of python standard library OS module
Centos7 installation of PHP and Nginx tutorial detailed
Detailed explanation of the usage of Python decimal module
Detailed explanation of how python supports concurrent methods
Detailed explanation of data types based on Python
Detailed tutorial of installing nginx on centos8 (graphic)