Rootop 服务器运维与web架构

2020-09-04
发表者 Venus
chrome浏览器中网络错误的3种情况 ERR_CONNECTION_TIMED_OUT、ERR_CONNECTION_REFUSED、ERR_CONNECTION_RESET已关闭评论

chrome浏览器中网络错误的3种情况 ERR_CONNECTION_TIMED_OUT、ERR_CONNECTION_REFUSED、ERR_CONNECTION_RESET

# 服务端监听端口,但拒绝接收syn包,或者网络不通。
比如iptables中拒绝掉syn标记的包

iptables -A INPUT -p tcp --dport 80 --syn -j DROP

以下错误是chrome浏览器访问时的报错信息:
ERR_CONNECTION_TIMED_OUT #客户端发送了syn包,但未收到回应的syn+ack包(服务端不响应),而且客户端一直在重传syn。

# 服务端未监听端口
ERR_CONNECTION_REFUSED #客户端发送了syn,服务端响应了rst+ack,客户端重传,服务端依旧响应rst+ack,3次握手无法建立。

# IP被墙
ERR_CONNECTION_RESET #客户端发送syn,服务器响应syn+ack,客户端回应ack,3次握手完成,客户端发起http请求,服务端回应rst+ack

2020-08-31
发表者 Venus
华为云服务器iptables中的自定义链IN_HIDS_MYSQLD_BIP_DROP和IN_HIDS_MYSQLD_DENY_DROP已关闭评论

华为云服务器iptables中的自定义链IN_HIDS_MYSQLD_BIP_DROP和IN_HIDS_MYSQLD_DENY_DROP

测试环境日志报连不上测试数据库,本地测试可以远程连接。其它服务器也可以连接,tcp抓包有reset位,推测是什么安全机制断开了连接。

在 /var/log/messages 日志中发现有mysqld_drop的字眼,遂查看iptables规则

[4333361.597329] mysqld_drop: IN=eth0 OUT= MAC=fa:16:3e:c0:96:2a:fa:16:3e:90:0d:c4:08:00 SRC=124.70.xxx.xxx DST=192.168.0.38 LEN=60 TOS=0x00 PREC=0x00 TTL=56 ID=15889 DF PROTO=TCP SPT=54734 DPT=3306 WINDOW=29200 RES=0x00 SYN URGP=0 
[4333361.702625] mysqld_drop: IN=eth0 OUT= MAC=fa:16:3e:c0:96:2a:fa:16:3e:90:0d:c4:08:00 SRC=124.70.xxx.xxx DST=192.168.0.38 LEN=60 TOS=0x00 PREC=0x00 TTL=56 ID=30534 DF PROTO=TCP SPT=47370 DPT=3306 WINDOW=29200 RES=0x00 SYN URGP=0 
[4333362.150774] mysqld_drop: IN=eth0 OUT= MAC=fa:16:3e:c0:96:2a:fa:16:3e:90:0d:c4:08:00 SRC=124.70.xxx.xxx DST=192.168.0.38 LEN=60 TOS=0x00 PREC=0x00 TTL=56 ID=52149 DF PROTO=TCP SPT=44338 DPT=3306 WINDOW=29200 RES=0x00 SYN URGP=0 

# 服务器iptables规则

[root@ecs-38b6-0002 ~]#  iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
IN_HIDS_MYSQLD_BIP_DROP  tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:3306
IN_HIDS_MYSQLD_DENY_DROP  tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:3306

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain IN_HIDS_MYSQLD_BIP_DROP (1 references)
target     prot opt source               destination         

Chain   (1 references)
target     prot opt source               destination         
LOG        all  --  124.70.xxx.xxx        0.0.0.0/0            LOG flags 0 level 4 prefix "mysqld_drop: "
REJECT     all  --  124.70.xxx.xxx        0.0.0.0/0            reject-with icmp-port-unreachable

发现多出来 IN_HIDS_MYSQLD_BIP_DROP 自定义链,这条链还被INPUT链引用了。而且规则中的ip是测试服的公网ip。
通过规则可以看出来自测试服的ip访问3306被丢弃+记录日志。

这2条链并不是我加的,发工单问华为云客服,客服也不知道,让排查是否自己安装。

ps查进程,发现有个hostguard进程

