Linux 单臂软路由设置及流量监控ntopng避坑

作者:Sender  来源:wavecn.com  发布日期:2023-06-25  最后修改日期:2023-06-25

Linux 的路由功能之强大,确实是 Windows 难以媲美的。而且在性能上只要经过仔细调优,可以达到100Gbps的线速吞吐,与基于ASIC电路的硬件路由器相比毫不逊色。

article banner

笔者:国际认证信息系统审计师、软考系统分析师

虽然 Windows 也不是不能打,但从各种可控角度,事实上我还是推荐用 Linux 做软路由。

加上现在要逐步实现国产化替代,Linux 软路由也就继续有了应用的意义。所以这次就不用 Rocky Linux 了,改用国产的 Linux 发行版:龙蜥 Anolis 8

openanolis 8

这次的文章也特意大量引用别人公众号文章,作为一种新风格的尝试。

言归正传。Linux 系统做软路由服务器其实并不复杂。

一、网络接口和路由转发

网络接口涉及到物理接口和虚拟接口。现在大多数发行版都默认安装了  NetworkManager,可以通过 nmcli 进行命令行配置,也可以用 nmtui 使用文本界面进行配置。

networkmanager logo

只是从笔者角度觉得,还是写 ifcfg 配置文件比用 nmcli 或者 nmtui 命令来得简单直接,更不用说图形界面了,真 · Linux 管理员根本不需要 GUI 的好吧

NetworkManager 作为守护程序,它的最大作用是应对网络连接变化时的自动切换和配置。这对于移动终端还是有必要的,但如果是服务器且静态配置网络设置,完全可以关闭该服务以节省资源。

单臂软路由服务器一般需要两个物理的网络接口,分别用于内外网。这里依然要说一下之前说过的观点:某些网上教程简化为一个物理接口,这我是强烈反对,因为没有从物理上把内外网分区,没有安全性可言。

1、首先是配置外网接口,创建连接并添加地址。

为了有效区分内外网,我把外网连接命名为 ens_wan,内网连接则是 ens_lan。设备名称就不要改,安装时自动命名是什么就是什么。这个步骤最适宜是在安装操作系统时就设置好。

如果是安装完成后设置,那就需要把连接改名,通过 nmcli 可以如下操作:

# nmcli connection modify ens33 connection.id ens_wan

这就把在安装过程中自动命名的 ens33 改为 ens_wan 了,这个操作可以立即生效。

2、其次是配置内网接口。

单臂软路由特点就是一个内网网口要对接多个子网。使用 nmcli 对内网连接添加作为子网网关的IP地址,然后用 connection up 操作刷新即可。如下是添加192.168.101.0/24子网的网关192.168.101.1:

# nmcli connection modify ens_lan +ipv4.addresses "192.168.101.1/24"
# nmcli connection up ens_lan
连接已成功激活 (D-Bus 活动路径: /org/freedesktop/NetworkManager/ActiveConnection/6)

也可以用 nmtui 去实现各种配置过程,新手来说,某程度上会比打命令稍方便一些,比如这样的:

nmtui

3、再然后就是路由转发。

老生常谈的启用路由转发操作:

# echo 1 > /proc/sys/net/ipv4/ip_forward

不过现在 Anolis 8 已经不需要了,默认就是1而且改不回去0。

设置路由就是 route 命令,这已经是网管基本功。

既然是路由器的用途就会有设置静态路由的时候。正常情况下,随着网络连接上添加了子网网关地址,相应的路由规则也会自动添加。但如果是再下游的子网,就要考虑通过手工增加静态路由实现网络互通。

NetworkManager 的 nmcli 也支持设置路由,因此现在一般可以先尝试用传统的 route 命令进行设置和测试,比如这样设置局域网子网的静态路由:

# route add -net 192.168.48.0/24 gw 192.168.49.90 dev ens_lan

写这些有点灌水的感觉了,建议参考这里:

程序猿阿蛮:详解 linux 路由 route 命令

测试通过后,再用 nmcli 将其固化:

# nmcli connection modify ens_lan +ipv4.routes "192.168.48.0/24 192.168.49.90"

注意:

1)nmcli 添加静态路由后需要将网络连接重新激活才能生效(不需要down,只需要up就能生效,删除路由后亦然)。

