最近搭建实验室网络和服务器,初试 RedHat EL 发行版。 感受企业级发行版和 Geek 级发行版的差异,重新体会 ArchLinux 的 KISS 原则。

先介绍下实验室的网络环境,一共两间房:楼下的机房和楼上的实验室。 机房有一台 H3C ER 路由器和一台交换机,实验室有一个路由器、一个交换机,加两个 WiFi 热点。 机房有两根线接上来到实验室。 我的任务是把机房的两台 RedHat 接入实验室网络并提供代理和 VPN 服务。 麻烦在于我只知道这两台机器是 RedHat,其他一无所知。

用 Console-COM 接口重置路由和重新接通实验室和机房网络之后,终于可以 ping 到我要去配置的服务器了。 本文的故事从登录到服务器开始。

重置密码成功

当然,首先要重置 root 密码。重启、进入 grub、编辑启动项、选择并编辑内核参数、最后加一个 1、启动并进入单用户模式。然后的操作就熟为人知了:重置 root 密码,添加用户并加入 sudoers

passwd
useradd harttle -g wheel
passwd harttle
vim /etc/sudoers # 允许wheel group
exit

根据 archlinux 来的习惯,我甚至准备 yum install vim sudoers。惊喜地发现这些软件 RHEL 都内置了,也许编辑 sudoers 也并非必要。像 centOS 一样,一经安装便是一个完整的服务器操作系统,而且提供长期维护的版本,确实是服务器的绝佳选择。

此时我已经是管理员用户了,那么在系统启动后登录我的账号,一眼就认出来四年前见过的 Gnome,怀旧的情愫油然而生。接下来配置网络!

配置 DHCP 失败

懒得找从哪里打开 console,于是 Ctrl+Alt+F1 打开 TTY1,居然是不响应键盘的启动 log!然后继续 Ctrl+Alt+F2 打开 TTY2,OK,登录。然后习惯性地开始配置网络:

ip link
ip link set eth0 up
ip addr add 192.168.x.x dev eth0
ip link set eth0 netmast 255.255.255.0 broadcast 192.168.1.255

这样设置好 IP 与掩码之后才会与路由器位于同一网段,才能登录到路由器。ArchLinux 中甚至没有内置 ifconfig(在 net_tools 中)和 iwconfig(在 wireless_tools 中),因为 ip 就可以完成所有配置呀!ArchLinux 就是这么名副其实的 Simple。

接着用 firefox 去路由器,绑定静态 DHCP。然后呢,就来通过 DHCP 来获得地址吧:

$ dhcpcd eth0
Command dhcpcd not found
$ ps aux | grep dhcp    # 没有~~~~(>_<)~~~~ 
$ dhc <Tab> <Tab>
$ dhclient eth0         # 原来是这样
$ ip addr               # 仍然没分配到地址

如果这时候你希望从 Gnome 桌面的网络连接模块里得到信息的话,我告诉你里面甚至连本地连接接口都没有!不要使用 GUI 做系统管理。

来,开始排错!Ctrl+Alt+F3 打开 TTY3,监听 DHCP 报文:

tcpdump -n -i eth0 port 67 or port 68

回到 TTY2,再来一次 dhclient eth0,提示已经在运行。哦,原来是后台进程,ps 出来 kill 掉。再来一次 dhclient eth0,提示已发送信号给 DHCP 客户端守护进程,同时 TTY3 没有任何响动。擦,是后台进程但不是守护进程!总之 dhclient 并未发送 DHCP 报文,也没有提示错误或者警告

在 ArchLinux 中 dhcpcd 是 DHCP 客户端守护进程,每次命令的调用都会发送一次 DHCP 报文,立竿见影。

配置 SSH 失败

没办法,就用现在的静态 IP 继续设置 sshd,这样我就可以远程操作了!

vim /etc/ssh/sshd_config
# 禁止root用户登录、检查端口是否正确、设置AliveInteval、AllowUsers、etc。

在路由器映射 22 号端口后测试 ssh!在本地 ssh harttle@localhost 登录成功!ssh harttle@<路由器公网IP> 连接失败!同时 tcpdump port 22 可以看到收到了路由器转发来的 SSH 报文,难道是路由表?

vim /etc/sysconfig/iptables
# 检查filter是否REJECT了eth0上与ssh有关的包

路由表没问题,试着重启 service iptables restart,仍不起作用。到此为止,回家睡觉!

