经典的 inetd 守护程序已经存在很久了。有几种替换 inetd 的功能的方法,但是最灵活、最简便的方法似乎是 xinetd。inetd 能做的,xinetd 也能做,并且 xinetd 还能做更多的事情。譬如,TCP 封装、模块化配置、连接重定向和入站连接的负载限制,而这些只是使得 xinetd 成为系统管理员良好选择的部分特性。
本文是为从初学者到中级系统管理员这样的读者而准备的,并且文中的说明和示例并不尝试假设您已经熟悉 inetd。在本文中,我们将研究 xinetd 的一些简单用法,从安装到安全性策略的实现。
为实现本文的目的,您的系统最好安装了最近的主流(2000 或更新)UNIX(Linux、Solaris、BSD)。这些示例在 Perl 和 UNIX(以及其它操作系统)的早期版本上也可以运行,但是它们功能方面的障碍应该由读者作为练习来解决。给定的特定示例是用于 Red Hat Linux 的,但是它们在其它系统上应该也可以运行(除 chkconfig 以外)。
对于 UNIX 系统管理员,inetd 和 cp/rm/mv 命令一样基本。它总是存在,并准备着处理入站连接。 但它到底是什么?它用来做什么?
首先从 TCP/IP (它也包括 UDP,但我们目前还不考虑)开始回答。当您建立与一台主机的连接时,实际上是创建了一个 TCP/IP 连接(通常是一个套接字) ― 这好象是在您和主机之间打了一个电话。TCP/IP 连接由起始主机和接收主机唯一地定义,但还有其它标识。如果我们都连接到一台服务器,它如何区分 webserver、telnet、SSH、FTP 和其它连接呢?套接字也通过建立连接所使用的端口来定义。例如,端口 21 是入站 FTP、端口 22 是 SSH、端口 23 是 TELNET(有关其它大多数端口,可以查看 UNIX 系统上的 /etc/services)。
一旦建立了连接,某人就在另一端拿起了电话。这可以是接线员或直线。直线表示您直接连接到了服务器,而接线员是涉及 inetd 的方法。接线员实际上处理一组入站直线(主机上的端口),并亲自将它们交给负责的程序(服务器)。
UDP 是另一种连接方法。象 TCP 一样,UDP 基本上是和某人的对话,但是不保证它是可靠的。UDP(继续使用电话的比喻)就象将消息扔到传送带上,让接收者站到另一端。 您可以从传送带得到许多消息,但是如果消息太多(网络流量高)或者读取消息费时太久(服务器忙),则接收者可能会丢失一些消息。
如果使用 inetd,在执行一些检查后,您被重定向到特定服务器。只有一个配置文件 ― inetd.conf,管理所有入站连接。因而在系统上添加、删除、更改或复查服务变得更为简单。例如,在 Solaris 系统上使用 TCP 封装器将 ftp 定义如下:
清单 1,FTP 服务的 inetd.conf 定义
ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd |
这些是创建一个 FTP 连接所需的全部参数。 简单地说,我们以面向流(stream)的方式使用 TCP/IP(tcp)时,同时允许多个 FTP 连接(nowait)、作为 root 运行以及调用 FTP(接下来,TCP 封装器将调用 FTP 守护程序)。
用一上午的时间解析很困难吗?绝对困难。有必要这么复杂吗?不。xinetd 继承了 inetd 的设计并将它模块化,这意味着每个服务都可以存在于它自己的配置文件中。xinetd 还添加了一些象 TCP 封装器之类的功能部件,使得配置更加简单。
xinetd 保持了中央配置(接线员)方法,将所有配置文件存储到单一位置,通常是 /etc/xinetd.conf 和 /etc/xinetd.d/*,使系统管理员可以更容易地获得。模块化配置意味着,您可以通过将服务复制到 xinetd.d 目录来向多台机器上分发该服务,也可以用同类的手段除去它。甚至可以指定额外的包含目录。
最后,xinetd FAQ(请参阅本文后面的 参考资料)声明了 RPC 程序在 xinetd 下运行得不太好。不过没问题,对 RPC 使用 inetd,并对其它所有服务使用 xinetd。这就象雇了两个接线员,一个说西班牙语,另一个说所有其它语言。
那么 xinetd 是什么?一句话,它就是个程序。处理入站网络连接没什么神奇。可以使用 Perl、Python 或 Java 来处理。Xinetd 是用 C 编写的,而且它和它的前辈 inetd 一样快,如果不是更快的话(例如,TCP 封装器不必为每个入站连接而执行;它们在启动时装入内存)。
xinetd 正在开发中。(您的版本可能过时了,所以请务必到主页上查找最新的版本;请参阅 参考资料。)因为它正在开发中,所以 xinetd 的安全漏洞得以迅速弥补,而不象 inetd 那样薄弱,通常要很长时间才能弥补。当然,xinetd 是随源代码一起交付的,所以您可以复查源代码并自己找到可能存在弱点的地方。
如何使用 xinetd 定义服务呢?编写一个服务文件,它除了指定 /etc/xinetd.conf 中所指定的一般参数之外,还指定特定配置。所以,如果 /etc/xinetd.conf 是这样的:
清单 2,样本 xinetd.conf(标准的 Red Hat 7.1)
defaults
{
instances = 60
log_type = SYSLOG authpriv
log_on_success = HOST PID
log_on_failure = HOST
cps = 25 30
}
service telnet
{
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
disable = yes
}
includedir /etc/xinetd.d
|
您放到 /etc/xinetd.d 中的每个服务文件都会继承这些缺省值,并指定它自己的参数。这里,telnet 服务在顶级定义,而不是在子目录中定义。这太棒了,这种模块性允许复杂的配置。
要使 xinetd 重新读取配置文件,不必重新启动它。只要向它发送 USR2 信号即可。
那些参数表示什么意思?让我们通读整个清单。您也可以在命令行下使用
man xinetd.conf 来查看列表(如果那个帮助页面正确安装的话),但这个概述试图用更简单的术语来解释参数,并不假定您已经知道关于套接字和服务的所有信息。一些参数(rpc_version、rpc_number)被跳过。
- id
- 该服务的唯一名称。服务名称在花括号之前指定,但是 ID 使逻辑上相同的服务可能拥有多个协议。这是对于临时用户的受限使用。例如,NFS 服务可以在 UDP 或 TCP 传输协议上运行。在 Red Hat Linux 7.1 上,TCP 版本(在 /etc/xinetd.d/time 中)和 UDP 版本(在 /etc/xinetd.d/time-udp中)中提供了对于 xinetd 来说内部的时间服务。
- type
- 这实际上应该称为“特殊类型”,因为它只适用于特殊服务。它可以是以下几种类型的组合:“RPC”,用于 RPC 服务(由 SUN 引入的远程过程调用,导致了很多安全性问题,最好避免使用);“INTERNAL”,用于构建到 xinetd 内部的服务,譬如时间服务;“UNLISTED”,用于在系统列表(/etc/services 或用于 RPC 服务的 /etc/rpc)中找不到的非标准服务。
- flags
- 这里放置着所有额外标志。列表很长并且技术性很强;我们感兴趣的标志包括 REUSE(用于套接字重用,譬如 telnet)、NAMEINARGS/NOLIBWRAP(如果您希望手工调用 TCP 封装器或者完全地避免使用封装器)、NODELAY/KEEPALIVE(用于调整 TCP 套接字)、DISABLE(覆盖顶级“disable”参数)以及 SENSOR(用于检测和防止某些类型的“拒绝服务(denial-of-service)”网络攻击)。
- disable
- 除非您希望禁用某项服务,否则总是把它设成“no”。Red Hat Linux 的 chkconfig 程序将为您打开或关闭“disable”参数;在 Red Hat 上,用 chkconfig 启用和禁用特定服务可能比手工方式简单些。请注意,chkconfig 预期在 /etc/xinetd.d/SERVICE 中找到服务文件。所以对于上面 清单 2 中的示例,chkconfig 将不会在请求时打开或关闭 telnet。可以将它认为是一个错误或特性,取决于您的观点。
- socket_type
- 通常您希望这个参数设置成“stream”,除非使用 UDP 服务,此时设置成“dgram”。该参数也可以设置成“raw”和“seqpacket”,但极少见。
- protocol
- 这是连接所用的协议,通常是“tcp”或“udp”,但是在理论上您可以使用来自 /etc/protocols 的任何值。
- wait
- 如果设置成“no”,xinetd 将为每个连接上的服务启动一个新的处理程序。如果是“yes”,xinetd 预期该处理程序处理所有后续连接直到它死亡。在大多数情况下,这个参数是“no”。
- server, server_args
- 处理程序的程序名,以及它应当获得的参数。处理程序名不应该象在 inetd 环境下那样,出现在参数中。
- port
- 服务的端口。通常不需要,因为端口通过 /etc/services 文件来映射到服务。
- redirect
- 允许 xinetd 将所有服务的流量发送给另一台主机。因此,受防火墙保护的主机可以通过中央 xinetd 转发器接受安全流量,而不必建立与外部网络的连接。在某些工作中,可以采用这个特征来在两台主机间执行故障转移服务。
- banner, banner_success, banner_fail
- 一个将要在“任意/一个成功/一个不成功”连接上打印的来自文件的定制文本块。
- enabled
- 在全局级别上补充“disabled”参数和 DISABLE 标志。
- include, includedir
- 告诉 xinetd 要包含文件或目录。
- user, group, umask, groups
- 当启动服务处理程序时,xinetd 应该扮演的 UNIX 属性。这主要用于非安全服务。
- nice
- 确定该服务对于系统有多重要的 UNIX 优先级级别。可以针对您的系统调整它,请查看“nice”的 man 页面。
- env
- 用于服务处理程序的环境变量。
- passenv
- 应该向下传递到服务处理程序的 xinetd 中的环境变量。
- instances
- 可以同时启动的处理程序数。可以调整这个参数以防止拒绝服务攻击。如果您希望缺省(无限制)行为,将它设置成“UNLIMITED”。
- max_load
- I: ) 如果系统过载,停止接受连接。负载数取决于系统,仅当您确实知道自己在做什么时才能调整它。
- rlimit_as, rlmist_cpu, rlimit_data, rlimit_rss, rlimit_stack
- rlimit 参数指定用于服务处理程序的资源限制(内存、CPU 以及特定内存区域)。
- only_from, no_access
- 对 TCP 封装器的补充,这是阻挡主机建立与我们的连接的方法之一。请注意,缺省值是允许对任何人的访问,除非 TCP 封装器(其规则通常在 /etc/hosts.allow 中)另有规定。
- access_times
- 一天中服务可用的时间。例如,“6:00-23:00”意味着服务从上午 6 点到晚上 11:01 可用。
- log_type, log_on_success, log_on_failure
- 各种日志记录选项。USERID 标志可能特别麻烦,因为它向连接的主机询问关于与我们连接的用户,这使得处理变慢。尽可能避免使用 USERID。
- bind
- 允许服务特定于接口,通常是出于安全性考虑。例如,在网络内部的 FTP 服务只是 FTP,而外部 FTP 连接将生成入侵者警报。“id”参数在这里很有用。
- per_source
- 指定来自源 IP 的服务的最大实例数。对于处理“单源拒绝服务(single-source denial-of-service)”攻击或出错程序建立的过多连接非常有用。
- cps
- 每秒允许的最大连接数,以及服务再度启用之前的秒数。“30 45”表示“每秒 30 个入站连接,如果超过限制,则等待 45 秒”。主要用于对付拒绝服务攻击。
- deny_time
- 对引发 SENSOR 标志的人拒绝服务的时间。
经典的 TCP 封装器软件包是个非常有用的工具。通过一个集中式的文件(通常是 /etc/hosts.allow 和 /etc/hosts.deny),针对每个服务,根据需要来允许或拒绝对任何主机的访问。 不幸的是,TCP 封装器库不太了解系统负载、资源限制、多重攻击之类的情况。xinetd 合并了 TCP 封装器功能性(通过 libwrap 库),所以您可以顺利地迁移到 xinted,并继续使用和以前相同的配置文件。
这差不多就是迁移所要做的全部工作了。保持旧的 hosts.deny 和 hosts.allow 文件,xinetd 将乐意遵循它们。但是,请牢记,xinetd 有许多在 TCP 封装器基础上改进的连接控制选项。例如,限制每秒连接数或过载时的连接数,可以成为对服务器管理极有价值的帮助。
确保您是使用 libwrap 选项编译 xinetd 的,否则,它将不知道 TCP 封装器。如果 xinetd 来自于 Red Hat Linux 上的 RPM,确保您在开放机器“之前”,测试 TCP 封装器文件是否正常运行。
尽管可以有多种方法使用 xinetd,redirect 参数为我们提供了最有趣的使用方法。众所周知,故障转移很难实现,并且硬件故障转移很昂贵。 这里所描述的方法(通过简单的软件)既便宜又有效。它具有单故障点 ― 重定向点,所以您应该考虑该方式是否可接受。如果不能接受,那么,硬件故障转移就贵得有道理了。
首先,确定一种方法从两台或者更多的机器中选出一台“活动的”机器。 假设您通过一个脚本 set_active.pl 来完成(我们将为 telnet 服务完成该步,但是它对任何其他服务也有效,只要能保持服务切换到其他服务器而不带来不良影响)。脚本将采用我们用来设置新故障转移的机器名,以及给我们适当的用于编辑的 /etc/xinetd.d/SERVICE 文件的服务名。请随意定制脚本以编辑不同文件,或使用不同参数。可以用一行“perl -p -i -e”脚本执行这个作业,但您可以在将来对这种方法作许多扩展,并可以对参数执行错误检查。
这太简单了。现在只要决定调用这个脚本的过程即可 ― 可以是手工、通过一个 cron 作业、或者由另一个程序触发。此时,它成为体系结构决策。别忘了在这时向 xinetd 发送 USR2 信号,如果愿意,也可以重新启动它。在 Red Hat Linux 上可以用“pkill -USR2 xinetd”完成信号的自动化,而重新启动 xinetd 只要使用“/etc/rc.d/init.d/xinetd restart”(在 Linux 上)或者其它类似命令(在大多数 UNIX 系统上)。
这种故障转移将“不会”对数据库连通性生效,除非在数据库端做许多额外工作。建议您最好将它用于诸如 rsync、ssh、ftp 和 telnet 之类的协议,其中,故障转移机器彼此没有相互依赖性。
很清楚,xinetd 所提供的众多特性是选择它的一个好理由。但是,请不要忘记 xinetd 的其它好处:错误一经报告就得到修正、源代码免费可用以及从现有的 inetd 配置进行迁移(当您使用随 xinetd 一起交付的 itox 助手程序时)非常容易。
为什么不使用 xinetd?向后兼容性将成为您最好的理由,还有与您的特定平台的非兼容性。xinetd 软件在 Solaris 和 Linux 服务器上最流行,所以在您的特定平台上可能会有尚未解决的问题。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 获得 Perl
脚本来从两台或者更多的机器中选出一台“活动的”机器:
set_active.pl。
- 请查看
xinetd
主页。
-
xinetd FAQ
回答了许多问题。
- 请阅读
Frederic Raynal 的关于 xinetd 的文章。
- 获得 MacSecurity.org 的
xinetd
教程。
- 请阅读
developerWorks 上“功能丰富的 Perl”系列中 Teodor
的其它 Perl 文章:
- A programmer's Linux-oriented setup
- Application configuration with Perl
- Automating UNIX system administration with Perl
- Debugging Perl with ease
- The elegance of JAPH
- Genetic algorithms applied with Perl
- One-liners 101
- Parsing with Perl modules
- Perl 5.6 for C and Java programmers
- Reading and writing Excel files with Perl
- Review of Programming Perl, Third Edition
- 请浏览
developerWorks上的
更多 Linux
参考资料。
- 请浏览
developerWorks上的
更多开放源码参考资料。

Teodor Zlatanov,1999 年毕业于波士顿大学(Boston University),获计算机工程硕士学位。他从 1992 年以来一直担任程序员,使用 Perl、Java、C 和 C++ 语言。他的兴趣是用于文本解析的开放源码、三层客户机服务器数据库体系结构、UNIX 系统管理、COBRA 和项目管理。通过 tzz@iglou.com与 Teodor 联系。