☆ 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} ::=
\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的字节