按照 RedHat 的习惯重新配置

第二天,对上述的失败反思了很久。用了这么久的 ArchLinux,相信如上的命令没有问题。来一本鸟哥,学习一下 CentOs,毕竟和 RedHat 是一样的源码。读后恍然大悟:

vim /etc/sysconfig/network-scripts/ifcfg-eth0
# 发现这里是原来管理员的设置,静态IP与静态路由,但开启了dhcp,改正之。
/etc/init.d/network restart
# 一切都好了。DHCP正常、SSH连接成功。

原来 RedHat 是这样配置的。确实 Simple,满足服务器操作系统的一大需求。 为什么这样 Simple 却花费了我如此多的功夫呢?我的命令也正确为什么没有得到应有的结果?这正是因为 RedHat 并无 KISS 原则

Keep it simple, stupid.

首先根据 RFC-2131,DHCP 作为局域网内的协议,其功能是:为主机提供 Internet 配置。在多数实现中该配置都包括了 IP、掩码、广播、DNS、路由。然而 dhclient 未能将得到的这些字段都进行设置,因为 /etc/sysconfig/network-scripts/ifcfg-eth0 是这样配置的:

BOOTPROTO=dhcp
IPADDR=192.168.1.72
NETMASK=255.255.255.0
GATEWAY=192.168.1.2

这里的路由是 192.168.1.2,导致 sshd 可以接收到 SSH 报文,但却发送不出去。于是局域网内可以 SSH(根据 RFC791 的 IP 协议,此时不经过路由,而是通过 ARP 来直接寻找 MAC 地址),但不能通过局域网的路由从外部访问。

严格地说该配置是有误的。开启 DHCP,却指定了静态网络配置。RedHat 没有抱怨而是选择了容错,这样的策略使得网络配置更加灵活,例如可以部分设置采用 DHCP ;但造成了 dhclient 命令没有达到预期的结果。其原因很简单, 该策略比较 complex,不满足 simple 原则

其次,dhclient 只是发送信号给守护进程,而不保证执行用户的意图:发送 DHCP 报文。这样的设计虽然通过更复杂的逻辑避免了额外的 payload,其后果就是未能执行承诺的操作。原因仍然很显然, 这样的策略比较 smart,不满足 stupid 原则 。让你发 DHCP 你就发 DHCP,自作聪明地忽略该操作将会让 tcpdump 无法追溯到出了什么问题!

RedHat 服务器配置

既然装好了,把常用的配置都记录一下,以免今后忘记。我这里的版本是 RedHat6.3。

yum 源

所谓“源”不就是软件包的获取地址,相同平台上系统,具有相同的系统调用,自然软件包是通用的。 CentOS 是基于 RedHat 的源文件开发的,因此如果你不想支付数千元服务费给红帽,就使用 CentOS 的源。 教育网源对教育网用户是最方便的,这个 ustc 的源就很好。拷过来!

因为 RedHat 和 CentOS 的 $releasever 产生方式不一样,会导致源的 url 有区别,结果就是获取源时发生 HTTP 404。 进入 /etc/yum.conf/etc/yum.repos.d/rhel-source.repo,用 vim 替换一下~(:%s/\$releasever/6/g) 然后更新:

yum clean all
yum makecache
yum -y update

VPN 或代理

为了更好地利用 Internet,外网服务器最常搭建的就是 VPN 服务。 VPN 协议有多种,而 pptp、l2tp 需要路由器支持。 当然可以使用 openVPN 等上层协议的 VPN 工具,其代价便是客户端都需要安装特定的程序。 于是我们决定使用代理服务器,以当前较流行的 squid 为例。

而普通路由器之所以能让多台主机共享互联网 IP,依赖于其 NAT 地址转换。NAT 地址转换需要用到 TCP/UDP 的端口字段。pptp 是直接运行在 IP 层之上的协议,并无端口字段,一些路由器可以利用它的其他无用字段来实现 NAT 穿透,于是 pptp 协议需要特殊的路由器。

更改路由表的 filter 表,即 RedHat 防火墙:

# file: /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3128 -j ACCEPT

安装 squid 后,配置 squid:

# file: /etc/squid/squid.conf
http_access allow all

启动 squid:

# 开机启动
chkconfig squid on
# 启动
service squid start

再通过路由器的端口映射就可以使用了。

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2014/10/09/kiss.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。