分类目录归档:linux

edns 与 8.8.8.8 DNS Cache

测试bind-9.8.1-P1 的edns的时候发现,google DNS解析的结果一直在跳,有时候在电信区,有时候在us区

于是给它打了第一个patch,让query log 支持edns的client subnet显示,便于排查

筛选下日志,发现很多edns请求不在我们的ecs ACL范围内,最终落到了google DNS IP 所在的us区域,推测应该是这个造成了google DNS 的错误缓存

于是,把ecs的default区域加入拦截

view "default_ecs" {
match-clients { ecs 0.0.0.0/0; ecs ::/0;};
... ...
};

这样一来,的确是响应了edns请求,结果却是更多的出现了default 区的结果(热数据),或者在client所属区域和default区结果之间跳动(冷数据)

听包,发现google DNS发送过来的请求Scope Netmask 都是0,如果ecs ACL拦截不成功到了default_ecs区域,最终被ecs 0.0.0.0/0; ecs ::/0; 拦截成功,导致返回的Scope Netmask变成了0

Scope Netmask 变为0意味着什么? 意味着这个结果集有效并且范围最大,从而污染所有的subnet client结果集

目前来看,只能给它打个patch

让client subnet 到了default区域的结果集Scope Netmask 为起address netmask长度,控制结果集的有效范围

测试下,把某个网段故意从ecs ACL挪走,让default ecs拦截看看响应是否是我们期待的

正常网段的请求,返回我们ecs ACL的Netmask

上线测试,目前服务正常

 

附上edns 文档,非常重要: 
https://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-01
http://noops.me/?p=653

nginx proxy模式下502 bad gateway 问题

并发测试的时候发现nginx 502 bad gateway 了,看了下日志发现很多upstream Cannot assign requested address的记录
connect() to 192.168.89.170:80 failed (99: Cannot assign requested address) while connecting to upstream

正常判断应该是端口不够用了
不过,我确实开启了: net.ipv4.tcp_tw_recycle = 1 和 net.ipv4.tcp_tw_reuse = 1两个参数
理论上应该可以把timewait 端口重用,查了下这个参数跟tcp_timestamps有关(http://blog.sina.com.cn/s/blog_781b0c850100znjd.html)

if (tmp_opt.saw_tstamp &&
tcp_death_row.sysctl_tw_recycle &&
(dst = inet_csk_route_req(sk, req)) != NULL &&
(peer = rt_get_peer((struct rtable *)dst)) != NULL &&
peer->v4daddr == saddr) {
if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
(s32)(peer->tcp_ts – req->ts_recent) >
TCP_PAWS_WINDOW) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
goto drop_and_release;
}
}

tmp_opt.saw_tstamp:该socket支持tcp_timestamp
sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内
TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp

因此: 应该在proxy端和后端都开启net.ipv4.tcp_timestamps=1

网卡LACP聚合配置

本文主要介绍多网卡lacp 聚合模式配置,即mode=4模式下RHEL6 bonding 和 RHEL7 team的配置

此模式需要在交换机做配置LACP聚合,具体参考交换机设置
配置范例以双网卡eth0 eth1为例,多网卡类推

RHEL6 配置

1.新增配置文件/etc/modprobe.d/bonding.conf,内容如下

alias bond0 bonding
options bond0 miimon=100 mode=4 lacp_rate=1 xmit_hash_policy=layer3+4

2.更改网卡配置

#/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
USERCTL=no

#/etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
USERCTL=no

#/etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
USERCTL=no
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.233
NETMASK=255.255.255.0
NETWORK=192.168.1.0
GATEWAY=192.168.1.254

3.重启网络

service network restart

4.注意点: 参见最后附录

 

RHEL7 配置

1. 修改网卡配置

# /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=”eth0″
ONBOOT=yes
UUID=”原来的UUID”
DEVICETYPE=TeamPort
TEAM_MASTER=team1

#/etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
DEVICETYPE=TeamPort
UUID=”原来的UUID”
ONBOOT=yes
TEAM_MASTER=team1