# nmcli connection up ens_lan
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/3)

2)命令行参数方式的 nmcli 操作默认保存操作结果。但如果是交互模式则需要执行 save persistent 命令才能保存。

4、NetworkManager 的安全相关要点

如果是企业的分支机构,通常要设置 VPN 接入到总部。但 NetworkManager 默认不连接需要输入密码的连接。因此,需要先把 VPN 连接设置为所有用户可用,并设置为所有用户保存密码(必须是明文而不能是keyring方式保存),然后记录下 VPN 连接的 UUID,添加到路由器互联网连接的附加连接上:

# UUID=$(nmcli --get-values connection.uuid connection show VPN连接名)
# nmcli connection modify ens_wan connection.secondaries "$UUID"

但是,明文保存的密码不具备安全性。从个人经验认为,由于现在讨论的是软路由服务器,一般不可能有网络安全三员之外的登录用户,而VPN是两地站点之间的数据通道作用,基于证书认证登录即可保证登录安全性,万一证书私钥泄露,基于证书更替撤销等操作机制也可以保证通道的安全性,所以没必要再对证书私钥下密码导致还需要明文保存密码。

NetworkManager 更详细的使用方法可以参考其文档:

https://networkmanager.dev/docs/

二、防火墙和NAT

早期发行版是通过 iptables 命令进行操作,现在都是通过 firewalld 服务以及 firewall-cmd 命令进行操作。

firewalld logo

firewalld 的配置操作比直接操作 iptables 要方便,不需要手工写脚本或者编辑配置文件。尤其是常见操作,比如做路由器所必须设置的 NAT 转换,如下简单一条命令就实现了在外部网区域启用 NAT 转换:

# firewall-cmd --zone=external --add-masquerade

如果要设置开放端口,操作命令也很清晰,注意如下命令操作的是内部网区域,开放 SSH 端口用于远程登录管理:

# firewall-cmd --zone=internal --add-port=22/tcp

firewall-cmd 可实现的操作非常多,只说几个要点:

1、最容易被忽视的,但又非常有用的是 firewalld 预定义了一些区域,可以利用这些区域去绑定不同的网卡,从而区分细化过滤规则,不像以前 iptables 还要自己定义,且清晰度不如 firewalld。

比如上面的操作我们对外部区域 external 设置了NAT,那么接下来把公网接口转入该区域,这个设置就有意义了:

# firewall-cmd --zone=external --change-interface=公网接口名称
# firewall-cmd --set-default-zone=external

关于 firewalld 的预定义区域,可以参考:

Linux中国:理解多区域配置中的 firewalld

2、对于 firewalld,我一向觉得 firewall-cmd 这个命令实在有点长,为了少打字,我会在 /root/bin 下面建立一个符号链接叫 fwcmd,指向 /bin/firewall-cmd:

# mkdir /root/bin
# ln -s /bin/firewall-cmd /root/bin/fwcmd

3、初学 firewalld 的管理员最容易忽略的就是固化配置:

# firewall-cmd --runtime-to-permanent

要把运行配置保存下来成为固化配置。

4、firewalld 有个特殊的参数叫“允许区域漂移”,为了保持兼容性默认为“yes”,可以根据实际情况而修改为“no”,参考我以前的文章:

firewalld警告信息处理两例之清理virbr0及关闭区域漂移

5、如果 firewalld 配置了大量的开放端口或服务,一个个删除的确是很折磨,firewall-cmd 也没有提供一次全删的命令参数。但我们可以通过命令行脚本实现批量删除。

如下是删除全部开放了的端口的命令,注意其中的 --permanent 参数,删除的是固化配置而不是当前运行配置:

# firewall-cmd --permanent --list-all | grep ports | head -n 1 | \
cut -d: -f2 | tr ' ' '\n' | xargs -I {} firewall-cmd --permanent --remove-port={}

如下是删除全部开放了的服务的命令,和上一操作大同小异,我特意没写 --permanent 参数来对比,所以操作的是当前运行配置:

# firewall-cmd --list-all | grep services | head -n 1 | \
cut -d: -f2 | tr ' ' '\n' | xargs -I {} firewall-cmd --remove-service={}

