标签归档:nginx

nginx 升级后访问400 BAD REQUEST增多的问题

一些旧设备访问nginx的时候可能会出现400 bad request, 这个跟2020.2月nginx移除了一个兼容特性有关

Disabled duplicate “Host” headers (ticket #1724). Duplicate “Host” headers were allowed in nginx 0.7.0 (revision b9de93d804ea) as a workaround for some broken Motorola phones which used to generate requests with two “Host” headers[1]. It is believed that this workaround is no longer relevant.

新增的这块代码如下: 会判断是否有重复的host 头, 而在之前的版本是认为可以容忍的

这个兼容特性被移除后, 会导致一些旧版本的移动设备响应异常

而我们线上测试机器主要是兼容了spdy协议, 也出现了400 BAD REQUEST, 这个跟spdy代码里边本身进行了一遍header处理有关:

可以参考:

https://hg.nginx.org/nginx/rev/4f18393a1d51

http://mailman.nginx.org/pipermail/nginx-devel/2020-February/012999.html

nginx 生成coredump的办法

网上很多说nginx生成coredump的办法在RHEL7 RHEL8都无法正确的生成core 文件, 这里给一下正确的步骤

#新建一个文件夹, 并确认nginx可以读写
$ mkdir /opt/itc/fssnginx/logs/cores/
$ sudo chown root:root /opt/itc/fssnginx/logs/cores/
$ sudo chmod 1777 /opt/itc/fssnginx/logs/cores/

#设置unlimited core file dump
$ ulimit -c unlimited
#也可以在系统中彻底修改
$vim /etc/security/limits.conf
* soft core unlimited

#设置系统级别的core file
$ echo "/opt/itc/fssnginx/logs/cores/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern

#允许suid dumpable
$ sudo sysctl -w fs.suid_dumpable=2

$ sysctl -p


#重启nginx
systemctl restart nginx
#编译nginx.conf,然后重启nginx 服务
working_directory  /opt/itc/fssnginx/logs/cores/;
worker_rlimit_core 500M;

测试,找到nginx workprocess的进程号,发送 SIGSEGV  给该work process进程

$ps aux|grep nginx
$kill -11 `$work_process_pid`
#检查core 文件
$ll /opt/itc/fssnginx/logs/cores/
-rw-------. 1 nobody nobody 65753088 Jun 22 17:54 core.nginx.5662
-rw-------. 1 nobody nobody 70475776 Jun 22 18:03 core.nginx.5702

释疑: 看起来跟内核变量有关

#旧版本RHEL6是这个设置:

kernel.core_pattern = core

#新版本OS 是这个: 会被通过管道发给这个可执行命令

kernel.core_pattern = |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e

参考文档:

https://docs.nginx.com/nginx/admin-guide/monitoring/debugging/

nginx spdy patch for 1.14.0 1.13.12

spdy 协议由于安卓碎片化的存在 暂时还是需要保留一段时间的兼容性

准备升级到nginx1.14的时候发现 work process 会自动 退出, 同时系统日志有 nginx segfault的信息

修改配置,抓取coredump信息,需要做以下内容
nginx 增加

worker_rlimit_core 5000M;
working_directory /path/to/cores/;
$> ulimit -c unlimited
$> mkdir /opt/coredump/ && chown nobody.nobody /opt/coredump/ # 先建目录,还要确认nginx用户可以写此目录
$> echo “/opt/coredump/core-%e-%p-%h-%t” > /proc/sys/kernel/core_pattern

拿到coredump文件后使用gdb分析

gdb /path/to/nginx /path/to/cores/nginx.core
backtrace full

发现问题指向了
src/http/ngx_http_spdy.c:ngx_http_spdy_state_read_data 的
buf->last = ngx_cpymem(buf->last, pos, size);

简单调试发现buf->last是个0, ngx_cpymem会因为内存越界导致coredump

而分析代码 + gdb 断点调试 看到初始化r->request_body->buf的部分: ngx_http_spdy_init_request_body(r) 并未执行

打印r->request_body 内容发现这块被初始化了,对比nginx1.12.2和1.10.3版本发现旧版本则是未做初始化

翻了下调用的部分:ngx_http_request_body: ngx_http_read_client_request_body 可以看到在nginx 1.13.12版本开始会对r->request_body 做了初始化操作,这部分直接导致了SPDY 补丁 的不兼容

所以答案就很简单了,修改下判断条件即可

新补丁放在了:https://github.com/favortel/nginx_patch/blob/master/nginx-1.14.0_spdy_h2.patch
参考文档:
https://toontong.github.io/blog/nginx-gdb-coredump-segfault.html
https://www.nginx.com/resources/wiki/start/topics/tutorials/debugging/
http://lxr.nginx.org/source/src/http/ngx_http_request_body.c
http://lxr.nginx.org/source/src/http/ngx_http_request_body.c?v=nginx-1.12.2