分类目录归档:linux

Meanings of fields in /proc/net/dev?

seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
       "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
       dev->name,
       stats->rx_bytes,
       stats->rx_packets,
       stats->rx_errors,
       stats->rx_dropped + stats->rx_missed_errors,
       stats->rx_fifo_errors,
       stats->rx_length_errors + stats->rx_over_errors +
        stats->rx_crc_errors + stats->rx_frame_errors,
       stats->rx_compressed,
       stats->multicast,
       stats->tx_bytes,
       stats->tx_packets,
       stats->tx_errors,
       stats->tx_dropped,
       stats->tx_fifo_errors,
       stats->collisions,
       stats->tx_carrier_errors + stats->tx_aborted_errors +
        stats->tx_window_errors + stats->tx_heartbeat_errors,
       stats->tx_compressed);

openssl 探测证书过期时间

true | openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux

这边一直都是用这个来探测证书的健康的, 在内网的使用还可以, 在公网探测中就很容易出现僵死的情况

后来在sererfault.com查到可以用timeout + 命令来解决

https://serverfault.com/questions/361464/is-it-possible-to-set-a-timeout-on-openssls-s-client-command

测试时发现”timeout 5 true | openssl …” 的管道会失败, 在公网的探测就傻兮兮的只能用了

timeout 5 openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux

缺点是每条指令都要等5秒, 当然, 结合多进程问题也不是太大…

直到今天, 才发现自己摆了个乌龙, 可以使用timeout 5 bash -c “true | openssl s_client… “, true可以处理实时正常结果, timeout可以处理异常结果

timeout 5 bash -c "true | openssl s_client -connect IP:443 -servername hostname 2>&1 | openssl x509 -noout -text -certopt no_header,no_signame,no_pubkey,no_sigdump,no_aux "

aws lightsail ipv6 路由问题

OS 为: amazon linux 2, 当开启ipv6.forwarding的时候, 发现路由就不通了

sysctl -w net.ipv6.conf.all.forwarding=1

#ping6 www.qq.co

connect: Network is unreachable

netstat -nr6 也能看到没有default route, 此时ipv6地址也无法被外部访问

如果关闭ipv6 forwarding, 那么就有默认路由, 也能ping通外部和被访问

::/0 fe80::7c:6bff:feef:ca54 UGDAe 1024 2 9 eth0

能看到路由有一个很特别的标志UGDAe, UpGatewayDynamicAllonlinkExpires

E(e): It maps to RTF_EXPIRES. It means the route has a non-infinite lifetime. In this case, the kernel probably learned the route dynamically from a RA (Router Advertisement).

这个路由其实是动态广播的, 那么这个现象就跟一个参数有关了

net.ipv6.conf.interface.accept_ra

Accept Router Advertisements; autoconfigure using them.

It also determines whether or not to transmit Router Solicitations. If and only if the functional setting is to accept Router Advertisements, Router Solicitations will be transmitted.

Possible values are: 0 Do not accept Router Advertisements. 1 Accept Router Advertisements if forwarding is disabled. 2 Overrule forwarding behaviour. Accept Router Advertisements even if forwarding is enabled.

Functional default: enabled if local forwarding is disabled. disabled if local forwarding is enabled.

Nb: per interface setting (where “interface” is the name of your network interface); “all” is a special interface: changes the settings for all interfaces

默认系统这个参数是1, 当开启forwarding的时候, 不接受路由广播, 所以这个场合, 应该修改为2, Accept Router Advertisements even if forwarding is enabled.

sysctl -w net.ipv6.conf.all.forwarding=1
sysctl -w net.ipv6.conf.eth0.accept_ra=2

备注:

 UP U
 GATEWAY G
 REJECT !
 HOST H
 REINSTATE R
 DYNAMIC D
 MODIFIED M
 DEFAULT d
 ALLONLINK a
 ADDRCONF c
 NONEXTHOP o
 EXPIRES e
 CACHE c
 FLOW f
 POLICY p
 LOCAL l
 MTU u
 WINDOW w
 IRTT i
 NOTCACHED n

nginx upstream check module TCP check检测漏洞

upstream test_check_bin {
server 10.19.127.22:8080;
server 10.19.127.57:8080;
server 10.19.126.6:8080;

keepalive 32;
check interval=10000 rise=2 fall=3 timeout=3000 default_down=false;

}

我们使用的是一个臭名昭著的模块 , 这个模块的作者去了淘宝后便只有tengine里边的模块得到更新了

