Skip to content

☆ finger协议(RFC 1288意译版)

http://www.ietf.org/rfc/rfc1288.txt https://scz.617.cn/network/200511092108.txt

历史上总共出过四个版本的RFC介绍finger协议([1]),RFC 1288代替了前三个版本, 一般只需查阅1288即可,这个版本是1991年12月出场的。

fingerd是一种远程用户信息程序(RUIP),finger协议就是与fingerd之间的通信协议。 最流行的fingerd实现源自BSD UNIX,因此这几份RFC也是围绕Berkeley实现展开。

fingerd侦听79/TCP口。某些版本的Linux上的/etc/services文件中另有如下信息:

finger 79/tcp finger 79/udp cfinger 2003/tcp

我不清楚79/UDP是怎么来的,反正RFC 1288中没有提及,也可能是Linux自身的增强 实现,又或是services文件的胡说八道。至于cfingerd,上网查了查,是个fingerd 的增强实现,也没听说侦听2003/TCP啊,我比较孤陋寡闻吧。这次只关心79/TCP,不 纠缠其它。

fingerd等待来自客户端的请求并响应之,然后主动关闭相应的TCP连接。客户端正是 靠FIN包确认响应数据接收完毕,响应内容本身并没有长度标识或结尾标识。

通信报文中允许出现[0x80,0xFF]区间的字节。

finger查询请求的BNF(巴克斯-诺尔范式)定义如下:


{Q1} ::= [{W}|{W}{S}{U}]{C} {Q2} ::= [{W}{S}][{U}]{H}{C} {U} ::= username {H} ::= @hostname | @hostname{H} {W} ::= /W {S} ::= | {S} {C} ::=

\r\n,即\x0D\x0A

空格,即\x20。

{S}

这个是递归定义的,意味着空格可以重复任意次数。

/W

/W由最后直接处理查询请求的RUIP(相对forward行为而言)负责解释,一般指明
冗余输出。最坏情况下,RUIP简单忽略它。

RFC 1196中/W错误地出现在行尾,这是一次低级错误:

{Q1}    ::= [{U}][/W]{C}
{Q2}    ::= [{U}]{H}[/W]{C}

从4.3 BSD起fingerd的实现就是把/W放在行首的。

{H}

这个是递归定义的,意味着"@hostname"可重复任意次数。

{U}

username的定义比较含混,RFC 1288要求username涵盖"login name"与"name in
real life"。历史上各种fingerd的实现对username的理解不一,许多安全问题
应之而生,需要实测。比如Solaris 8的实现,下两种请求等价:

"/W Super-User\r\n"
"/W root\r\n"

{Q2}

这种格式的请求需要第一个RUIP允许forward行为。假设A向B发送如下请求:

"root@HostC\r\n"

B收到查询请求后,向C发送如下请求:

"root\r\n"

B必须向A转发来自C的所有响应,等待C主动关闭TCP连接,然后才能主动关闭自
身与A之间的TCP连接。

我在这里有个疑问,"root\r\n"并不符合{Q2}、{Q1}中的任一个。这个BNF定义
是否也犯了低级错误,少考虑了一种情况?"root@HostC\r\n"符合{Q2},按RFC
1288处理下来,必然出现"root\r\n"这种不在BNF定义之中的查询请求。总觉得
应该修正如下:

{Q1}    ::= [{W}|{U}|{W}{S}{U}]{C}

对照RFC 1196,更加坚定我这个想法。

应该可以配置RUIP是否允许forward行为。如果RUIP被配置成不允许forward行为,
该RUIP必须明确返回服务拒绝类的信息,比如:

"Finger forwarding service denied"

Aix的fingerd缺省没有指定"-f",即不允许forward行为,其拒绝信息为:

"Finger forwarding service denied.\n"

Linux的fingerd缺省没有指定"-f",即不允许forward行为,其拒绝信息为:

"fingerd: forwarding not allowed\r\n"

Solaris 8的fingerd没有命令行参数禁用forward行为,缺省就允许。

RFC 1288建议缺省禁用forward行为。

{C}

这种查询在请求返回在线用户列表。如果RUIP不拒绝这种请求,必须在响应中至
少包含用户的全名(name in real life),其他信息则是实现相关的。

应该可以配置RUIP拒绝此类请求。如果RUIP被配置成拒绝此类请求,该RUIP必须
明确返回服务拒绝类的信息,比如:

"Finger online user list denied"

Solaris 8和Aix的fingerd没有命令行参数拒绝此类请求。Linux的fingerd有个
"-u",指定后将拒绝{C}查询,其拒绝信息为:

"Please supply a username\r\n"

但我手头这个版本缺省未指定。

{U}{C}

这种查询在请求返回指定用户{U}的信息,无论该用户是否在线。RUIP必须响应
这种请求,如果你打算拒绝这种请求,就不要开启finger服务。

必须在响应中至少包含用户的全名(name in real life)。如果该用户在线,那
些在{C}响应中出现的该用户的信息必须在{U}{C}响应中出现。其他信息则是实
现相关的。

RFC 1288指明每个用户可以自制一个用户信息文件,该文件的内容可以出现在响
应报文中。但1288没有规定实现细节,换句话说,对用户信息文件的支持是实现
相关的。一般实现中该文件是:

$HOME/.plan

应该可以配置RUIP是否使用用户信息文件。

RFC 1288指出RUIP可以在响应查询请求时执行一个程序,但这是个危险的特性,一是 不建议实现这个特性,二是即使实现了也应该可以通过配置禁用。绝大部分fingerd 的实现都借助于finger,我猜RFC 1288的意思不是指这种情况。

RFC 1288建议将finger查询请求记入日志。

RFC 1288还就客户端安全做了一些建议。缺省情况下客户端应该过滤响应内容中的不 可打印字符,只保留\r、\n、\t以及[0x20,0x7E]区间的字节。客户端可以考虑实现 两个命令行参数改变缺省行为以支持类似中文这样的语言:

1) 允许所有小于0x20的字节

2) 允许所有大于0x7E的字节