我的 LAN 上的 Web 服务器出现了一个奇怪的问题。HTTP 请求一直在运行,但没有给出有意义的错误代码。
这个问题发生在我的华硕路由器和思科路由器上,但奇怪的是,它并没有发生在我的旧 DLink 路由器上。下面分析一下两者的区别。
[2 月 19 日晚上 10:30 更新] 我尝试从 Apache 切换到 Nginx 服务器(基于 Kevin 的评论),它们显示的结果相同。似乎是与服务器无关的 TCP 数据包问题(请参阅下面的 tcpdump)。我还试验了 TCP 数据推送大小,发现失败的概率随着请求大小而下降。当小于 ~800 字节时,它在循环 5-10 次后设法加载大约一半的时间,然后才获得罕见的 ACK。在 ~2000 字节时,它很少但有时有效。在 ~6000 字节时,没办法。DLink 路由器可以立即处理任何这些文件大小。我检查过是否有任何干扰数据包来自环回接口,但那里没有。我切换了电缆/端口(但没有切换 NIC,只有一个)。
我尝试使用 telnet 对一个简单页面进行手动 HTTP 请求:
telnet 192.168.0.101 80
GET /index.html HTTP/1.0
那里出现了相同的问题,挂了几秒钟。
Netstat 输出:
simon@fire:~$ sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1056/sshd
tcp 0 0 0.0.0.0:23 0.0.0.0:* LISTEN 1147/xinetd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1482/sendmail: MTA:
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1064/mysqld
tcp 0 0 127.0.0.1:587 0.0.0.0:* LISTEN 1482/sendmail: MTA:
tcp6 0 0 :::21 :::* LISTEN 1066/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1056/sshd
tcp6 0 0 :::80 :::* LISTEN 1234/apache2
关闭 Apache 并尝试 netcat 立即在同一端口上运行:
simon@fire:~$ sudo service apache2 stop
simon@fire:~$ { echo -ne "HTTP/1.0 200 OK\r\nContent-Length: 13\r\n\r\n"; echo "Hello World!"; } | sudo nc -l 80
GET / HTTP/1.1
Host: 192.168.0.101
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
(On client --> Works immediately)
tcpdump 转储似乎表明 Push 数据包后缺少“ACK 2921”数据包。然后服务器重复 Push 数据包,仍然没有 ACK。然后它继续执行一系列 seq 1:1461 ACK,然后完成 F 数据包,似乎放弃了。
我不是 tcp 数据包方面的专家,但这是通过分析失败案例(ASUS 路由器)与成功案例(Dlink 路由器)得出的。在 DLink 上,有一个清晰的 ACK 2921 数据包。在此之前,两者显示的输出相同。
一个明显的区别是,使用 DLink 时,服务器通过其 IP(192.168.0.104)查看客户端,而在 ASUS 上,服务器通过其主机名(Gin)查看客户端 - 但对第三个路由器(Cisco)进行实验排除了这是问题的一部分,因为它也通过 IP 查看客户端,但在其他方面表现与 ASUS 相同。
simon@fire:~$ sudo tcpdump -i eth0 port 80 or port 443
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
19:43:37.815448 IP Gin.60309 > fire.http: Flags [S], seq 4284943091, win 8192, options [mss 1460,nop,wscale 2,nop,nop,sackOK], length 0
19:43:37.815490 IP fire.http > Gin.60309: Flags [S.], seq 1854464822, ack 4284943092, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
19:43:37.815684 IP Gin.60309 > fire.http: Flags [.], ack 1, win 16425, length 0
19:43:37.816701 IP Gin.60309 > fire.http: Flags [P.], seq 1:344, ack 1, win 16425, length 343: HTTP: GET / HTTP/1.1
19:43:37.816729 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, length 0
19:43:37.818341 IP fire.http > Gin.60309: Flags [.], seq 1:2921, ack 344, win 237, length 2920: HTTP: HTTP/1.1 200 OK
19:43:37.818357 IP fire.http > Gin.60309: Flags [P.], seq 2921:4155, ack 344, win 237, length 1234: HTTP
-- There seems to be a missing [.] ack 2921 packet here!? Then the server tries again --
19:43:37.827311 IP fire.http > Gin.60309: Flags [P.], seq 2921:4155, ack 344, win 237, length 1234: HTTP
19:43:38.051329 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:38.499322 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:39.395318 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:41.191327 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:42.823524 IP fire.http > Gin.60309: Flags [F.], seq 4155, ack 344, win 237, length 0
19:43:42.823736 IP Gin.60309 > fire.http: Flags [.], ack 1, win 16425, length 0
19:43:44.783318 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:51.967338 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:43:52.825832 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:43:52.825875 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:44:02.826426 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:44:02.826464 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:44:06.335330 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:44:12.827029 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:44:12.827067 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:44:22.827563 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:44:22.827592 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:44:32.828133 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:44:32.828157 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:44:35.039322 IP fire.http > Gin.60309: Flags [.], seq 1:1461, ack 344, win 237, length 1460: HTTP: HTTP/1.1 200 OK
19:44:42.828692 IP Gin.60309 > fire.http: Flags [.], seq 343:344, ack 1, win 16425, length 1: HTTP
19:44:42.828734 IP fire.http > Gin.60309: Flags [.], ack 344, win 237, options [nop,nop,sack 1 {343:344}], length 0
19:45:08.571555 IP Gin.60309 > fire.http: Flags [F.], seq 344, ack 1, win 16425, length 0
19:45:08.571581 IP fire.http > Gin.60309: Flags [.], ack 345, win 237, length 0
(Pressed CTRL C after 30 seconds)
^C
32 packets captured
32 packets received by filter
0 packets dropped by kernel
使用 DLink 路由器(工作正常)时的 tcpdump 场景如下:
simon@fire:/sbin$ sudo tcpdump -B 4096 -i eth0 port 80 or port 443
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:48:20.209920 IP 192.168.0.104.53696 > fire.http: Flags [S], seq 1043812686, win 8192, options [mss 1460,nop,wscale 2,nop,nop,sackOK], length 0
21:48:20.209954 IP fire.http > 192.168.0.104.53696: Flags [S.], seq 639467520, ack 1043812687, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
21:48:20.210290 IP 192.168.0.104.53696 > fire.http: Flags [.], ack 1, win 16425, length 0
21:48:20.211575 IP 192.168.0.104.53696 > fire.http: Flags [P.], seq 1:344, ack 1, win 16425, length 343: HTTP: GET / HTTP/1.1
21:48:20.211603 IP fire.http > 192.168.0.104.53696: Flags [.], ack 344, win 237, length 0
21:48:20.213190 IP fire.http > 192.168.0.104.53696: Flags [.], seq 1:2921, ack 344, win 237, length 2920: HTTP: HTTP/1.1 200 OK
21:48:20.213199 IP fire.http > 192.168.0.104.53696: Flags [P.], seq 2921:4155, ack 344, win 237, length 1234: HTTP
21:48:20.213959 IP 192.168.0.104.53696 > fire.http: Flags [.], ack 2921, win 16425, length 0
21:48:20.415317 IP fire.http > 192.168.0.104.53696: Flags [P.], seq 2921:4155, ack 344, win 237, length 1234: HTTP
21:48:20.416066 IP 192.168.0.104.53696 > fire.http: Flags [.], ack 4155, win 16116, options [nop,nop,sack 1 {2921:4155}], length 0
21:48:25.215387 IP fire.http > 192.168.0.104.53696: Flags [F.], seq 4155, ack 344, win 237, length 0
21:48:25.215864 IP 192.168.0.104.53696 > fire.http: Flags [.], ack 4156, win 16116, length 0
21:48:25.216086 IP 192.168.0.104.53696 > fire.http: Flags [F.], seq 344, ack 4156, win 16116, length 0
21:48:25.216093 IP fire.http > 192.168.0.104.53696: Flags [.], ack 345, win 237, length 0
^C
14 packets captured
14 packets received by filter
0 packets dropped by kernel
我还检查了防火墙,发现没有数据包符合“拒绝”规则,并且还执行了推荐的 iptables 命令,但没有帮助:/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT
ifconfig 输出:
eth0 Link encap:Ethernet HWaddr 00:16:e6:85:ad:a1
inet addr:192.168.0.101 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::216:e6ff:fe85:ada1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4660 errors:0 dropped:2 overruns:0 frame:0
TX packets:1769 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:399847 (399.8 KB) TX bytes:210999 (210.9 KB)
Interrupt:17
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:47 errors:0 dropped:0 overruns:0 frame:0
TX packets:47 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:15869 (15.8 KB) TX bytes:15869 (15.8 KB)
iptables 输出:
~$ sudo iptables -L -n
Chain INPUT (policy DROP)
target prot opt source destination
f2b-sshd tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 22
ufw-before-logging-input all -- 0.0.0.0/0 0.0.0.0/0
ufw-before-input all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-input all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-logging-input all -- 0.0.0.0/0 0.0.0.0/0
ufw-reject-input all -- 0.0.0.0/0 0.0.0.0/0
ufw-track-input all -- 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy DROP)
target prot opt source destination
ufw-before-logging-forward all -- 0.0.0.0/0 0.0.0.0/0
ufw-before-forward all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-forward all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-logging-forward all -- 0.0.0.0/0 0.0.0.0/0
ufw-reject-forward all -- 0.0.0.0/0 0.0.0.0/0
ufw-track-forward all -- 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ufw-before-logging-output all -- 0.0.0.0/0 0.0.0.0/0
ufw-before-output all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-output all -- 0.0.0.0/0 0.0.0.0/0
ufw-after-logging-output all -- 0.0.0.0/0 0.0.0.0/0
ufw-reject-output all -- 0.0.0.0/0 0.0.0.0/0
ufw-track-output all -- 0.0.0.0/0 0.0.0.0/0
Chain f2b-sshd (1 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-after-forward (1 references)
target prot opt source destination
Chain ufw-after-input (1 references)
target prot opt source destination
ufw-skip-to-policy-input udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:137
ufw-skip-to-policy-input udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:138
ufw-skip-to-policy-input tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:139
ufw-skip-to-policy-input tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:445
ufw-skip-to-policy-input udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:67
ufw-skip-to-policy-input udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:68
ufw-skip-to-policy-input all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type BROADCAST
Chain ufw-after-logging-forward (1 references)
target prot opt source destination
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "
Chain ufw-after-logging-input (1 references)
target prot opt source destination
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "
Chain ufw-after-logging-output (1 references)
target prot opt source destination
Chain ufw-after-output (1 references)
target prot opt source destination
Chain ufw-before-forward (1 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 3
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 4
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 11
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 12
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 8
ufw-user-forward all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-before-input (1 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ufw-logging-deny all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 3
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 4
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 11
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 12
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmptype 8
ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp spt:67 dpt:68
ufw-not-local all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT udp -- 0.0.0.0/0 224.0.0.251 udp dpt:5353
ACCEPT udp -- 0.0.0.0/0 239.255.255.250 udp dpt:1900
ufw-user-input all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-before-logging-forward (1 references)
target prot opt source destination
Chain ufw-before-logging-input (1 references)
target prot opt source destination
Chain ufw-before-logging-output (1 references)
target prot opt source destination
Chain ufw-before-output (1 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ufw-user-output all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-logging-allow (0 references)
target prot opt source destination
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW ALLOW] "
Chain ufw-logging-deny (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID limit: avg 3/min burst 10
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "
Chain ufw-not-local (1 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
RETURN all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type MULTICAST
RETURN all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type BROADCAST
ufw-logging-deny all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 10
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-reject-forward (1 references)
target prot opt source destination
Chain ufw-reject-input (1 references)
target prot opt source destination
Chain ufw-reject-output (1 references)
target prot opt source destination
Chain ufw-skip-to-policy-forward (0 references)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-skip-to-policy-input (7 references)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-skip-to-policy-output (0 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-track-forward (1 references)
target prot opt source destination
Chain ufw-track-input (1 references)
target prot opt source destination
Chain ufw-track-output (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW
ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW
Chain ufw-user-forward (1 references)
target prot opt source destination
Chain ufw-user-input (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 /* 'dapp_Nginx%20Full' */
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 /* 'dapp_Nginx%20HTTP' */
Chain ufw-user-limit (0 references)
target prot opt source destination
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 3/min burst 5 LOG flags 0 level 4 prefix "[UFW LIMIT BLOCK] "
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain ufw-user-limit-accept (0 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
Chain ufw-user-logging-forward (0 references)
target prot opt source destination
Chain ufw-user-logging-input (0 references)
target prot opt source destination
Chain ufw-user-logging-output (0 references)
target prot opt source destination
Chain ufw-user-output (1 references)
target prot opt source destination
如果我尝试从端口 80 上的服务器访问互联网,也会发生类似的问题(非常慢、旋转或有时需要很长时间才能加载一个简单的页面)。
这是一个 LAMP 服务器(Ubuntu 16.4)。
提前致谢!
答案1
您是否尝试过在服务器上运行 tcpdump?
sudo tcpdump -i eth0 port 80 or port 443
如果您没有看到数据包,您可能需要仔细检查您的防火墙。
您还可以关闭 apache 并在端口 80 上运行临时的 netcat 网络服务器
{ echo -ne "HTTP/1.0 200 OK\r\nContent-Length: 13\r\n\r\n"; echo "Hello World!"; } | sudo nc -l 80
编辑:
您可以使用 tcpdump 写入文件,然后使用 wireshark 在客户端计算机上传输并打开它,以查看数据包中传输的信息。
sudo tcpdump -i eth0 port 80 or port 443 -w httpdebug.pcap
然后将该文件复制到装有 wireshark 的机器上。如果您需要在 Windows 机器上安装 wireshark,则可以跳过安装 winpcap。
您可以尝试其他一些步骤:
- 让 apache 提供一个只包含“Hello World!”或者一些很短内容的文件。
- 使用 netcat 网络服务器尝试托管您的 index.html
{ echo -ne "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <index.html)\r\n\r\n"; cat index.html; } | sudo nc -l 80
如果后者有效,则可能是存在大量渲染阻塞内容或 Apache 中的某些配置错误。我会尝试清除并重新安装 Apache,而不是搜索配置问题。
答案2
根据sudo netstat -lntp
输出,您apache
的设置没有监听 IPv4。
您需要在 apache 的配置中添加:
#NameVirtualHost *:80
Listen 0.0.0.0:80
如果您要在网站上使用 SSL 协议,则还请添加:
<IfModule ssl_module>
# NameVirtualHost *:443
Listen 0.0.0.0:443
</IfModule>
<IfModule mod_gnutls.c>
# NameVirtualHost *:443
Listen 0.0.0.0:443
</IfModule>
这些设置适用于 Apache 2.4 及以上版本。如果您使用 2.2 版本,则还需添加
NameVirtualHost *:80
NameVirtualHost *:443
在(apache|httpd|ports)\.conf