新增配置: /etc/sysconfig/network-scripts/ifcfg-team1
DEVICE=team1
DEVICETYPE=Team
ONBOOT=yes
BOOTPROTO=none
IPADDR=192.168.1.23
PREFIX=24
DEFROUTE=no
TEAM_CONFIG='{“runner”: {“name”:”lacp”, “active”:true, “fast_rate”:true, “tx_hash”:[“ipv4”], “ports”:{“eth0”:{}, “eth1”:{}}}}’
MTU=1476

2. 重新启动机器,是的,重新启动机器

问题研究

 
1. RHEL6网卡in能分摊到不同网卡,但是out只走一个网卡
检查/proc/net/bonding/bond0 文件,看看 Transmit Hash Policy 是否正确,一般layer2 在内网测试可能会有问题
需要配置xmit_hash_policy=layer3+4 或者 xmit_hash_policy=layer2+3

2. RHEL7 systetemctl restart network 网卡不通
恩,是的,重启机器吧

HP 380G5 安装RHEL7 找不到磁盘

安排一位同学做Docker测试的时候,用的是台380G5的老机器,结果发现找不到磁盘

那位同学搜了下,是驱动被移除了,HP官方不再支持在新OS下的测试,需要显式打开支持

在kernel 引导时加入 hpsa.hpsa_allow_any=1 就可以了

相关文档:
http://serverfault.com/questions/611182/centos-7-x64-and-hp-proliant-dl360-g5-scsi-controller-compatibility
https://www.kernel.org/doc/Documentation/scsi/hpsa.txt

nginx with static libcurl

场景是这样子的: 这边有个nginx 模块 include curl/curl.h,而我的编译参数–with-openssl使用了最新的openssl 1.0.1g,编译出来的nginx直接segfault

去除这个模块或者去掉–with-openssl都能正常使用,推测是系统的libcurl(https)包含了libssl的依赖,与内嵌的openssl产生冲突

于是解决办法就是把libcurl也编译到nginx里边,绕开冲突和依赖

1. 静态编译libssl
cd openssl-1.0.1g
./config –prefix=/usr/src/redhat/BUILD/nginx-1.4.7/openssl-1.0.1g/.openssl no-shared no-threads
make
make install
make install LIBDIR=lib

2. 静态编译libcurl
cd curl-7.36.0
./configure –prefix=/usr/src/redhat/BUILD/nginx-1.4.7/curl-7.36.0/.curl –with-ssl=/usr/src/redhat/BUILD/nginx-1.4.7/openssl-1.0.1g/.openssl/lib/ –disable-ldap –disable-ldaps –without-libidn –enable-static=yes –enable-shared=no

#去除对librt.so的依赖,不介意可以不修改
sed -i /HAVE_CLOCK_GETTIME_MONOTONIC/d lib/curl_config.h

make
make install

3. 修改nginx的Makefile
#替换libcurl.so(lcurl)为静态编译的libcurl.a
sed -i ‘s#-lcurl#curl-7.36.0/.curl/lib/libcurl.a -Lopenssl-1.0.1g/.openssl/lib -lcrypto -lz#g’ objs/Makefile
make
make install

做完这步,就生成了包含libcurl和libssl的nginx了

