继上篇:nfs协议,写文件流程分析,继续理解nfs协议的网络通信。
通过开源项目go-nfs-client理解nfsv3的rpc通信协议,从而知道怎么解析抓取的数据包,获取需要的信息。
nfs rpc请求:
uint32 4字节消息id
uint32 4字节消息类型(rpc请求的消息类型为0,rpc响应的消息类型为1)
Body 不定长NFS协议请求参数
nfs rpc响应:
uint32 4字节消息id
uint32 4字节消息类型(rpc请求的消息类型为0,rpc响应的消息类型为1)
uint32 4字节rpc状态码
如果rpc状态码为0
{
uint32 4字节填充,没有意义
uint32 4字节响应参数偏移量,需要跳过:res.Seek(偏移量, io.SeekCurrent)
..... 被跳过的字节(长度=偏移量)
uint32 4字节rpc响应状态码,如果0为成功,其它为失败
Body 不定长度NFS协议响应参数
}
否则
{
uint32 4字节rpc拒绝状态码
}
nfs rpc的请求Body不只有请求参数,还有请求头,这是不同于响应Body的地方。请求头用来标识请求的是哪个操作等信息。
nfs协议通用请求头:
uint32 4字节RPC版本号。
uint32 4字节NFS程序的标识符。100003表示使用的是NFS版本3的程序标识符。
uint32 4字节NFS程序的版本号。3表示使用的是NFS版本3。
uint32 4字节NFS程序中的具体过程(操作)。例如3表示执行的是LOOKUP操作、7为WRITE操作、8为CREATE操作等,NFS协议文档有提供具体操作的值。
{
uint32 4字节身份验证的类型或方式。不同的Flavor值对应不同的身份验证机制,例如UNIX认证、Kerberos认证等。
[]byte 不定长度的身份验证的具体内容或数据。它是一个字节切片([]byte),用于存储身份验证所需的数据。具体的内容和格式取决于所使用的身份验证机制和Flavor值。
} Cred 客户端的身份验证信息。
{
uint32 4字节身份验证的类型或方式。不同的Flavor值对应不同的身份验证机制,例如UNIX认证、Kerberos认证等。
[]byte 不定长度的身份验证的具体内容或数据。它是一个字节切片([]byte),用于存储身份验证所需的数据。具体的内容和格式取决于所使用的身份验证机制和Flavor值。
} Verf 验证信息。rpc.AuthNull表示使用的是空验证。
验证信息Auth结构体如下:
type Auth struct {
Flavor uint32
Body []byte
}
通常Verf为Null,这种情况下Auth结构体的Flavor为0,整个结构体大小为4个字节。
通常Cred为UNIX,这种情况下Auth结构体的Flavor为1,Body如下:
uint32 4字节客户端时间戳(纳秒)
string 不定长,表示客户端机器名称或主机名
uint32 4字节用户id
uint32 4字节用户组id
uint32 4字节表示附加组ID(Additional Group ID)的数量
uint32 4字节表示附加组ID的列表
rpc请求的Body在header之后就是具体操作的请求参数了。
从rpc请求头和Body请求头大部分字段都能知道长度,但是UNIX验证信息表示客户端机器名称或主机名的字段是个字符串,那么服务端反序列化怎么知道长度是多少呢?
这就要说到xdr编解码协议了,nfs的rpc协议采用xdr编解码协议来编解码数据包。
在xdr中,对于不固定长度的字段,通常会在序列化时在字段前面添加一个固定长度的字段来表示实际数据的长度。这个长度字段通常是一个整数,用于指示后续数据的长度。
我们也可以直接用github.com/rasky/go-xdr
库来编解码数据包。
这里有一篇文章介绍的更专业一点(linux nfs NetworkTracing),介绍了nfs协议的rpc请求头、rpc请求、rpc响应,可以看看。