提醒:上述操作是全部删除,没有保留。如果是远程操作比如 SSH 或者 VNC 方式,建议是对固化配置进行清除,然后对固化配置添加当前远程操作的服务(或端口),最后再 RELOAD 生效。否则如果是对运行配置操作,会立即无法访问服务器。

三、DHCP和DNS

1、首先是DNS缓冲服务器的设置。

要在内部区域开放DNS端口:

# firewall-cmd --zone=internal --add-port=53/udp

还需要安装 BIND 并将之配置为仅起缓冲用途的 DNS 缓冲服务器。这里简单归纳一下配置步骤,首先是安装BIND:

# dnf install named -y

然后修改配置文件,包括以下4个关键项目:

1)侦听端口和地址。懒人可以直接设置地址为any,反正防火墙会拦截外网接口不暴露在侦听53端口。

listen-on port 53 { any; };

但从良好实践出发,应改为内网各子网网关地址:

listen-on port 53 { 192.168.100.1; 192.168.101.1; };

2)允许查询的地址范围,同样可以填any或设置具体的地址范围。

allow-query { any; };

3)查询转发地址,填写1个或多个上游DNS服务器地址。

forwarders { 上游DNS服务器地址1; 上游DNS服务器地址2; };

要根据情况选择合适的上游 DNS 服务器地址。一种错误情况是使用A运营商的线路但设置了B运营商的 DNS 服务器地址,会有可能导致被访问的网站相关的 CDN 加速失效。所以这里就没写具体IP了。

4)关闭dnssec校验。

dnssec-validation no;

最后在内网区域开放防火墙端口、启用和启动服务:

# firewall-cmd --zone=internal --permanent --add-port=53/udp
# firewall-cmd --reload
# systemctl enable named
# systemctl start named

注意上面修改过程中各处的分号不可少。

经过配置后,就可以在内网终端上测试 DNS 缓冲服务器的效果了。还可以参考类似的公众号文章:

飓风网络安全:Linux之DNS服务器搭建及常见DNS攻击和防御

黑白天实验室:Linux部署DNS服务器

关于 DNS 服务器其实远不止这么点事情,可以看看我之前关于 DNS 安全和 DNS 解析技巧的文章:

企业内网DNS服务器安全和性能基础实践

内网DNS服务实现公网域名在内网转换解析

2、简单的DHCP服务器配置

先简单地安装软件包,然后使用默认配置文件:

# dnf install dhcp-server -y
# \cp /usr/share/doc/dhcp-server/dhcpd.conf.example /etc/dhcp/dhcpd.conf

cp前面的反斜杠是压制询问是否覆盖的提示。

然后修改这个配置文件......改的还挺多,直接贴修改后的有效配置文件作为示例吧,不适用的配置已经删除,补充了中文注释:

# dhcpd.conf

# 首先是全局配置,也就是DHCP区域定义中不另外定义时就使用全局配置。

# 本地主域名及后缀,随便命名,比如lan.corp
option domain-name "lan.corp";

# DNS服务器名称或IP地址,多个时用逗号分隔。
# 实际应该在子网定义中按子网进行配置。
# 这里设置的是路由器本身(假设为192.168.49.90)和一个外部DNS(8.8.4.4)。
option domain-name-servers 192.168.49.908.8.4.4;

# 默认释放时间,秒数
default-lease-time 600;
# 最大释放时间,秒数
max-lease-time 7200;

# 是否开启动态DNS更新,一般按默认值none,即不允许
#ddns-update-style none;

# 如果DHCP服务器是本地网络的正式服务器,需要取消下一行的注释
#authoritative;

# 启用下行为设置DHCP的日志信息到其他日志文件,
# 需要同步修改SYSLOG.CONF去实现配置。
#log-facility local7;

# 第一张子网,很基本的子网定义,注意路由器IP地址设置可以设置多个,用逗号分隔
# 子网192.168.100.0/24
# 动态分配范围从 192.168.100~150
# 网关为路由服务器的接口地址 192.168.100.1
# 域名服务器重定义为 192.168.100.1, 8.8.4.4 两项
# 域名定义为 sublan100.corp
# 注意:如果域名服务器有定义内部域,就不能这样一个外部一个内部的设置!
# 只能要么只有1个内部,要么主备2个内部。
# 1内1外的设置仅适用于内部DNS服务器是纯缓冲服务器
subnet 192.168.100.0 netmask 255.255.255.0 {
  range 192.168.100.100 192.168.100.150;
  option routers 192.168.100.1;
  option domain-name-servers 192.168.100.18.8.4.4;
  option domain-name "sublan100.corp";
}

