Linux

浅谈 Linux 上的 SLAAC:原理、配置和系统行为

TL; DR:本文简要介绍了 IPV6 自动配置的基本概念和原理,并讨论了在 Linux 下自动配置(aka. SLAAC)原理和坑点,其中:

启用 IPV6 SLAAC 并允许内核自动添加 IPV6 默认路由需要使 net.ipv6.conf.{iface}.autoconf = 1 且 net.ipv6.conf.{iface}.accept_ra = 1
如果启用了 net.ipv6.conf.{iface}.forwarding ,则对应网卡接口 accept_ra 需要为 2
上述 iface 既可以是 default/all,也可以是具体某个网卡接口,但是需要特别注意,对于部分 IPV6 配置项,仅修改 net.ipv6.conf.all 时不会应用到全部网卡接口,使用时请确认所需的网卡接口上配置正确。
另外在部分发行版中可能修改 accept_ra 实际不生效,系统可能出现预期外行为(无法自动获取的地址和路由,或配置为不需要 SLAAC 时系统仍会进行配置等),此时可检查系统中是否存在其他网络管理工具如 netplan 造成了遗留影响。

TL; DR:变更 sshd 这种高危操作三思而后行,最好留个后路谨防失联。
TL; DR 2:裸奔的 aria2c 可以用于写入文件最终导致 getshell,为了安全起见,公网上的 aria2c 建议禁用 rpc-listen-all 或/和设置足够强的 rpc token,也避免使用 root 运行 aria2c。

如 https://lwn.net/Articles/812537/ 所述,由于 SHA-1 签名算法的暴力破解成本已下降到可接受范围,OpenSSH 8.2 决定不再支持 ssh-rsa 签名算法,其结果是,过旧版本的 ssh-server 将无法使用高版本 ssh-client 连接,比如 CentOS6 的 5.3 不支持 ecdsa host key,也不支持 rsa-sha256 或更强的算法,摆在 CentOS6 用户面前的只有两条路,1. 升级 OpenSSH 版本,2. 准备一个旧版 ssh client 用来登陆老旧服务器。

很不巧的是我手头正好有一台老旧的、没有接 IPMI 管理网卡的 CentOS6 物理服务器,CentOS6 主源中没有符合要求版本的 OpenSSH(>5.7),于是我需要尝试自行编译或找一个别人编译好的二进制,于是我找到了 https://github.com/faishal/openssh-portable/releases/download/cent.os.6.7.openssh.7.3p1/openssh-7.3.zip ,事实表明它有坑,Google 搜出来的第一个结果也不一定总是靠谱的。

从内网第二网关配置浅谈 ARP Flux 问题

TLDR :在同一个广播域内存在多个路由器/转发器如 VPN 网关、DR 模式的 IPVS 时,需注意内网主机的 ARP 配置,否则默认配置下 Linux 内核会使用所有可用 IP 进行 ARP ,可能引起被称为 ARP Flux 的混乱现象,一个典型现象为:网卡会使用绑定在其他网卡上的 IP 地址进行收发包。net.ipv4.conf.all.arp_ignore,net.ipv4.conf.all.arp_announce,net.ipv4.conf.all.arp_filter 等参数可以调整这一行为

背景,内网一台虚拟机用 wireguard 和外部一个 CN2 出口打了隧道,希望将这台虚拟机配置为内网 VPN 网关,其他机器将任意 IP 的路由指向此虚拟机(以下简称 gw)即可实现走 CN2 访问目的 IP。

在实际操作中,发现一个现象,按照上述流程配置过 iptables 和路由规则后,有时仍会发现内网的包不会按照预期转发到 gw 的 wghub 接口,此时在 gw 抓包会发现内网其他主机发来的包不是从 ethA 进入,查看内网其他主机的 ARP ,发现 ARP 缓存是错误的,ip neigh flush all 后使用 arping 进行测试,发现无论请求 192.168.0.a 还是 192.168.0.b,gw 都会同时将两张网卡的 MAC 地址作为响应,且响应返回时先后顺序固定,因此不明就里的客户端就会取第一个响应记录到 ARP 表。

TL; DR:本文主要从 socket 的关闭方式谈到 socket 的 SO_LINGER 属性,进一步分析 nginx 关于 lingering 的配置和源码,浅谈如何避免 socket 关闭时可能出现的一些问题。

在 Unix 上,一个连接实际上对应的是内核里的一个 fd, sockfd = socket(int socket_family, int socket_type, int protocol) ,因此 socket 的关闭实际上是使用 close() 调用将其当作一个普通 fd 进行关闭;但是对于 TCP 连接,可以使用 shutdown() 系统调用,将其当作一个全双工连接进行关闭后再使用 close() 进行销毁,两种方式在行为上略有区别。

nf_conntrack 的数据结构和相关参数调优

在内核中,连接跟踪表是一个二维数组结构的哈希表(hash table),哈希表的大小记作HASHSIZE,哈希表的每一项(hash table entry)称作bucket,因此哈希表中有HASHSIZE个bucket存在,每个bucket包含一个链表(linked list),每个链表能够存放若干个conntrack条目(bucket size)。需要明确的是,nf_conntrack 模块并不是所有 Linux 内核都会加载,最常见的导致加载该模块的原因是使用了 iptables、lvs 等内核态 NAT/防火墙导致内核需要对连接表进行追踪,iptable_nat、ip_vs 等多个内核模块都依赖 nf_conntrack, 但是 nf_conntrack 的存在会影响高并发下的内核收包性能。