使用 CentOS 实现小型网络路由 - 基础服务

前些时间入手 Gen8 一台,这东西作为家用虚拟化平台是不错的选择。作为一开始的设想,是想将它唯一的 PCI-e 用来插显卡,配合 VT-d 技术直通入虚拟机,而在 ESXi 上跑别的服务。那么,首先需要一个可靠的路由来做外网 NAT,于是就有了这篇。

关于软路由系统的选择,参考了这篇 WIKI
首先并不是很喜欢使用普遍路由中使用的 DD-WRT or OpenWrt,DD 是因为功能不满足需求,而 OpenWrt 直到 15.05 才有官方的 x86-64,暂且不论兼容性,有许多包在 64 位需要自己编译,并且最新版的 OpenWrt 移除了 14.x 中的 oldpackages,导致 pdnsd 也没了。一直在使用的 RouterOS 配置简明,但是在 x86 上表现一般,且没有第三方的包(没有 VMXNET3 驱动),后来选择了 VyOS(前身Vyatta),看中的就是这玩意带一个类似硬路由的 shell,可惜使用时由于其官方 community 源 404,还是 pass 了。

想来 Linux 用起比较顺手,就干脆用它来用作路由。看了一圈最后还是选了 CentOS,虽然其官方文档惨不忍睹,但是有 RHEL 这个老爹在,光是网络部分的文档就有 12 章之多,RHEL 文档地址

开工之前首先先回想一下实现一个简单的路由需要哪些服务。

  • NAT: Masquerade、转发流量就靠它了
  • DHCP Server: 用来分配内网机器地址
  • DNS Server: 域名 IP 映射,这里目标是配一个无劫持的 DNS
    接着就是开工了:

配通本机网络

确保本机 route 正确,能正常 ping 通外网 IP,这个就不多介绍了。

提醒一下 CentOS7 自带的 nmcli 似乎有问题,于是下篇绕过这个管理器直接使用 CLI 来配置网络

1
2
systemctl stop NetworkManager
systemctl disable NetworkManager

本示例网卡分配情况:qq%e6%88%aa%e5%9b%be20161124220734

配置各个网络介面

1
vi /etc/sysconfig/network-scripts/ifcfg-br144
1
vi /etc/sysconfig/network-scripts/ifcfg-eno50338560
1
vi /etc/sysconfig/network-scripts/ifcfg-eno50338560.128
参考配置
网桥 (ifcfg-br144)
1
2
3
4
5
6
7
8
9
DEVICE=br144 #桥接设备名:brX
TYPE=Bridge
IPADDR=172.16.144.1 #IP 地址
PREFIX=20 #网络标识
GATEWAY=172.16.144.1 #网关地址
BOOTPROTO=none
ONBOOT=yes
MTU=9000
STP=yes #启用 STP
普通端口 (ifcfg-eno33559296)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TYPE=Ethernet
BOOTPROTO=none #静态地址,如若是外网口设为dhcp
DEFROUTE=no #不添加默认路由,如若是外网口设为yes
PEERDNS=no #不添加默认 DNS,如若是外网口设为yes
PEERROUTES=no
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6_DEFROUTE=no
IPV6_PEERDNS=no
IPV6_PEERROUTES=no
IPV6_FAILURE_FATAL=no
NAME=eno33559296
UUID=cf803907-bfb2-4157-9bee-79050d505cb4
HWADDR=00:0c:29:20:7c:38 #根据实际 MAC 地址修改
DEVICE=eno33559296
ONBOOT=yes #随开机 UP
MTU=9000 #修改 MTU
BRIDGE=br144 #添加此行将此端口加入桥 br144,不需要添加 IP 设定,改为在桥 br144 中添加
VLAN端口 (ifcfg-eno50338560.128)
1
2
3
4
5
6
7
8
DEVICE=eno50338560.128 #普通端口名.VLAN_ID
BOOTPROTO=none
ONBOOT=yes
MTU=8972
IPADDR=172.16.128.1 #IP 地址
PREFIX=20 #网络标识
NETWORK=172.16.128.0 #所在网络
VLAN=yes #VLAN口
配置完毕重启网络服务
1
systemctl restart network

qq%e6%88%aa%e5%9b%be20161124210139

DHCPd

