Estou mantendo um servidor remoto por meio do SSH. Para garantir que minha manutenção tenha apenas um pequeno impacto na velocidade de rede do servidor, limitei meu tráfego de saída para 200 KiB / s descartando pacotes usando a seguinte regra de iptables:
# ip6tables -A INPUT -p tcp -m hashlimit --hashlimit-above 200kb/s -m tcp --destination 3ffe:ffff::dead:beef --dport 22 -j DROP
# ip6tables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp anywhere 3ffe:ffff::dead:beef limit: above 200kb/s tcp dpt:22
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
No entanto, agora, quando saturo o link, as sessões do SSH caem em intervalos de tempo previsíveis de 15 minutos:
$ for TRIAL in 'seq 1 5'
> do
> yes | dd status=progress if=/dev/stdin bs=1k count=$((500*1024)) 2>dd.$TRIAL.log |
> ssh -vvv remotehost 'cat >/dev/null' 2>&1 |
> while read LINE
> do
> printf '%s\t%s\n' 'date +%H:%M:%S' "$LINE"
> done | tee output.$TRIAL.log
> done
$ tail <output.1.log
20:51:53 debug2: channel 4: rcvd adjust 131072
20:51:54 debug2: channel 4: rcvd adjust 131072
20:51:55 debug2: channel 4: rcvd adjust 131072
20:51:55 debug2: channel 4: rcvd adjust 131072
20:51:56 debug2: channel 4: rcvd adjust 131072
20:51:56 debug2: channel 4: rcvd adjust 131072
20:51:57 debug2: channel 4: rcvd adjust 131072
20:51:58 debug2: channel 4: rcvd adjust 131072
20:51:58 debug3: send packet: type 1
20:51:58 packet_write_wait: Connection to 3ffe:ffff::dead:beef port 22: Broken pipe
$ for TRIAL in 'seq 2 5'; do tail -n 1 <output.$TRIAL.log; done
21:07:34 packet_write_wait: Connection to 3ffe:ffff::dead:beef port 22: Broken pipe
21:23:11 packet_write_wait: Connection to 3ffe:ffff::dead:beef port 22: Broken pipe
21:38:47 packet_write_wait: Connection to 3ffe:ffff::dead:beef port 22: Broken pipe
21:54:24 packet_write_wait: Connection to 3ffe:ffff::dead:beef port 22: Broken pipe
$ for TRIAL in 'seq 1 5'; do cat <dd.$TRIAL.log; echo; done
190336000 bytes (190 MB, 182 MiB) copied, 925.446 s, 206 kB/s
190317568 bytes (190 MB, 182 MiB) copied, 925.541 s, 206 kB/s
190258176 bytes (190 MB, 181 MiB) copied, 925.136 s, 206 kB/s
190503936 bytes (191 MB, 182 MiB) copied, 926.104 s, 206 kB/s
190619648 bytes (191 MB, 182 MiB) copied, 926.24 s, 206 kB/s
No lado remoto, os comandos executados ainda são interrompidos, portanto, o servidor não detecta a queda da sessão. Isso me diz que isso é um problema do cliente:
$ ssh remotehost ps ax | grep -F 'cat >/dev/null'
6999 ? Ss 0:00 bash -c cat >/dev/null
13084 ? Ss 0:00 bash -c cat >/dev/null
13425 ? Ss 0:00 bash -c cat >/dev/null
13593 ? Ss 0:00 bash -c cat >/dev/null
13779 ? Ss 0:00 bash -c cat >/dev/null
Se eu limitar a velocidade na qual canalizo os dados para o SSH (observe o comando pv -q -L 200k
abaixo), as sessões SSH não são mais ignoradas, então uso isso como solução alternativa até encontrar uma solução:
# ip6tables -D INPUT -p tcp -m hashlimit --hashlimit-above 200kb/s -m tcp --destination 3ffe:ffff::dead:beef --dport 22 -j DROP
# ip6tables -A INPUT -p tcp -m hashlimit --hashlimit-above 300kb/s -m tcp --destination 3ffe:ffff::dead:beef --dport 22 -j DROP
$ while TRIAL in 'seq 6 10'
> do
> yes | dd status=progress if=/dev/stdin bs=1k count=$((500*1024)) 2>dd.$TRIAL.log |
> pv -q -L 200k | ssh -vvv remotehost 'cat >/dev/null' 2>&1 |
> while read LINE
> do
> printf '%s\t%s\n' 'date +%H:%M:%S' "$LINE"
> done | tee output.$TRIAL.log
> done
$ tail <output.6.log
22:48:14
22:48:14 debug1: channel 3: free: port listener, nchannels 1
22:48:14 debug3: channel 3: status: The following connections are open:
22:48:14
22:48:14 debug1: fd 0 clearing O_NONBLOCK
22:48:14 debug1: fd 1 clearing O_NONBLOCK
22:48:14 debug1: fd 2 clearing O_NONBLOCK
22:48:14 Transferred: sent 524986928, received 94512 bytes, in 2925.9 seconds
22:48:14 Bytes per second: sent 179429.8, received 32.3
22:48:14 debug1: Exit status 0
$ for TRIAL in 'seq 6 10'; do tail -n 1 <dd.$TRIAL.log; done
524288000 bytes (524 MB, 500 MiB) copied, 2919.03 s, 180 kB/s
524288000 bytes (524 MB, 500 MiB) copied, 2559.03 s, 205 kB/s
524288000 bytes (524 MB, 500 MiB) copied, 2644.5 s, 198 kB/s
524288000 bytes (524 MB, 500 MiB) copied, 2559.03 s, 205 kB/s
524288000 bytes (524 MB, 500 MiB) copied, 2559.01 s, 205 kB/s
Isso me diz que a sessão SSH tem algo a ver com o fato de as mensagens de controle SSH não passarem, mas por que esse seria o caso?
Os pacotes TCP keep alive provavelmente foram descartados, mas o kernel não envia o primeiro pacote keep alive até depois de duas horas, muito tempo depois que minhas sessões SSH caíram depois de 15 minutos, então é improvável que isso seja a causa do meu problema ( /proc/sys/net/ipv4/tcp_keepalive_time
se aplica ao IPv6, bem como ao IPv4 ):
$ cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
O cliente SSH está definido para o tempo limite se não receber resposta a três mensagens SSH mantidas consecutivas, que são enviadas em intervalos de 5 minutos. De acordo com o momento, essa parece ser uma causa muito mais provável, mas a saída de depuração do SSH acima não indica que essas mensagens estão sendo enviadas pelo cliente. Há apenas um monte de mensagens no início (autenticação, abertura de um canal, etc .) e depois uma mensagem de desconexão após 15 minutos sem nada entre:
$ grep 'send packet' <output.1.log
20:36:33 debug3: send packet: type 20
20:36:33 debug3: send packet: type 30
20:36:33 debug3: send packet: type 21
20:36:33 debug3: send packet: type 5
20:36:33 debug3: send packet: type 50
20:36:33 debug3: send packet: type 50
20:36:33 debug3: send packet: type 50
20:36:33 debug3: send packet: type 90
20:36:33 debug3: send packet: type 80
20:36:33 debug3: send packet: type 98
20:36:33 debug3: send packet: type 98
20:51:58 debug3: send packet: type 1
Não apenas isso, mas se eu substituir o comando remoto cat > / dev / null por tee > / dev / null, a saída será retornada para mim, mas a sessão SSH ainda cai, então não parece ser um problema de não poder receber respostas do servidor. Na direção oposta, o servidor não envia SSH manter mensagens permanentes:
$ cat .ssh/config
Host remotehost
User username
Hostname 3ffe:ffff::dead:beef
ControlMaster auto
ControlPath /var/tmp/remotehost.socket
TCPKeepAlive yes
ServerAliveInterval 300
ServerAliveCountMax 3
$ ssh remotehost cat /etc/ssh/sshd_config
PasswordAuthentication no
TCPKeepAlive yes
ClientAliveInterval 0
Tags ssh networking ipv6 iptables linux