# 第二张子网,比较完整的配置,但没有实际区别
# 子网192.168.101.0/24
# 动态分配范围从 192.168.101.200~250
# 网关为路由服务器接口地址 192.168.101.1
# 广播地址设置为 192.168.101.255,
# 域名服务器重定义为 192.168.101.1 8.8.4.4 两项
# 域名定义为 sublan101.corp
# 默认释放时间重定义为 1200 秒
# 最大释放时间重定义为 28800 秒
subnet 192.168.101.0 netmask 255.255.255.0 {
  range 192.168.101.200 192.168.101.250;
  option domain-name-servers 192.168.101.18.8.4.4;
  option domain-name "sublan101.corp";
  option routers 192.168.101.1;
  option broadcast-address 192.168.101.255;
  default-lease-time 1200;
  max-lease-time 28800;
}

# 建议对于不分配IP地址的范围同样在DHCP中定义,以便DHCP服务器掌握网络拓扑
subnet 192.168.49.0 netmask 255.255.255.0 {
}

# 需要特别配置的主机声明,固定地址如果不设置则依然是动态分配。
# 如果设置,则要注意固定地址不能在可分配的地址池范围内。
# 固定地址也可用主机域名,但这就需要在DNS服务器中配置本地域解析了。
host mylaptop {
  hardware ethernet a1:02:c0:51:6d:75;
  fixed-address 192.168.49.99;
}

# 终端分类、共享地址池等相对少用的配置这里就省略掉。

完成修改后,照样是开放防火墙端口、启用和启动服务:

# firewall-cmd --zone=internal --permanent --add-service=dhcp
# firewall-cmd --reload
# systemctl enable dhcpd
# systemctl start dhcpd

也可以参考:

回忆总是那么美:Linux搭建dhcp服务器

四、吞吐量优化和网络安全措施

1、吞吐量优化

作为软路由服务器,优化在于网络性能,这当然就是时延和吞吐量这两个关键指标先行,NAT 负载能力跟上了。

对于时延和吞吐量,之前写的关于 Windows 作为软路由服务器的硬件优化措施是同样适用的:

Windows 服务器网络性能调优系列硬件篇

我之前有一篇是专门介绍Linux网络吞吐优化设置的,主要聚焦于吞吐量和 NAT 承载能力,也可以参考:

Linux 软路由网络吞吐优化设置

需要说明的是随着 Linux 内核不断发展,其网络子系统所提供的可调节参数也在不断变化。对于本次作为实践环境的 Anolis 8 所使用的 5.10 内核,这些参数都还在,只是个别默认值不同于以前,比如:

/proc/sys/net/ipv4/tcp_rmem

默认值是:

4096    131072  6291456

这三个值中间的值比我原来设计的 87380 还要高。读者可以自己再研究是保留默认值还是另外设置一个新的值。

2、网络安全

作为路由器,网络安全包括自身安全和局域网安全两个范畴。自身安全通过防火墙封禁端口、设置各种密码管理规则、启用 SELinux 等等手段实现。

需要前置提醒的是,Anolis 8 安装后默认不启用 SELinux,但应该启用。方法可以参考我之前关于 SELinux 的文章:

SELINUX介绍连载之二(模式切换篇)

在局域网安全范畴,安全管理员和网络管理员应收集内网终端的 MAC 地址,然后在 DHCP 服务的配置中设置 MAC 地址和 IP 地址的绑定分配关系,同时通过防火墙设置 MAC 地址过滤,实现严格控制终端通过路由器访问出外网或跨网段访问其它子网。

要做好安全措施,还需要通过网络交换机,设置端口绑定、VLAN 等措施,进一步限制恶意外来终端通过广播方式尝试访问网络范围的其他网络资产。

五、设置流量监控

