☆ 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的字节