[root@ecs-38b6-0002 conf]# ps aux | grep hostguard
root      7361  0.0  0.0 112712   968 pts/0    S+   16:33   0:00 grep --color=auto hostguard
root      9206  0.0  0.0  49044  1468 ?        Ss   Jun17   9:34 /usr/local/hostguard/bin/hostguard
root     27978  0.1  0.0 1398848 7388 ?        Sl   Jul13  99:12 /usr/local/hostguard/bin/hostguard
[root@ecs-38b6-0002 conf]# cd /usr/local/hostguard/conf/
[root@ecs-38b6-0002 conf]# ll
total 2448
-r-------- 1 root root      32 May 14 13:00 agent.conf
-rw-r--r-- 1 root root     105 Aug 31 00:00 agentinfo
drwxr-xr-x 2 root root    4096 May 14 13:00 benchmarkconf
-r-------- 1 root root   14340 May 14 13:00 cmsvul.dat
-r-x------ 1 root root    1497 May 14 13:00 config_ssh_log.sh
-r-x------ 1 root root    3193 May 14 13:00 config_ssh_xinetd.sh
-r-------- 1 root root   35332 May 14 13:00 dict.dat
-rw-r--r-- 1 root root      33 Jun 17 12:28 lb.dat
-r-------- 1 root root 1751200 May 14 13:00 magic.mgc
-rw-r--r-- 1 root root      63 Aug 31 16:29 master.dat
-rw-r--r-- 1 root root       0 Aug 30 23:36 modlogin_deny.conf
-rw-r--r-- 1 root root       0 Jul 13 19:19 mysqld_iptables_bip
-rw-r--r-- 1 root root       0 Aug 28 11:21 mysqld_iptables_block
-rw-r--r-- 1 root root    5128 Jun 17 12:29 policy.dat
-rw-r--r-- 1 root root      24 Jul 13 19:18 priv_cpu.dat
-r-------- 1 root root      65 May 14 13:00 res.conf
-r-------- 1 root root   40181 May 14 13:00 rootkit.json
-r-------- 1 root root    3332 May 14 13:00 selfitgr.dat
-rw-r--r-- 1 root root      10 Aug 31 16:33 sending.dat
-r-------- 1 root root     149 Jun 17 12:28 system.conf
-r-------- 1 root root     426 May 14 13:00 user.key
-r-------- 1 root root      26 May 14 13:00 version
-r-------- 1 root root  590648 May 14 13:00 wsyrules.dat

发现也有mysql相关的文件,估计就是这个进程导致的了。查华为文档发现,hostguard是华为主机安全软件。
至于原因,推测是测试服发起了大量连接(有对mysql连接池操作过加大动作)或者大量的错误mysql认证,导致云服务器中的安全进程判断为不安全连接,直接给拒绝了。

2020-08-25
发表者 Venus
内核参数 tcp_syn_retries 参数已关闭评论

内核参数 tcp_syn_retries 参数

/proc/sys/net/ipv4/tcp_syn_retries 的值表示socket客户端进行s.connect()连接时,在服务端未返回SYN + ACK标识的情况下,也就是连接超时后,离第一次SYN包发送之后的重试次数,包括重试时间的计算。
tcp_syn_retries默认是6,本机主动发起SYN连接,如果一直收不到服务端返回的SYN + ACK,那么应用程序最大的超时时间就是127秒,也就是2^6次幂-1。

# 测试,服务端启动nginx,监听80端口
# 服务端通过iptables拒绝80端口的syn包
[root@centos ~]# iptables -A INPUT -p tcp --dport 80 --syn -j DROP

 

# 客户端查看tcp_syn_retries值
root@rootop:/proc/sys/net/ipv4# cat tcp_syn_retries 
6

 

# 客户端telnet连接
root@rootop:~# telnet 106.53.233.92 80

 

# 服务端抓包
[root@centos ~]# tcpdump -i eth0 -n src 101.32.23.53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
第一次访问  
11:00:35.015937 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2288999938 ecr 0,nop,wscale 7], length 0

# 重试第1次访问,间隔 2^0=1 秒
11:00:36.019825 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289000942 ecr 0,nop,wscale 7], length 0

# 重试第2次访问,间隔 2^1=2 秒
11:00:38.035884 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289002958 ecr 0,nop,wscale 7], length 0