https://github.com/yaoweibin/nginx_upstream_check_module

目前发现了在当前代码存在两个问题:

  1. TCP检查在几种情况下会失效, 比如交换机挂掉, upstream机器网线被拔了, upstream机器crash了
  2. TCP检查的rise count 存在不增加的情况, 主要是裸JAVA和JAVA容器(java -Dspring.profiles.active=local -jar httpbin-gateway-test.jar),裸python -m SimpleHTTPServer 80之类

第一个问题是因为这个版本的upstream check TCP代码使用的keepalive模式, 根据这个文章的解释TCP Keepalive的心跳包是7200s,两个小时,一旦建立,没有收到主动关闭请求的话在探测端会一直保留establish的状态

https://m.haicoder.net/note/tcpip-interview/tcpip-interview-tcp-keepalive.html

当upstream端突然硬件故障/交换机挂掉/网卡被拔之类的极端情况出现的 时候, nginx 基于keepalivedTCP检测是没办法捕获到这个情况的(检测模块没收到RST/或者dst unr包)

在正常情况下, 比如upstream 端web服务器 STOP了, web服务器oom被系统kill了, docker 实例被stop/kill了, 都会触发关闭连接的请求包 给到nginx 端, 能识别到服务down了

这个是upstream端被kill了
docker kill/stop 都会发包告知nginx TCP监测端

从tengine这个模块的最新代码看, 作者也意识到了这个问题, TCP检测把need_keepalive参数从1改成了0

这个1表示need_keepalive, tengine修改为0了
ngx_check_conf_t 模块这个结构体的定义

这个参数变成0之后会影响clean_event的操作, 每次检测完毕后会close掉连接,每个检测周期都会重新发起TCP连接

need_keepalive参数控制了连接是否销毁的行为

第二个问题: rise counts 不增加, 这个通常都是upstream 端listen 模式有问题导致, 它并没有正确的定期回包, 通常情况下, nginx, apache都能正常的主动回包让rise counts增加

大多数upstream端主动发送包(确认是否存活), 否则很快就会close

python java这些裸起的一些简单服务就没有定期主动回包, 而在这个版本的代码中, 会判断这个connection是否存在, 如果存在则return了导致计数器不会增加

tengine的新代码是去掉了connection != NULL的判断条件

不过, 划重点: 无论是否回包, rise counts 是否增加,并不影响TCP监测的存活性, TCP监测keepalive模式仅仅以能否建立连接(刚启动时)/是否收到upstream的异常包为判断依据

总结: 为了避免过于复杂的处理逻辑, tengine去掉了keepalive的TCP探测,每次请求完都销毁连接,下次探测再重新协商请求

这里给下针对这个问题的patch:

https://www.4os.org/patch/nginx_upstream_check_tcp.patch

小米路由R1D ipv6设置

分为普通模式和中继模式, 略有不同

  • 中继模式需要配置

/etc/config/ipv6
config ipv6 settings
list if_on "lan"
option enabled "1"
list if_on "ipv6"
option enabled "1

/etc/config/network

config interface 'lan6'
option ifname '@lan'
option proto 'dhcpv6'

可以适当配置ipv6的DNS, 非必须

  • 普通模式需要配置

/etc/config/ipv6
config ipv6 settings
list if_on "wan"
option enabled "1"
list if_on "ipv6"
option enabled "1

/etc/config/network

config interface 'wan6'
option ifname '@wan'
option proto 'dhcpv6'
list dns '240c::6666'
list dns '240c::6644'

然后重启或者/etc/init.d/network restart即可

rp_filter和fwmark base 策略路由

  • 前提:

先说下网络环境, 这边架了个tunnel, 之前无论是全部走tunnel 还是部分目标IP走tunnel都没有问题, 实现如下

ip rule add from 10.4.224.100 table routeTableName

ip route add $line via 172.16.172.1 dev tunnel (table routeTableName)

  • 新的需求: 根据部分协议,比如TCP来走这个路由, 实现办法是

iptables -t mangle -A PREROUTING -s 10.4.224.100/32 -d 10.0.0.0/8 -p tcp -m tcp -j MARK --set-xmark 3

ip rule add from 10.4.224.100 fwmark 3 table tun

在这个路由表使用的策略路由则不生效了, 相同的语句导致无法访问网络了

ip route add $line dev tunnel table tun

  • 听包看看:

在tunnel的对端服务器能看到对端回包后后续传输失败了

在本地linux 网关的tunnel听包可以看到回包也过来了