最后是关于流量监控,ntopng 这个软件。先提一下 ntop 这个文本方式的命令行工具,用于查看网络流量情况。但该工具已经过时,被 Anolis 8 的上游发行版删除,所以也不包含在 Anolis 8 中了。

ntop banner

继承者是 ntopng,即ntop next gen,顾名思义就是ntop的下一代。与传统的 ntop 相比,ntopng 是个复杂的网络流量监控软件:由多个组件组合而成,提供 WEB 界面,支持流量分析、抓包以及深度包检测等网络流量监控功能,非常适合在软路由服务器上安装使用,但对服务器资源要求比如 CPU 和内存都较高。

ntopng 具体的功能特性、安装使用教程到处都有,直接引用如下:

Python运维实践:基于web的网络流量分析工具ntopng及使用

云计算和网络安全技术实践:ntopng的实践(一)

但是这些教程都没有指出,ntopng 如果不加以适当配置,是有坑的。

第一个坑是内存占用,来自于 ntopng 数据库所依赖的 redis 内存型键值数据库。

该数据库需要占用大量的内存,如果不设置限值,随着数据规模增长,所有的内存都有可能被其占用耗尽。因此,需要修改 /etc/redis.conf 配置文件,按照服务器的实际内存情况和使用需要,设置其中的 maxmemory 和 maxmemory-policy 两项设置。比如:

maxmemory 300mb
maxmemory-policy volalite-lru

即最大内存限制设置为300mb,内存的替换算法设置为最近易失性。

最大内存限值的设置还需要考虑 redis 异步持久化写盘机制会对内存数据库产生临时的内存快照。这个快照需要的内存是1比1的,所以 maxmemory 的实质是会占用该值两倍大小的内存,只是其中的一半是在持久化过程中动态占用。

第二个是大坑:硬盘寿命问题。源头也同样是 redis 键值数据库。

如果路由服务器使用的是 SSD 硬盘,那么在默认配置下会迅速耗尽硬盘寿命。

这是因为 redis 的持久化机制,把内存中的数据生成快照保存到磁盘里面的过程,是异步、后台且持续的。默认就被配置为持续不间断地进行。

在安装了 ntopng 后,检查/etc/redis.conf配置文件,有如下的默认设置:

save 900 1 
save 300 10 
save 60 10000

这三行配置的意思是:

服务器在 900 秒之内,对数据库进行了至少 1 次修改。
服务器在 300 秒之内,对数据库进行了至少 10 次修改。
服务器在 60 秒之内,对数据库进行了至少 10000 次修改。

只要满足任意一个,就会进行写盘。这样的频率,稍微有点流量的网关随便都能触发第二条,甚至最频繁的第三条(取决于网络内终端的数量)。而每次写盘都是全数据库写盘,简单的乘法计算就可以知道一天下来会向硬盘写入多少数据。

这个数据量,对于小容量的 SSD 硬盘是致命的。由于服务器企业级 SSD 硬盘都比较贵,而且作为路由服务器的存储要求并不高,用户采购时自然会选择较小的固态硬盘。

结果还不够2年,服务器的管理固件就警告 SSD 硬盘寿命只剩下1%。

ssd life loss

老郁闷了。

解决办法包括:

1、调整持久化触发频率

最简单的调整办法就是修改触发条件从而降低触发频率。如果不关心 redis 存下来的数据,也对服务器的稳定性有信心,那么可以调整触发条件,简单地只保留1条规则且把时间间隔修改为比较长的间隔,比如1个小时。写入的数据量就会随之而成比例地下降。

该调整的缺点在于写盘间隔越长,可恢复的有价值数据就越少,可持续性容灾设计中的 RPO 是也。

2、修改持久化机制

从默认的全量写盘方式改为增量写盘方式,即 AOF 方式。

开启 AOF 功能需要 /etc/redis.conf 文件中将 appendonly 配置项修改为 yes,并指定 AOF 文件名称和备份存放路径:

appendonly yes
appendfilename appendonly.aof
dir /usr/local/var/db/redis/

但是,此方法对于繁忙的路由服务器是没有太多意义的,因为很可能单位时间内的增量甚至还大于内存数据库的内存占用量。

而且,AOF 文件是要占硬盘空间的,redis 还需要通过重写操作将其覆盖以释放空间,复杂性大大增加。