一次错误mv /* /path/to 操作的恢复

一次错误mv /* /path/to 操作的恢复

描述:执行mv命令的时候没有注意路径,结果把根目录下的大部分目录都挪到了一个新路径中,然后立即
出错命令不能继续,因为 /lib已经被挪走了,/lib下保存有最基本的系统运行库,现代的linux系统大多
数命令已经动态连接了,当/lib路径改变的时候,那你能用来创建目录,或用来copy文件的任何命令,都
不好用了,都会报下面错误:
/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
这表示已经找不到ld-linux.so.2这个文件了

由于文件都已经被挪走了,我们平时依赖的工具都不好用了。即使你敲入绝对路径,也会提示:
/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory这个错误
尝试了下面的命令
/www/users/abcdefg.net/{ls,ln,mkdir,mktemp,ftp,rsync,mv,cp,rm,ldconfig,scp,sftp,perl,ash,zsh,csh} 报的都是上面的错误,
常规的创建文件,创建目录和目录文件转移操作,及远程或本地复制文件操作都无法进行了。
再尝试找下好用的命令:
cd export declare echo > 这些内置命令都是好用的。

我们看下现场,由于ls已经不好用了。那只好用bash的自动补齐功能(TAB键)来看看有哪些目录和文件
首先检查哪些目录被挪走了,执行下面命令:
/www/users/abcdefg.net [按TAB]
输出如下:
backup bin boot dev ecshop etc home lib lost+found media misc mnt opt proc www_logs ucenter
可以看出 bin和lib都已经被挪过来了,那我们既不能直接执行bin下的程序,也不能执行任何依赖/lib下的程序,而且etc也被mv到这里来
所以我们连修改ld.so.conf并生成新的ld.so.cache的机会也没有,因为我们无法执行创建/etc目录的命令。

开始恢复吧
过程不复杂,我们还有ld-linux.so.2 可用,虽然它已经变了位置。
ld-linux.so.2是linux系统的动态连接器,我们可以用他来执行命令,我们使用它的–library-path参数来重新指定LD_LIBRARY_PATH的位置

再看看根目录还有啥
/www/users/abcdefg.net/lib/ld-linux.so.2 –library-path /www/users/abcdefg.net/lib /www/users/abcdefg.net/bin/ls / -F
输出正常,

恢复/lib
/www/users/abcdefg.net/lib/ld-linux.so.2 –library-path /www/users/abcdefg.net/lib /www/users/abcdefg.net/bin/cp -rfp /www/users/abcdefg.net/lib /lib

恢复/bin
/www/users/abcdefg.net/lib/ld-linux.so.2 –library-path /www/users/abcdefg.net/lib /www/users/abcdefg.net/bin/cp -rfp /www/users/abcdefg.net/bin /bin

恢复其他目录
cd /www/users/abcdefg.net
for i in bin boot etc lib media misc mnt opt ; do rsync -av –progress ./$i/ /$i/; done

然后我们再还原dev目录
cd dev
cp -dRp * /dev

重新检查ssh登陆,此时已经能登陆系统了,仔细检查/boot /etc ,都已经正确恢复,重起系统,所有恢复完毕

nginx lua 模块的一个bug

近期协助排查一个故障发现有50x错误,开error日志发现有malloc或者crash work process的记录

[emerg] 5309#0: *288 malloc(808334101) failed (12: Cannot allocate memory) while sending to client
[notice] 4579#0: signal 18 (SIGCHLD) received
[notice] 4579#0: worker process 5211 exited with code 0

这其实是lua模块导致的问题,在0.7.5之前,nginx lua module存在 ngx.req.clear_header 导致的内存溢出问题,需要升级到最新版
that is all,完毕

nginx gunzip filter 模块

介绍下igor职业打手Maxim Dounin写的一个gunzip模块

Gunzip module for nginx.
This module allows gunzipping responses returned with Content-Encoding: gzip
for clients that doesn’t support it. It may be usefull if you prefer to store
data compressed (to save space or disk/network IO) but do not want to penalize
clients without gzip support.

Note well: only responses with Content-Encoding set to gzip before this module
are handled (e.g. using “add_header Content-Encoding gzip;” isn’t enough as it
happens after). As of now only proxy and fastcgi are able to do so.

这个模块能针对不支持gzip编码的客户端,直接解压gzip格式的内容
好处:
1.跟源站直接请求压缩的内容,减少回源带宽,提高响应速度
2.只保留一份压缩的内容,减少缓存的大小,相同的cache能放更多的内容
配置格式比较简单:

Configuration directives:

gunzip (on|off)

Context: http, server, location
Default: off

Switches gunzip.

gunzip_buffers

Context: http, server, location
Default: 32 4k/16 8k

Specifies number and size of buffers available for decompression.

Usage:

location /storage/ {
gunzip on;

}

需要特别指出:
1.客户端不支持gzip编码,那么gunzip模块就返回解压的内容
2.客户端支持gzip编码,那么gunzip就自动不起作用,返回原始内容

某些特殊需求,比如addition_filter,我们知道这些filter在非压缩的内容才能正常工作,要结合这个模块就不是那么方便了
因此可以简单修改代码,让它不理会客户端的header,总是返回非压缩内容,注释掉这一整块即可:
ngx_http_gunzip_filter_module.c

141 #if (nginx_version >= 8025 || (nginx_version >= 7065 && nginx_version < 8000)) 142 143 r->gzip_vary = 1;
144
145 if (!r->gzip_tested) {
146 if (ngx_http_gzip_ok(r) == NGX_OK) {
147 return ngx_http_next_header_filter(r);
148 }
149
150 } else if (!r->gzip_ok) {
151 return ngx_http_next_header_filter(r);
152 }
153
154 #else
155
156 if (ngx_http_gzip_ok(r) == NGX_OK) {
157 return ngx_http_next_header_filter(r);
158 }
159
160 #endif

有人写了个gunzip_always的开关补丁,可以控制这个属性,patch暂时不放出来

模块地址: http://mdounin.ru/hg/ngx_http_gunzip_filter_module/

nginx ssl https 设置

本文已经过时并且存在大量不安全,请参阅最新文档   https://www.4os.org/index.php/category/https/
nginx 默认编译就是支持https的,只需要开启ssl就好
配置如下:
                listen                  443 ;
                server_name             4os.org *.4os.org;

                ssl                     on;
                ssl_certificate         gz.crt;
                ssl_certificate_key     gz.key;
                ssl_session_timeout     5m;
                ssl_protocols           SSLv2 SSLv3 TLSv1;
                ssl_ciphers             ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
                ssl_prefer_server_ciphers       on;
....

其中:
gz.crt是证书颁发机构给的证书(免费ssl-证书/)
gz.key是解密后的私钥

上文中提到的私钥是加密的,可以在startssl的工具箱里边解密,也可以自己做:

openssl  rsa -in gz.pri -out gz.key,输入私钥生成时设置的密码,出来的就是不加密的私钥了,nginx启动也不会要你输入密码了

补充:

1. “SSL_CTX_use_PrivateKey_file fail”之类的错误,通常都是私钥和证书不匹配造成的,请确认你生成证书与私钥匹配

2.firefox证书需要根证书信息:

wget http://www.startssl.com/certs/sub.class1.server.ca.pem

cat sub.class1.server.ca.pem >> gz.crt

免费SSL 证书

不再推荐 startssl,推荐 let’s encrypt, 请参考文章免费HTTPS证书

一般来说,开启https服务总会涉及到证书问题,通常自签发的证书在浏览器会有”鲜红告警”,而CA的证书又颇贵
https://www.startssl.com/ 是一个免费的证书提供商,并支持ie,firefox,chrome等主流浏览器

1.注册,点击右上角的钥匙

选择sign-up,并输入要求填写的所有信息,由于是人工审核,请谨慎填写(必须是私人地址)

2. 注册成功后会收到封邮件(建议留gmail),点击链接会安装一份证书,以后就可以凭证书自动登录该网站了(上图Auth…)

3. 登录后到控制面板,有3个框:分别是工具箱/证书向导/验证向导

先点验证向导(validations wizard),分别验证邮箱和域名(确认该域名属于你,系统一般会发信给域名的postmaster或者你注册域名时留的邮箱)

4. 证书向导,点Certificats wizard,选择web Server SSL证书,下一步

5. 输入私钥的密码,请特别留意密码你清楚记得

6. 然后系统会提示你保存加密私钥(你稍后可以在工具箱里边解密之,不要现在做,请确认保存该密钥),下一步选择域名和子域名申请证书

7. 提交申请,稍等个大概10分钟,会收到邮件提示证书开通,在后台下载就可以了(Toolbox-Retrieve Certificate)

到这里,SSL 证书已经搞定,nginx配置可以参考http://www.4os.org/index.php/2012/05/09/nginx-ssl-https-%E8%AE%BE%E7%BD%AE/