在本地linux 网关的内网听包能看到只有客户端的发包没有收到回包

那么问题就发生在tunnel 到 内网网卡这一段, 包要么是路由不对,要么是被drop了, 由于之前是可以直接访问的, 那么路由的可能性很小

  • 问题定位检测:

使用如下方式确认回包是否被drop了,配置:

sysctl -w net.ipv4.conf.default.log_martians=1
sysctl -w net.ipv4.conf.all.log_martians=1

发现有如下的检测日志:

IPv4: martian source 10.4.224.100 from 122.13.86.120, on dev tunnelX
IPv4: martian source 10.4.224.100 from 122.13.86.120, on dev tunnelX

这里由于是reverse path filter, 原理是把源和目标调换确认该设备接口是否是最佳接口, 显然回包被认为是不合适的包, 被过滤掉了

  • 问题解决:

问题就简单了, 设置rp_filter即可

sysctl -w net.ipv4.conf.default.rp_filter=2

sysctl -w net.ipv4.conf.all.rp_filter=2

  • 问题解析:

那么问题来了, 为什么原来的简单策略路由就可以, 加了–set-mark 3后, 基于fwmark的就不行呢?

从听包可以看到原有的策略路由是可以正常返回的, 包括tunnel和内网网卡

推测很大可能是因为我们使用了 ip rule add from 10.4.224.100/32 table routeTableName的方式能让rp_filter检测到回程数据包的reverse path是合理的

而rp_filter大概率是无法识别到fmwark的策略路由的, 检测的时候发现回包数据不合理被drop了

如何确认以上这番推测是否合理呢? 这里做了个测试, 从tunnel对端的机器使用tunnel接口ping 10.4.224.100

ping 10.4.224.100 -I tunnelX
PING 10.4.224.100 (10.4.224.100) from 172.16.172.1 tunnelX: 56(84) bytes of data.
^C
--- 10.4.224.100 ping statistics ---
77 packets transmitted, 0 received, 100% packet loss, time 77858ms

查看本地linux的日志可以看到数据包被drop了

Mar 18 09:37:25 gw kernel: IPv4: martian source 10.4.224.100 from 172.16.172.1, on dev tunnelX
Mar 18 09:37:25 gw kernel: IPv4: martian source 10.4.224.100 from 172.16.172.1, on dev tunnelX

由于是reverse path 校验嘛, 给它加个路由

ip route add 172.16.0.0/16 dev tunnelX table myRouteTable

于是, 通了

ping 10.4.224.100 -I tunnelX
PING 10.4.224.100 (10.4.224.100) from 172.16.172.1 tunnelX: 56(84) bytes of data.
64 bytes from 10.4.224.100: icmp_seq=1 ttl=62 time=2.22 ms
64 bytes from 10.4.224.100: icmp_seq=2 ttl=62 time=37.9 ms

至于为什么ping值这么飘忽…因为这个是wifi的IP啊, 我去毒打wifi管理员了



  • 背景资料:

关于rp_filter的问题可以参考本站这个链接:

/usr/share/doc/kernel-doc-2.6.32/Documentation/networking/ip-sysctl.txt rp_filter -

INTEGER 0 - No source validation. 不检测源

1 - Strict mode as defined in RFC3704 Strict Reverse Path Each incoming packet is tested against the FIB and if the interface is not the best reverse path the packet check will fail. By default failed packets are discarded.

严格检测模式

2 - Loose mode as defined in RFC3704 Loose Reverse Path Each incoming packet's source address is also tested against the FIB and if the source address is not reachable via any interface the packet check will fail.

松散检测模式, 只要有一个设备接口有这个地址就可以

Current recommended practice in RFC3704 is to enable strict mode to prevent IP spoofing from DDos attacks. If using asymmetric routing or other complicated routing, then loose mode is recommended. The max value from conf/{all,interface}/rp_filter is used when doing source validation on the {interface}. Default value is 0. Note that some distributions enable it in startup scripts.

  • 参考资料:

https://blog.csdn.net/dog250/article/details/7947705

aws lightsail ssh 挂掉如何登录

在尝试调整sshd端口的时候不小心把ssh弄挂了, 由于vps里边也是有防火墙的,外边进不去,控制台也进不去,因为amazon的lightsail 实际上并没有console控制台, 它的控制台也是通过ssh登录的

这个时候需要如下步骤来拯救机器和数据

1.    打开 Amazon Lightsail 控制台

2.    创建实例的手动快照