# 重试第3次访问,间隔 2^2=4 秒
11:00:42.163811 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289007086 ecr 0,nop,wscale 7], length 0

# 重试第4次访问,间隔 2^3=8 秒
11:00:50.355830 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289015278 ecr 0,nop,wscale 7], length 0

# 重试第5次访问,间隔2^4=16 秒
11:01:06.483835 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289031406 ecr 0,nop,wscale 7], length 0

# 重试第6次访问,间隔2^5=32 秒
11:01:40.531835 IP 101.32.23.53.40838 > 10.0.8.15.http: Flags [S], seq 293412828, win 64240, options [mss 1424,sackOK,TS val 2289065454 ecr 0,nop,wscale 7], length 0

 

# 客户端tcp_syn_retries改为10次
root@rootop:/proc/sys/net/ipv4# cat tcp_syn_retries 
10

再次访问并抓包

[root@centos ~]# tcpdump -i eth0 -n src 101.32.23.53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
第一次访问
12:23:01.071964 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293945993 ecr 0,nop,wscale 7], length 0

# 重试第1次访问,间隔 2^0=1 秒
12:23:02.100530 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293947022 ecr 0,nop,wscale 7], length 0

# 重试第2次访问,间隔 2^1=2 秒
12:23:04.116528 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293949038 ecr 0,nop,wscale 7], length 0

# 重试第3次访问,间隔 2^2=4 秒
12:23:08.340521 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293953262 ecr 0,nop,wscale 7], length 0

# 重试第4次访问,间隔 2^3=8 秒
12:23:16.532513 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293961454 ecr 0,nop,wscale 7], length 0

# 重试第5次访问,间隔2^4=16 秒
12:23:32.660578 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2293977582 ecr 0,nop,wscale 7], length 0

# 重试第6次访问,间隔2^5=32 秒
12:24:06.452593 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2294011374 ecr 0,nop,wscale 7], length 0

# 重试第7次访问,间隔2^6=64 秒
12:25:11.988544 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2294076910 ecr 0,nop,wscale 7], length 0

# 重试第8次访问,间隔2^7=128 秒,实际约2分钟
12:27:12.820615 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2294197742 ecr 0,nop,wscale 7], length 0

# 重试第9次访问,间隔2^7=128 秒,实际约2分钟
12:29:13.652590 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2294318574 ecr 0,nop,wscale 7], length 0

# 重试第10次访问,间隔2^7=128 秒,实际约2分钟
12:31:14.484568 IP 101.32.23.53.41694 > 10.0.8.15.http: Flags [S], seq 3047227869, win 64240, options [mss 1424,sackOK,TS val 2294439406 ecr 0,nop,wscale 7], length 0

在实际中并不会让客户端重试这么多次,比如在socket连接中会定义超时时间。
超过时间,则不再发送syn。
# python 代码

import socket
import function.func as func

s = socket.socket()
s.settimeout(3) # 超时
print(func.now())
s.connect_ex(('106.53.233.92', 80))
# 注意是用的connect_ex()方法,而不是connect()方法
print(func.now())

# 返回值
2020-08-25 13:41:34
2020-08-25 13:41:37

# 服务器抓包结果

[root@centos ipv4]# tcpdump -i eth0 -n src 39.89.53.61 and port 80
13:41:35.421132 IP 39.89.53.61.54940 > 10.0.8.15.http: Flags [S], seq 1603668167, win 64240, options [mss 1404,nop,wscale 8,nop,nop,sackOK], length 0
13:41:36.440757 IP 39.89.53.61.54940 > 10.0.8.15.http: Flags [S], seq 1603668167, win 64240, options [mss 1424,nop,wscale 8,nop,nop,sackOK], length 0
13:41:38.421645 IP 39.89.53.61.54940 > 10.0.8.15.http: Flags [S], seq 1603668167, win 64240, options [mss 1424,nop,wscale 8,nop,nop,sackOK], length 0

可以看到设置超时3秒后,重试第一次和第二次加起来用了3秒,客户端超时后结束,抓包也不再打印内容。

2020-08-24
发表者 Venus
backlog全连接队列和半连接队列已关闭评论

backlog全连接队列和半连接队列

[root@localhost ~]# man listen 查看listen方法的文档