这里不使用 Dnsmasq 自带的 DHCP-Server,而是用 DHCPd 来实现(因为直接有官方文档),安装
1
systemctl disable NetworkManager
安装完毕后会自动生成一个配置示例
1
/usr/share/doc/dhcp-{version}/dhcpd.conf.example
我们可以复制这个示例,也可以完全自己写,这里按照自己需求写
1
vi /etc/dhcp/dhcpd.conf

qq%e6%88%aa%e5%9b%be20161124210042qq%e6%88%aa%e5%9b%be20161124210054

启动&开机自启
1
2
systemctl start dhcpd
systemctl enable dhcpd
这里如果报错,使用 journalctl -xe 查看

很有可能是 DHCPd 中的设置网段 并没有在当前端口中找到,检查 II 中的配置,并确保端口 UP 状态。
6. ###### 2016.11.26 补充:此版本(4.2.5-42) DHCPd 有 BUG,会意外退出。参考

  • 解决方案:
1
vi /etc/NetworkManager/dispatcher.d/12-dhcpd

找到行,添加带有 ‘+’ 的两行

1
2
3
4
5
6
7
if [ "$STATUS" = "up" ]; then
# restart the services
+ systemctl reset-failed dhcpd.service
systemctl -q is-enabled dhcpd.service && systemctl restart dhcpd.service
+ systemctl reset-failed dhcpd6.service
systemctl -q is-enabled dhcpd6.service && systemctl restart dhcpd6.service
fi

Dnsmasq

系统自带了 Dnsmasq,我们只需要配置好,设置启动就可以
编辑配置文件
1
vi /etc/dnsmasq.conf

注意以下编辑选项,其他选项我这里都是被注释状态:

1
2
3
4
5
6
7
8
9
10
11
domain-needed #只解析合法域名
bogus-priv
no-resolv #不读取 /etc/resolv.conf
no-poll #不读取 /etc/resolv.conf
server=127.0.0.1#5353 #上游 DNS 地址,这里设置成本地 5353 口,是因为有 ChinaDNS 监听在此端口,达到不被污染劫持的目的,具体配置在下一篇说
except-interface=eno16780032 #不监听外网端口,根据需要修改
no-dhcp-interface=br144 #不监听 DHCP 请求
no-dhcp-interface=eno50338560 #不监听 DHCP 请求
no-dhcp-interface=eno50338560.12 #不监听 DHCP 请求
cache-size=2000 #做 DNS 请求缓存
conf-dir=/etc/dnsmasq.d #加载额外配置文件的目录,这个后面优化无污染 DNS 时候用到

qq%e6%88%aa%e5%9b%be20161124205854

启动&开机自启
1
2
systemctl start dnsmasq
systemctl enable dnsmasq
添加 iptables 规则
1
2
3
iptables -I INPUT -p udp -m state --state NEW --dport 53 -j ACCEPT
iptables-save > /etc/sysconfig/iptables
systemctl restart iptables
测试,若失败请确认上游 DNS 可用,监听设置正确
1
dig @127.0.0.1 google.com -p53

qq%e6%88%aa%e5%9b%be20161124224342

配置 NAT

这个核心功能就由 iptables 来完成,安装基础配置请参考 CentOS7 基础配置
添加 Masquerade 规则,将内网流量伪装发送至出口端口 (eno16780032)
1
iptables -t nat -A POSTROUTING -o eno16780032 -j MASQUERADE

qq%e6%88%aa%e5%9b%be20161124204739

放行所有内网 INPUT FORWARD 请求
1
2
3
4
5
6
7
8
9
10
iptables -I INPUT -i br144 -j ACCEPT
iptables -I INPUT -i eno50338560 -j ACCEPT
iptables -I INPUT -i eno50338560.128 -j ACCEPT
iptables -I FORWARD -i br144 -j ACCEPT
iptables -I FORWARD -o br144 -j ACCEPT
iptables -I FORWARD -i eno50338560 -j ACCEPT
iptables -I FORWARD -o eno50338560 -j ACCEPT
iptables -I FORWARD -i eno50338560.128 -j ACCEPT
iptables -I FORWARD -o eno50338560.128 -j ACCEPT
iptables-save > /etc/sysconfig/iptables
检查配置,按情况调整 INPUT/FORWARD 链规则位置
1
iptables -L
1
vi /etc/sysconfig/iptables
1
systemctl restart iptables

qq%e6%88%aa%e5%9b%be20161124204955

至此基本路由功能配置完毕,还是挺省资源的。配合 ss-redir 实现 FxxkGFW 在下一章讲qq%e6%88%aa%e5%9b%be20161124210417