3.    在 Snapshots (快照)选项卡上的 Manual snapshots (手动快照)项下,选择新快照旁边的三个点。

4.    选择 Create new instance (创建新实例)。

5.    选择与上一个实例相同的可用区域。

6.    选择 Add launch script (添加启动脚本),然后添加以下脚本

sudo sed -i 's/Port /#Port /g' /etc/ssh/sshd_config
sudo systemctl restart sshd.service
sudo systemctl stop firewalld.service
sudo systemctl disable firewalld.service
sudo systemctl enable sshd
sudo systemctl restart sshd
sudo systemctl enable sshd.service
sudo systemctl restart sshd.service

7.    选择新的实例计划,或使用与之前的实例相同的计划。

8.    输入实例的名称,然后选择 Create instance (创建实例)。

新实例开始运行后,等待 10 到 15 分钟,然后尝试使用基于浏览器的 SSH 控制台连接到该实例。

注意:如果以前的实例具有静态 IP 地址,则可以在新实例上使用它。分离静态 IP 地址,然后从 Networking (联网)选项卡将其附加到新实例。有关更多信息,请参阅 Amazon Lightsail 中的静态 IP 地址

如果以上问题仍不能修复, 则需要尝试为机器配置会话管理器, 这个就比较复杂了,仅供参考

https://lightsail.aws.amazon.com/ls/docs/en_us/articles/understanding-static-ip-addresses-in-amazon-lightsail

SSH 服务已关闭

如果 SSH 服务未在实例上运行或未处于活动状态,则 SSH 连接将失败,并且您会收到 UPSREAM_NOT_FUND [519] 错误消息。要解决此问题,请为您的 Lightsail 实例配置 AWS Systems Manager 会话管理器服务。配置会话管理器后,在没有 SSH 服务的情况下访问实例,然后修复 SSH 问题。

SSH 问题的基本故障排除步骤包括:

  • 请查看 /var/log/auth.log 或 /var/log/secure 文件中的 SSH 身份验证日志以识别错误,具体取决于操作系统的版本。
  • 测试 SSH 配置文件语法,然后更正所有错误。
sudo sshd -t
sudo systemctl restart sshd

参考文档: https://aws.amazon.com/cn/premiumsupport/knowledge-center/lightsail-resolve-ssh-console-errors/

APNIC 区域不准确的情况

bilibili.com广州电信区域发现无法访问, 这边上网是根据APNIC的CN列表来的

结果发现8.134.32.222 这段的IP无法访问, 从搜狗查看是阿里云广东的节点,跟APNIC的数据集有冲突,APNIC显示是新加坡

于是用CNNIC校验了下,发现了矛盾的地方,CNNIC显示是CN Aliyun,但是mnt-by数据是SG新加坡, 不知道是不是跟新加坡买了这一段IP

wg 配置

wg 是性能非常优秀的链路接入软件, 在linux kernel 5.6的时候已经被纳入正式内核

以下介绍下在centos7 下的配置:

1.先升级下系统版本到最新

#yum upgrade

2. 安装必要的系统依赖库和软件,客户端和服务端一样操作

# sudo yum install epel-release elrepo-release
# sudo yum install yum-plugin-elrepo
# sudo yum install kmod-wireguard wireguard-tools

3. 生成服务器和客户端的公钥私钥

#服务器和客户端都需要分别执行一遍

wg genkey | tee privatekey | wg pubkey > publickey

4. 配置文件

#客户端

[Interface]
PrivateKey = “客户端私钥”
Address = 172.16.52.52/24
DNS = 8.8.8.8
MTU = 1420
[Peer]
PublicKey = “服务端公钥”
Endpoint = “服务端接入IP”:4430
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

服务端

[Interface]
Address = 172.16.52.0/24
MTU = 1420
SaveConfig = true
ListenPort = 4430
PrivateKey = “服务端私钥”
[Peer]
PublicKey = “客户端公钥”
AllowedIPs = 172.16.52.52/32

5. 服务端转发配置

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -I POSTROUTING -s 172.16.52.0/24 -o eth1 -j MASQUERADE

6. 开启脚本:

systemctl enable wg-quick@wg0

7. 可能产生的问题:

1) MSS导致大包无法通过, 这个是NAT代理常见的问题, 现象是ping 或者部分小网页能打开, 大的网页则卡住了, 一般都是MSS导致, 需要设置小MSS

iptables -t mangle -A POSTROUTING -p tcp –tcp-flags SYN,RST SYN -o eth1 -j TCPMSS –set-mss 1400

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