所以这个方法只适用于小型网络,二三十台终端的情况。

3、挂载机械硬盘

问题很多时候还是需要从最底层去解决。挂载机械硬盘专门用于 redis 持久化是最可行的措施,成本也不高,如果要数据安全就使用 RAID1 冗余即可。

具体方法就是为路由服务器采购配置企业级机械硬盘(建议使用 NLSAS 近线 SAS 硬盘),挂载到 redis 的存放路径承接数据写入。

当前主流 NLSAS 硬盘顺序写入速度可以达到170MB/s(注意:大于千兆网最大速率),假设 redis 数据库为300MB,理想情况下2秒就可以写完。所以,设置稍大的缓冲区和写盘触发周期就可以获得足够的写盘时隙了。

如果阵列卡有内存缓冲(切勿是 SSD 缓冲,死得更快),写盘过程还可以获得进一步的效率提升。

再如果启用了滚动抓包,专门硬盘的优势会更明显。持续写就写吧,反正写不死,只是比较忙。

写在最后

不可替代的网管需要有全栈能力:从物理层到应用层。谁会想到配置 Linux 软路由服务器,最后居然是要折腾 NoSQL 数据库写盘调优避坑。本文引用较多,写得比较散乱,如有遗漏可留言指出。

本栏目相关
  •  2024-01-28 网络运维及安全基础:MAC地址全面介绍之一
  •  2024-02-12 龙年新作:MAC地址厂商双向查询功能上线!
  •  2010-01-25 Linux 下的分区调整工具GParted实战
  •  2020-02-27 服务器热加硬盘、热转RAID模式,配合LINUX卷操作实现不重启服务器完成扩容
  •  2022-02-24 如何安装使用 Broadcom RAID卡命令行管理工具 StorCLI(或称PercCLI)?
  •  2023-02-26 能否用Windows服务器作为路由器?(基本配置篇)
  •  2022-02-25 Linux 软路由网络吞吐优化设置
  •  2022-12-12 Linux Kernel 日志排错分析和处置三例
  •  2023-04-16 Windows 服务器网络性能调优系列操作系统篇
  • 微信订阅号二维码

    本页网址二维码:

    本栏目热门内容
  • Acrobat虚拟PDF打印机执行打印时挂起,解决办法竟然...
  • LINKSYS交换机登录WEB界面显示不正确的解决方法
  • 又一次RAID 5阵列故障记录
  • 解决VMware vSphere ESXi 5.0 Update 1 中虚机不能...
  • 修改CentOS发行信息以绕过Dell服务器BIOS更新和DSET...
  • 解决虚拟化运行的 Windows Server 2003 标准版出现...
  • Windows Server 2008 重命名域和域控制器
  • Intel Nehalem CPU Errata 导致 VMWare ESXi(vSpher...
  • 一次很精神的电脑组装过程记录(但不是自己的电脑)...
  • 解决MySQL Cluster 备份总是失败,提示文件已存在的...
  • MegaCli安装及使用杂记
  • 解决WSUS显示客户端不全的问题
  • 解决 VMWare vSphere 6 客户端无法修改用户密码
  • 解决Windows Server 2008 R2域控制器显示无法连接到...
  • 本站服务器RAID 5阵列双硬盘失效挽救记录
  • 网站数据库从MySQL 5.0升级到5.6的记录
  • 解决MariaDB使用Percona XtraBackup增量备份出错
  • DELL PowerEdge 820 报CPU3 INTERNAL ERROR 的解决...
  • Linux 下的分区调整工具GParted实战
  • 修改arpwatch使通知邮件主题显示IP地址
  • 程序员漫画:如何用8种不同的编程语言去解救公主
  • 解决很好用的多合一即时通信软件pidgin的崩溃问题
  • 解决Samba WINS服务的错误解释问题
  • 使用 GParted 进行虚拟机硬盘分区调整操作
  • 解决Squid代理HTTP时在浏览器出现Content Encoding ...
  • 用Delphi编写使用到ADO的DLL的一些问题
  • 网站简单改版
  • 索尼系列手提电脑备份失败,出现700错误的解决办法
  • Dell R900服务器 BMC firmware incompatible with C...
  • 更多...