NFS报文分析
NFS协议基于RPC协议,每个NFS报文都对应着一个RPC报文类型。除NFS报文外,PORTMAP,MOUNT等同NFS密切相关的报文也在分析范围内。除特别说明外,本次分析服务器IP为192.168.0.120,客户端IP为192.168.0.186。
查询远程可挂载的目录
NFS服务未开启如果服务器未开启NFS功能输入
showmount –e 主机名或IP
则在终端显示:
mount clntudp_create,RPC,Program not registered
主要交互流程:

客户端通过TCP与服务器的Portmap程序建立连接,尝试通过TCP远程调用GETPORT,服务器返回MOUNT功能为开启。然后客户端再次尝试通过UDP达到此目的,服务期同样返回PROGRAM_NOT_AVAILABLE。整个过程是基于RPC的。
NFS服务已开启

客户端首先通过PORTMAP远程调用请求MOUNT的端口。后面又重传两次,重传报文的XID相同的,而服务器就是通过XID来判断一个报文是否是另一个的REPLY。服务器得到请求后返回端口号33394。客户端使用33394端口来进行EXPORT类型MOUNT请求。服务器返回请求,内容如下:

Procedure:EXPORT下面的Value Follows代表List 是否还有内容。
在获取到这个List后会在终端显示:

挂载远程目录挂载远程目录的过程最本质的是如何获得此目录在服务器上的文件句柄,我们在分析下面的交互时始终以此为中心。
挂载不存在的目录

首先通过客户端通过一个基于TCP的RPC获得MOUNT的端口32771,之后,客户端试图通过MOUNT请求来获得/home/work_ro的句柄,从而实现远程挂载。但由于目录不存在,服务器会当作权限不够来处理,所以返回ERR_ACCESS。
成功挂载

前面的交互和目录不存在的情况基本相同,只是服务器在MOUNT请求后返回了要挂在目录句柄。此后通过PORTMAP得到NFS的端口,

挂载成功后,客户端还要通过PORTMAP得到NFS端口,NFS端口这一部分请参看RFC1094。
完成上面的交互后,请求的文件目录已经成功挂载到了本地。
通过TYPE为GETATTR类型的NFS报文得到挂载目录的属性,其中包括:文件类型,访问权限,文件大小,文件的归属者以及上次的访问时间等,如下图:

然后,客户端发出了FSSTAT请求,这个请求的内容为此目录的动态信息。如下图:

目录的动态信息包括,总大小,可用的小等。
客户端发送FSINFO请求,服务器返回目录的静态的信息。
挂载多个目录到本地现在,向服务器

可以看到,在请求第一个目录时,我们可以看到在一个基于TCP的PORTMAP请求后,服务器返回了一个PORTMAP报文。但在后面的两个目录的请求过程中却只有请求,没有回复。
管理远程目录管理远程目录包括:获取列表,新建目录,新建文件,删除目录,删除文件,修改文件,修改属性等。
获取远程目录

通过ll命令来查看目录下面的文件列表,目录root_ro(0x75ec0804)下有以下文件或目录:
aaa hello bbb ccc test test2
我们可以看到客户端会首先进行一次GETATTR的请求,来确认挂载的是目录或者是文件。在Type字段说明了类型。

请求GETATTR后,客户端发出对root_ro的ACCESS的请求,得到的报文主要内容如下:

说明客户端可以读root_ro但不可进行创建等操作。作为挂载的顶级目录,root_ro同样是不可LOOKUP的。除非挂载了root_ro的上一级目录。
在客户端得到allow READ的消息后,通过发送NFS的READDIR请求,得到目录内容列表。

通过这个报文的内容,我们可以看到,root_ro目录下的内容。
然后,客户端开始又一次请求对root_ro的ACCESS报文,这个动作贯穿于NFS的所有交互中。当前请求的目的是看是否有权限进行下面的对子目录的LOOK UP操作。
得到allow READ之后,开始逐个发送子目录或文件的LOOKUP报文。在服务器发回的Reply报文中包含了这个目录或文件的句柄File Handle。
“NFS中一个基本概念是文件句柄(file handle)。它是一个不透明(opaque)的对象,用来引用服务器上的一个文件或目录。不透明是指服务器创建文件句柄,把它传递给客户,然后客户访问文件时,使用对应的文件句柄。客户不会查看文件句柄的内容——它的内容,只对服务器有意义。
“每次一个客户进程打开一个世纪位于一个NFS服务器上的文件时,NFS客户就会NFS服务器那里获得该文件的一个文件句柄。每次NFS客户为用户进程读或写时,文件句柄就会传给服务器以指定被访问的文件。
一般情况下,用户进程不会和文件句柄打交道——之有NFS客户和NFS服务器将文件句柄传来传去。在第2版的NFS中,一个文件句柄占据32个字节,第3版中增加为64个字节。”
——TCP/IP详解:卷1
新建目录在挂载根目录下,新建目录test1

新建目录时,首先进行两次ACCESS请求,获得对挂载根目录的操作权限。
经过上面两次请求,客户端向服务器查询要建立的目录是否存在。服务器回复不存在。
客户端再经过一次ACCESS请求后,发送NFS的MKDIR报文。服务器在返回Reply时,同时返回新建目录的file handle。如下图:

图 11
改变文件属性

主要操作为:首先客户端请求对挂载根目录的权限,和根目录的属性来判断是否可以改变test1的属性。再进行一次权限的请求,然后获得test1的属性。最后通过SETATTR请求来改变test1的属性。
删除目录

主要交互过程和新建目录大致相同,不做冗述。
卸载远程目录

先获得MOUNT的端口32771,在通过此端口卸载远程目录。