名称:
listen – listen for connections on a socket 在一个套接字上倾听连接

概述:
#include <sys/socket.h>
int listen(int s, int backlog);

描述:
在接收连接之前,首先要使用 socket(2) 创建一个套接字,然后调用 listen 使其能够自动接收到来的连接并且为连接队列指定一个长度限制.
之后就可以使用 accept(2) 接收连接. listen 调用仅适用于 SOCK_STREAM 或者 SOCK_SEQPACKET 类型的套接字.

参数 backlog 指定未完成连接队列的最大长度.如果一个连接请求到达时未完成连接 队列已满,那么客户端将接收到错误 ECONNREFUSED.
或者如果下层协议支持重发,那么这个连接请求将被忽略,这样客户端在重试的时候就有成功的机会.

注意:
在TCP套接字中 backlog 的含义在Linux 2.2中已经改变.它指定了已经完成连接正等待应用程序接收的套接字队列的长度,而不是未完成连接的数目.
未完成连接套接字队列 (半连接,SYN_RCVD状态) 的最大长度可以使用 /proc/sys/net/ipv4/tcp_max_syn_backlog 或者 sysctl 中设置
当打开syncookies时不存在逻辑上的最大长度,此设置将被忽略.参见 tcp(7) 以获取更多信息.

也就是说 backlog 是限制处于 全连接,ESTABLISHED(已完成三次握手) 状态但未由应用程序处理的队列值。

# 查看某个服务的backlog值,比如python写的socket服务,端口为1111

[root@localhost ~]# ss -ln | grep -E "1111|Netid"
Netid   State    Recv-Q   Send-Q   Local Address:Port   Peer Address:Port                                                                            
tcp     LISTEN   0        128      0.0.0.0:1111         0.0.0.0:*   

通过 Send-Q 列可以看到1111端口服务的backlog值为128,也就是默认系统的值。

[root@localhost ~]# cat /proc/sys/net/core/somaxconn
128

当然,这个值可以通过 sysctl.conf 中添加配置进行修改。

net.core.somaxconn=1024

(somaxconn 推测是 socket max connection 缩写)

# python 服务端代码
import socket

ADDRESS = ('0.0.0.0', 1111)
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
socket.bind(ADDRESS)
socket.listen(10)

如果在socket编程中,设置listen() 值为10,那么再次查看会变为10

[root@localhost ~]# ss -ln | grep -E "1111|Netid"
Netid   State    Recv-Q   Send-Q   Local Address:Port   Peer Address:Port                                                                            
tcp     LISTEN   0        10       0.0.0.0:1111         0.0.0.0:*   

注意:socket.listen()方法中的值和内核参数/proc/sys/net/core/somaxconn中的值会取最小值做为最大队列长度。

# 查看指定服务当前已用的队列数
上面的Recv-Q列,当state状态为LISTEN时,为已建立的全连接大小。

注意: ss 命令获取的 Recv-Q/Send-Q 在「LISTEN 状态」和「非 LISTEN 状态」所表达的含义是不同的
在ss -nt时,两列含义:
Recv-Q 连接此套接字的用户程序未拷贝的字节数。
Send-Q 远程主机未确认的字节数。

# 查看半连接队列数
半连接队列没有什么命令可以直接看,不过可以通过netstat计算SYN_RECV数量

[root@localhost ~]# netstat -antp | grep SYN_RECV | wc -l

半连接丢弃的3个条件,并不是单纯由max_syn_backlog 参数决定,可参考:https://www.toutiao.com/i6833215977505686028
1、如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
2、若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
3、如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;
>> 符号为c语言里的位移

2020-08-21
发表者 Venus
mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `xxx` at row: xxx已关闭评论

mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `xxx` at row: xxx

mysqldump备份时提示错误 Lost connection to MySQL server during query

# 查看超时参数

mysql> show global variables like '%timeout%';
可以看到下面2个参数的默认值
net_read_timeout 默认值 30
net_write_timeout 默认值 60

这2个参数的含义可以从  https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_net_read_timeout  查看。

# 解决方法,增大这2个参数的值:

mysql> set global net_read_timeout = 300; 
Query OK, 0 rows affected (0.03 sec)

mysql> set global net_write_timeout = 600;
Query OK, 0 rows affected (0.00 sec)

再次备份不报错了。