Ethereal-dev: [ethereal-dev] NFS dissector continued
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Uwe Girlich <Uwe.Girlich@xxxxxxxxxxx>
Date: Thu, 4 Nov 1999 14:51:26 +0100
I just finished the first part of the NFS dissector. It can only dissect GETATTR requests and replies (V2 and V3) but it is a start. I want to discuss some points I found during the implementation: * How should I print times of files? NFS v2 uses a microsecond resolution and NFS v3 a nanosecond one. I would prefer a generic time print routine. * What do we do with 64 Bit numbers? I used %u, if the upper part is zero and %x%08x, if the upper part is non-zero. Maybe I can use %llu on GNU C systems. * I would like to dissect the NFS file handle a bit further (major,minor of the device, inode of the file). The problem is only, every NFS server uses a different encoding scheme. tcpdump contains some heuristics for some systems (and I know the SVR4 encoding) but this may not always be correct. * I give almost always the type of a field in the dissector tree like in mode (mode3): 777 Is this overkill? In case someone doesn't have a capture of NFS I provide two short capture files as attachements (tcpdump). Oh, and BTW, the RPC part became a face lift too. Now I have a generic RPC string parse routine (used for Credentials, machinename).
Index: packet-nfs.c =================================================================== RCS file: /cvsroot/ethereal/packet-nfs.c,v retrieving revision 1.1 diff -u -r1.1 packet-nfs.c --- packet-nfs.c 1999/10/29 01:11:23 1.1 +++ packet-nfs.c 1999/11/04 13:11:02 @@ -41,130 +41,780 @@ static int proto_nfs = -1; -int dissect_fh2(const u_char *pd, int offset, frame_data *fd, proto_tree *tree); -/* -This is the table with the dissector functions. As almost all functions -start with a file handle and I had no more time, this is all I did up to now. -The RPC layer will cope with any following data and interpret it as data. -I'm not sure, if all compilers fill undefined structure members with zeros, -so I give the NULL value in all cases. -*/ +/***************************/ +/* NFS Version 2, RFC 1094 */ +/***************************/ -/* proc number, "proc name", dissect_request, dissect_reply */ -/* NULL as function pointer means: take the generic one. */ -const vsff nfs2_proc[] = { - { 0, "NULL", NULL, NULL }, - { 1, "GETATTR", dissect_fh2, NULL }, - { 2, "SETATTR", dissect_fh2, NULL }, - { 3, "ROOT", NULL, NULL }, - { 4, "LOOKUP", dissect_fh2, NULL }, - { 5, "READLINK", dissect_fh2, NULL }, - { 6, "READ", dissect_fh2, NULL }, - { 7, "WRITECACHE", dissect_fh2, NULL }, - { 8, "WRITE", dissect_fh2, NULL }, - { 9, "CREATE", dissect_fh2, NULL }, - { 10, "REMOVE", dissect_fh2, NULL }, - { 11, "RENAME", dissect_fh2, NULL }, - { 12, "LINK", dissect_fh2, NULL }, - { 13, "SYMLINK", dissect_fh2, NULL }, - { 14, "MKDIR", dissect_fh2, NULL }, - { 15, "RMDIR", dissect_fh2, NULL }, - { 16, "READDIR", dissect_fh2, NULL }, - { 17, "STATFS", dissect_fh2, NULL }, - { 0, NULL, NULL, NULL } -}; -int dissect_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree); -int dissect_nfs3_getattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree); +/* base 32 bit type for NFS v2 */ +int +dissect_unsigned_int(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"unsigned int"); + return offset; +} -const vsff nfs3_proc[] = { - { 0, "NULL", NULL, NULL }, - { 1, "GETATTR", dissect_nfs3_getattr_call, NULL }, - { 2, "SETATTR", dissect_fh3, NULL }, - { 3, "LOOKUP", dissect_fh3, NULL }, - { 4, "ACCESS", dissect_fh3, NULL }, - { 5, "READLINK", dissect_fh3, NULL }, - { 6, "READ", dissect_fh3, NULL }, - { 7, "WRITE", dissect_fh3, NULL }, - { 8, "CREATE", dissect_fh3, NULL }, - { 9, "MKDIR", dissect_fh3, NULL }, - { 10, "SYMLINK", dissect_fh3, NULL }, - { 11, "MKNOD", dissect_fh3, NULL }, - { 12, "REMOVE", dissect_fh3, NULL }, - { 13, "RMDIR", dissect_fh3, NULL }, - { 14, "RENAME", dissect_fh3, NULL }, - { 15, "LINK", dissect_fh3, NULL }, - { 16, "READDIR", dissect_fh3, NULL }, - { 17, "READDIRPLUS", dissect_fh3, NULL }, - { 18, "FSSTAT", dissect_fh3, NULL }, - { 19, "FSINFO", dissect_fh3, NULL }, - { 20, "PATHCONF", dissect_fh3, NULL }, - { 21, "COMMIT", dissect_fh3, NULL }, - { 0, NULL, NULL, NULL } -}; +/* RFC 1094, Page 12 */ +int +dissect_stat(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name, guint32* status) +{ + guint32 stat; + char* stat_name = NULL; + const value_string nfs2_stat[] = + { + { 0, "OK" }, + { 1, "ERR_PERM" }, + { 2, "ERR_NOENT" }, + { 5, "ERR_IO" }, + { 6, "ERR_NX_IO" }, + { 13, "ERR_ACCES" }, + { 17, "ERR_EXIST" }, + { 19, "ERR_NODEV" }, + { 20, "ERR_NOTDIR" }, + { 21, "ERR_ISDIR" }, + { 27, "ERR_FBIG" }, + { 28, "ERR_NOSPC" }, + { 30, "ERR_ROFS" }, + { 63, "ERR_NAMETOOLONG" }, + { 66, "ERR_NOTEMPTY" }, + { 69, "ERR_DQUOT" }, + { 70, "ERR_STALE" }, + { 99, "ERR_WFLUSH" }, + { 0, NULL } + }; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + stat = EXTRACT_UINT(pd, offset+0); + stat_name = val_to_str(stat, nfs2_stat, "%u"); + + if (tree) { + proto_tree_add_text(tree, offset, 4, + "%s (stat): %s (%u)", name, stat_name, stat); + } + offset += 4; + *status = stat; + return offset; +} + + +/* RFC 1094, Page 15 */ +int +dissect_ftype(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + guint32 ftype; + char* ftype_name = NULL; + + const value_string nfs2_ftype[] = + { + { 0, "Non-File" }, + { 1, "Regular File" }, + { 2, "Directory" }, + { 3, "Block Special Device" }, + { 4, "Character Special Device" }, + { 5, "Symbolic Link" }, + { 0, NULL } + }; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + ftype = EXTRACT_UINT(pd, offset+0); + ftype_name = val_to_str(ftype, nfs2_ftype, "%u"); + + if (tree) { + proto_tree_add_text(tree, offset, 4, + "%s (ftype): %s (%u)", name, ftype_name, ftype); + } + + offset += 4; + return offset; +} + + +/* RFC 1094, Page 15 */ int -dissect_fh2(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +dissect_fhandle(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) { proto_item* fitem; proto_tree* ftree = NULL; if (tree) { fitem = proto_tree_add_text(tree, offset, FHSIZE, - "file handle"); + "%s (fhandle)", name); if (fitem) - ftree = proto_item_add_subtree(fitem, ETT_NFS2_FH); + ftree = proto_item_add_subtree(fitem, ETT_NFS_FHANDLE); } if (ftree) { proto_tree_add_text(ftree,offset+0,FHSIZE, - "opaque data"); + "file handle (opaque data)"); } + offset += FHSIZE; return offset; } + +int +dissect_timeval(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ + guint32 seconds; + guint32 mseconds; + + proto_item* time_item; + proto_tree* time_tree = NULL; + + if (!BYTES_ARE_IN_FRAME(offset,8)) return offset; + seconds = EXTRACT_UINT(pd, offset+0); + mseconds = EXTRACT_UINT(pd, offset+4); + + if (tree) { + time_item = proto_tree_add_text(tree, offset, 8, + "%s (timeval): %u.%06u", name, seconds, mseconds); + if (time_item) + time_tree = proto_item_add_subtree(time_item, ETT_NFS_TIMEVAL); + } + + if (time_tree) { + proto_tree_add_text(time_tree,offset+0,4, + "seconds: %u", seconds); + proto_tree_add_text(time_tree,offset+4,4, + "micro seconds: %u", mseconds); + } + offset += 8; + return offset; +} + + +/* RFC 1094, Page 16 */ +const value_string nfs2_mode_names[] = { + { 0040000, "Directory" }, + { 0020000, "Character Special Device" }, + { 0060000, "Block Special Device" }, + { 0100000, "Regular File" }, + { 0120000, "Symbolic Link" }, + { 0140000, "Named Socket" }, +}; + +int +dissect_mode(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + guint32 mode; + proto_item* mode_item = NULL; + proto_tree* mode_tree = NULL; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + mode = EXTRACT_UINT(pd, offset+0); + + if (tree) { + mode_item = proto_tree_add_text(tree, offset, 4, + "%s (mode): 0%o", name, mode); + if (mode_item) + mode_tree = proto_item_add_subtree(mode_item, ETT_NFS_MODE); + } + + if (mode_tree) { + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_enumerated_bitfield(mode, 0160000, 16, + nfs2_mode_names, "%s")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 04000, 16, "Set user id on exec", "not SUID")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 02000, 16, "Set group id on exec", "not SGID")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 01000, 16, "Save swapped text even after use", "not save swapped text")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 0400, 16, "Read permission for owner", "no Read permission for owner")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 0200, 16, "Write permission for owner", "no Write permission for owner")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 0100, 16, "Execute permission for owner", "no Execute permission for owner")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 040, 16, "Read permission for group", "no Read permission for group")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 020, 16, "Write permission for group", "no Write permission for group")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 010, 16, "Execute permission for group", "no Execute permission for group")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 04, 16, "Read permission for others", "no Read permission for others")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 02, 16, "Write permission for others", "no Write permission for others")); + proto_tree_add_text(mode_tree, offset, 4, "%s", + decode_boolean_bitfield(mode, 01, 16, "Execute permission for others", "no Execute permission for others")); + } + + offset += 4; + return offset; +} + + +/* RFC 1094, Page 15 */ +int +dissect_fattr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ + proto_item* fattr_item = NULL; + proto_tree* fattr_tree = NULL; + int old_offset = offset; + + if (tree) { + fattr_item = proto_tree_add_text(tree, offset, + END_OF_FRAME, "%s (fattr)", name); + if (fattr_item) + fattr_tree = proto_item_add_subtree(fattr_item, ETT_NFS_FATTR); + } + + offset = dissect_ftype (pd,offset,fd,fattr_tree,"type"); + offset = dissect_mode (pd,offset,fd,fattr_tree,"mode"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"nlink"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"uid"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"gid"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"size"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocksize"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"rdev"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"blocks"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fsid"); + offset = dissect_unsigned_int (pd,offset,fd,fattr_tree,"fileid"); + offset = dissect_timeval (pd,offset,fd,fattr_tree,"atime"); + offset = dissect_timeval (pd,offset,fd,fattr_tree,"mtime"); + offset = dissect_timeval (pd,offset,fd,fattr_tree,"ctime"); + + /* now we know, that fattr is shorter */ + if (fattr_item) { + proto_item_set_len(fattr_item, offset - old_offset); + } + + return offset; +} + + +/* generic NFS2 call dissector */ +int +dissect_nfs2_any_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + offset = dissect_fhandle(pd, offset, fd, tree, "object"); + + return offset; +} + + +/* generic NFS2 reply dissector */ +int +dissect_nfs2_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) +{ + guint32 status; + + offset = dissect_stat(pd, offset, fd, tree, "status", &status); + + return offset; +} + + +/* RFC 1094, Page 5 */ +int +dissect_nfs2_getattr_call(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + offset = dissect_fhandle(pd, offset, fd, tree, "object"); + + return offset; +} + + +/* RFC 1094, Page 5 */ +int +dissect_nfs2_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) +{ + guint32 status; + + /* attrstat: RFC 1094, Page 17 */ + offset = dissect_stat(pd, offset, fd, tree, "status", &status); + switch (status) { + case 0: + offset = dissect_fattr(pd, offset, fd, tree, "attributes"); + break; + default: + /* do nothing */ + break; + } + + return offset; +} + +/* more to come here */ + + +/* proc number, "proc name", dissect_request, dissect_reply */ +/* NULL as function pointer means: take the generic one. */ +const vsff nfs2_proc[] = { + { 0, "NULL", NULL, NULL }, + { 1, "GETATTR", dissect_nfs2_getattr_call, dissect_nfs2_getattr_reply }, + { 2, "SETATTR", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 3, "ROOT", NULL, NULL }, + { 4, "LOOKUP", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 5, "READLINK", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 6, "READ", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 7, "WRITECACHE", NULL, NULL }, + { 8, "WRITE", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 9, "CREATE", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 10, "REMOVE", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 11, "RENAME", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 12, "LINK", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 13, "SYMLINK", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 14, "MKDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 15, "RMDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 16, "READDIR", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 17, "STATFS", dissect_nfs2_any_call, dissect_nfs2_any_reply }, + { 0, NULL, NULL, NULL } +}; +/* end of NFS Version 2 */ + + +/***************************/ +/* NFS Version 3, RFC 1813 */ +/***************************/ + + +/* RFC 1813, Page 15 */ +int +dissect_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"uint64"); + return offset; +} + + +/* RFC 1813, Page 15 */ +int +dissect_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uint32"); + return offset; +} + + +/* RFC 1813, Page 15 */ +int +dissect_fileid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"fileid3"); + return offset; +} + + +/* RFC 1813, Page 16 */ int -dissect_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +dissect_uid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) { + offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"uid3"); + return offset; +} + + +/* RFC 1813, Page 16 */ +int +dissect_gid3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"gid3"); + return offset; +} + + +/* RFC 1813, Page 16 */ +int +dissect_size3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + offset = dissect_rpc_uint64(pd,offset,fd,tree,name,"size3"); + return offset; +} + + +/* RFC 1813, Page 16 */ +int +dissect_mode3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + guint32 mode3; + proto_item* mode3_item = NULL; + proto_tree* mode3_tree = NULL; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + mode3 = EXTRACT_UINT(pd, offset+0); + + if (tree) { + mode3_item = proto_tree_add_text(tree, offset, 4, + "%s (mode3): 0%o", name, mode3); + if (mode3_item) + mode3_tree = proto_item_add_subtree(mode3_item, ETT_NFS_MODE3); + } + + /* RFC 1813, Page 23 */ + if (mode3_tree) { + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x800, 12, "Set user id on exec", "not SUID")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x400, 12, "Set group id on exec", "not SGID")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x200, 12, "Save swapped text even after use", "not save swapped text")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x100, 12, "Read permission for owner", "no Read permission for owner")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x80, 12, "Write permission for owner", "no Write permission for owner")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x40, 12, "Execute permission for owner", "no Execute permission for owner")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x20, 12, "Read permission for group", "no Read permission for group")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x10, 12, "Write permission for group", "no Write permission for group")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x8, 12, "Execute permission for group", "no Execute permission for group")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x4, 12, "Read permission for others", "no Read permission for others")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x2, 12, "Write permission for others", "no Write permission for others")); + proto_tree_add_text(mode3_tree, offset, 4, "%s", + decode_boolean_bitfield(mode3, 0x1, 12, "Execute permission for others", "no Execute permission for others")); + } + + offset += 4; + return offset; +} + + +/* RFC 1813, Page 16 */ +int +dissect_count3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name, char* type) +{ + offset = dissect_rpc_uint32(pd,offset,fd,tree,name,"count"); + return offset; +} + + +/* RFC 1813, Page 16 */ +int +dissect_nfsstat3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name, guint32* status) +{ + guint32 nfsstat3; + char* nfsstat3_name = NULL; + + const value_string nfs3_nfsstat3[] = + { + { 0, "OK" }, + { 1, "ERR_PERM" }, + { 2, "ERR_NOENT" }, + { 5, "ERR_IO" }, + { 6, "ERR_NX_IO" }, + { 13, "ERR_ACCES" }, + { 17, "ERR_EXIST" }, + { 18, "ERR_XDEV" }, + { 19, "ERR_NODEV" }, + { 20, "ERR_NOTDIR" }, + { 21, "ERR_ISDIR" }, + { 22, "ERR_INVAL" }, + { 27, "ERR_FBIG" }, + { 28, "ERR_NOSPC" }, + { 30, "ERR_ROFS" }, + { 31, "ERR_MLINK" }, + { 63, "ERR_NAMETOOLONG" }, + { 66, "ERR_NOTEMPTY" }, + { 69, "ERR_DQUOT" }, + { 70, "ERR_STALE" }, + { 71, "ERR_REMOTE" }, + { 10001, "ERR_BADHANDLE" }, +/* RFC 1813, Page 17 */ + { 10002, "ERR_NOT_SYNC" }, + { 10003, "ERR_BAD_COOKIE" }, + { 10004, "ERR_NOTSUPP" }, + { 10005, "ERR_TOOSMALL" }, + { 10006, "ERR_SERVERFAULT" }, + { 10007, "ERR_BADTYPE" }, + { 10008, "ERR_JUKEBOX" }, + { 0, NULL } + }; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + nfsstat3 = EXTRACT_UINT(pd, offset+0); + nfsstat3_name = val_to_str(nfsstat3, nfs3_nfsstat3, "%u"); + + if (tree) { + proto_tree_add_text(tree, offset, 4, + "%s (nfsstat3): %s (%u)", name, nfsstat3_name, nfsstat3); + } + + offset += 4; + *status = nfsstat3; + return offset; +} + + +/* RFC 1813, Page 17, 18, 19, 20: error explanations */ + + +/* RFC 1813, Page 20 */ +int +dissect_ftype3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name) +{ + guint32 ftype3; + char* ftype3_name = NULL; + + const value_string nfs3_ftype3[] = + { + { 1, "Regular File" }, + { 2, "Directory" }, + { 3, "Block Special Device" }, + { 4, "Character Special Device" }, + { 5, "Symbolic Link" }, + { 6, "Socket" }, + { 7, "Named Pipe" }, + { 0, NULL } + }; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + ftype3 = EXTRACT_UINT(pd, offset+0); + ftype3_name = val_to_str(ftype3, nfs3_ftype3, "%u"); + + if (tree) { + proto_tree_add_text(tree, offset, 4, + "%s (ftype3): %s (%u)", name, ftype3_name, ftype3); + } + + offset += 4; + return offset; +} + + +/* RFC 1813, Page 20 */ +int +dissect_specdata3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ + guint32 specdata1; + guint32 specdata2; + + proto_item* specdata3_item; + proto_tree* specdata3_tree = NULL; + + if (!BYTES_ARE_IN_FRAME(offset,8)) return offset; + specdata1 = EXTRACT_UINT(pd, offset+0); + specdata2 = EXTRACT_UINT(pd, offset+4); + + if (tree) { + specdata3_item = proto_tree_add_text(tree, offset, 8, + "%s (specdata3) : %u,%u", name, specdata1, specdata2); + if (specdata3_item) + specdata3_tree = proto_item_add_subtree(specdata3_item, + ETT_NFS_SPECDATA3); + } + + if (specdata3_tree) { + proto_tree_add_text(specdata3_tree,offset+0,4, + "specdata1: %u", specdata1); + proto_tree_add_text(specdata3_tree,offset+4,4, + "specdata2: %u", specdata2); + } + + offset += 8; + return offset; +} + + +/* RFC 1813, Page 21 */ +int +dissect_nfs_fh3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ guint fh_len; guint fh_len_full; + guint fh_fill; proto_item* fitem; proto_tree* ftree = NULL; fh_len = EXTRACT_UINT(pd, offset+0); fh_len_full = roundup(fh_len); + fh_fill = fh_len_full - fh_len; if (tree) { fitem = proto_tree_add_text(tree, offset, 4+fh_len_full, - "file handle"); + "%s (nfs_fh3)", name); if (fitem) - ftree = proto_item_add_subtree(fitem, ETT_NFS3_FH); + ftree = proto_item_add_subtree(fitem, ETT_NFS_FH3); } if (ftree) { proto_tree_add_text(ftree,offset+0,4, - "length: %d", fh_len); + "length: %u", fh_len); proto_tree_add_text(ftree,offset+4,fh_len, - "opaque data"); + "file handle (opaque data)"); + if (fh_fill) + proto_tree_add_text(ftree,offset+4+fh_len,fh_fill, + "fill bytes"); } offset += 4 + fh_len_full; return offset; } + +/* RFC 1813, Page 21 */ +int +dissect_nfs3time(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,char* name) +{ + guint32 seconds; + guint32 nseconds; + + proto_item* time_item; + proto_tree* time_tree = NULL; + + if (!BYTES_ARE_IN_FRAME(offset,8)) return offset; + seconds = EXTRACT_UINT(pd, offset+0); + nseconds = EXTRACT_UINT(pd, offset+4); + + if (tree) { + time_item = proto_tree_add_text(tree, offset, 8, + "%s (nfs3time): %u.%09u", name, seconds, nseconds); + if (time_item) + time_tree = proto_item_add_subtree(time_item, ETT_NFS_NFSTIME3); + } + + if (time_tree) { + proto_tree_add_text(time_tree,offset+0,4, + "seconds: %u", seconds); + proto_tree_add_text(time_tree,offset+4,4, + "nano seconds: %u", nseconds); + } + offset += 8; + return offset; +} + + +/* RFC 1813, Page 22 */ +int +dissect_fattr3(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ + proto_item* fattr3_item = NULL; + proto_tree* fattr3_tree = NULL; + int old_offset = offset; + + if (tree) { + fattr3_item = proto_tree_add_text(tree, offset, + END_OF_FRAME, "%s (fattr3)", name); + if (fattr3_item) + fattr3_tree = proto_item_add_subtree(fattr3_item, ETT_NFS_FATTR3); + } + + offset = dissect_ftype3 (pd,offset,fd,fattr3_tree,"type"); + offset = dissect_mode3 (pd,offset,fd,fattr3_tree,"mode"); + offset = dissect_uint32 (pd,offset,fd,fattr3_tree,"nlink"); + offset = dissect_uid3 (pd,offset,fd,fattr3_tree,"uid"); + offset = dissect_gid3 (pd,offset,fd,fattr3_tree,"gid"); + offset = dissect_size3 (pd,offset,fd,fattr3_tree,"size"); + offset = dissect_size3 (pd,offset,fd,fattr3_tree,"used"); + offset = dissect_specdata3(pd,offset,fd,fattr3_tree,"rdev"); + offset = dissect_uint64 (pd,offset,fd,fattr3_tree,"fsid"); + offset = dissect_fileid3 (pd,offset,fd,fattr3_tree,"fileid"); + offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"atime"); + offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"mtime"); + offset = dissect_nfs3time (pd,offset,fd,fattr3_tree,"ctime"); + + /* now we know, that fattr3 is shorter */ + if (fattr3_item) { + proto_item_set_len(fattr3_item, offset - old_offset); + } + + return offset; +} + + +/* generic NFS3 call dissector */ +int +dissect_nfs3_any_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) +{ + offset = dissect_nfs_fh3(pd, offset, fd, tree, "object"); + return offset; +} + + +/* generic NFS3 reply dissector */ +int +dissect_nfs3_any_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) +{ + guint32 status; + + offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status); + + return offset; + +} -/* In fact, this routine serves only as a place to copy some ideas for -more complicated dissectors. */ +/* RFC 1813, Page 32 */ int dissect_nfs3_getattr_call(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) +{ + offset = dissect_nfs_fh3(pd, offset, fd, tree, "object"); + return offset; +} + + +/* RFC 1813, Page 32 */ +int +dissect_nfs3_getattr_reply(const u_char* pd, int offset, frame_data* fd, proto_tree* tree) { - offset = dissect_fh3(pd, offset, fd, tree); + guint32 status; + + offset = dissect_nfsstat3(pd, offset, fd, tree, "status", &status); + switch (status) { + case 0: + offset = dissect_fattr3(pd, offset, fd, tree, "obj_attributes"); + break; + default: + /* void */ + break; + } + return offset; } + + +/* proc number, "proc name", dissect_request, dissect_reply */ +/* NULL as function pointer means: take the generic one. */ +const vsff nfs3_proc[] = { + { 0, "NULL", NULL, NULL }, + { 1, "GETATTR", dissect_nfs3_getattr_call, dissect_nfs3_getattr_reply }, + { 2, "SETATTR", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 3, "LOOKUP", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 4, "ACCESS", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 5, "READLINK", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 6, "READ", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 7, "WRITE", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 8, "CREATE", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 9, "MKDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 10, "SYMLINK", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 11, "MKNOD", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 12, "REMOVE", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 13, "RMDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 14, "RENAME", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 15, "LINK", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 16, "READDIR", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 17, "READDIRPLUS", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 18, "FSSTAT", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 19, "FSINFO", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 20, "PATHCONF", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 21, "COMMIT", dissect_nfs3_any_call, dissect_nfs3_any_reply }, + { 0, NULL, NULL, NULL } +}; +/* end of NFS Version 3 */ + void proto_register_nfs(void) Index: packet-rpc.c =================================================================== RCS file: /cvsroot/ethereal/packet-rpc.c,v retrieving revision 1.2 diff -u -r1.2 packet-rpc.c --- packet-rpc.c 1999/10/29 02:25:53 1.2 +++ packet-rpc.c 1999/11/04 13:11:06 @@ -322,6 +322,96 @@ } +int +dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name, char* type) +{ + guint32 value; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + value = EXTRACT_UINT(pd, offset+0); + + if (tree) { + proto_tree_add_text(tree, offset, 4, + "%s (%s): %u", name, type, value); + } + + offset += 4; + return offset; +} + + +int +dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, +char* name, char* type) +{ + guint32 value_low; + guint32 value_high; + + if (!BYTES_ARE_IN_FRAME(offset,8)) return offset; + value_high = EXTRACT_UINT(pd, offset+0); + value_low = EXTRACT_UINT(pd, offset+4); + + if (tree) { + if (value_high) + proto_tree_add_text(tree, offset, 8, + "%s (%s): %x%08x", name, type, value_high, value_low); + else + proto_tree_add_text(tree, offset, 8, + "%s (%s): %u", name, type, value_low); + } + + offset += 8; + return offset; +} + + + +/* arbitrary limit */ +#define RPC_STRING_MAXBUF 1024 + +int +dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name) +{ + proto_item *string_item; + proto_tree *string_tree = NULL; + + guint32 string_length; + guint32 string_fill; + guint32 string_length_full; + char string_buffer[RPC_STRING_MAXBUF]; + + if (!BYTES_ARE_IN_FRAME(offset,4)) return offset; + string_length = EXTRACT_UINT(pd,offset+0); + string_length_full = roundup(string_length); + string_fill = string_length_full - string_length; + if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset; + if (string_length>=sizeof(string_buffer)) return offset; + memcpy(string_buffer,pd+offset+4,string_length); + string_buffer[string_length] = '\0'; + if (tree) { + string_item = proto_tree_add_text(tree,offset+0, + 4+string_length_full, + "%s: %s", name, string_buffer); + if (string_item) { + string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING); + } + } + if (string_tree) { + proto_tree_add_text(string_tree,offset+0,4, + "length: %u", string_length); + proto_tree_add_text(string_tree,offset+4,string_length, + "text: %s", string_buffer); + if (string_fill) + proto_tree_add_text(string_tree,offset+4+string_length,string_fill, + "fill bytes: opaque data"); + } + + offset += 4 + string_length_full; + return offset; +} + + void dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { @@ -338,9 +428,9 @@ if (tree) { proto_tree_add_text(tree,offset+0,4, - "Flavor: %s (%d)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor); + "Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor); proto_tree_add_text(tree,offset+4,4, - "Length: %d", length); + "Length: %u", length); } offset += 8; @@ -348,9 +438,6 @@ switch (flavor) { case AUTH_UNIX: { guint stamp; - guint machinename_count; - guint machinename_full; - char machinename_buffer[256]; guint uid; guint gid; guint gids_count; @@ -366,32 +453,20 @@ "stamp: 0x%08x", stamp); offset += 4; - /* all the following stuff should go into something - like dissect_rpc_string() */ - if (!BYTES_ARE_IN_FRAME(offset,4)) return; - machinename_count = EXTRACT_UINT(pd,offset+0); - machinename_full = roundup(machinename_count); - if (!BYTES_ARE_IN_FRAME(offset+4,machinename_full)) return; - if (machinename_count>=sizeof(machinename_buffer)) return; - memcpy(machinename_buffer,pd+offset+4,machinename_count); - machinename_buffer[machinename_count] = '\0'; - if (tree) - proto_tree_add_text(tree,offset+0,4+machinename_full, - "machinename: %s", machinename_buffer); - offset += 4 + machinename_full; + offset = dissect_rpc_string(pd,offset,fd,tree,"machinename"); if (!BYTES_ARE_IN_FRAME(offset,4)) return; uid = EXTRACT_UINT(pd,offset+0); if (tree) proto_tree_add_text(tree,offset+0,4, - "uid: %d", uid); + "uid: %u", uid); offset += 4; if (!BYTES_ARE_IN_FRAME(offset,4)) return; gid = EXTRACT_UINT(pd,offset+0); if (tree) proto_tree_add_text(tree,offset+0,4, - "gid: %d", gid); + "gid: %u", gid); offset += 4; if (!BYTES_ARE_IN_FRAME(offset,4)) return; @@ -407,7 +482,7 @@ gids_entry = EXTRACT_UINT(pd,offset+0); if (gtree) proto_tree_add_text(gtree, offset, 4, - "%d", gids_entry); + "%u", gids_entry); offset+=4; } /* how can I NOW change the gitem to print a list with @@ -543,15 +618,15 @@ xid = EXTRACT_UINT(pd,offset+0); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+0,4, - "XID: 0x%x (%d)", xid, xid); + "XID: 0x%x (%u)", xid, xid); } /* we should better compare this with the argument?! */ msg_type = EXTRACT_UINT(pd,offset+4); - msg_type_name = val_to_str(msg_type,rpc_msg_type,"%d"); + msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u"); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+4,4, - "msg_type: %s (%d)", + "msg_type: %s (%u)", msg_type_name, msg_type); } @@ -567,14 +642,14 @@ rpcvers = EXTRACT_UINT(pd,offset+0); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+0,4, - "RPC Version: %d", rpcvers); + "RPC Version: %u", rpcvers); } prog = EXTRACT_UINT(pd,offset+4); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+4,4, - "Program: %s (%d)", progname, prog); + "Program: %s (%u)", progname, prog); } if (check_col(fd, COL_PROTOCOL)) { @@ -606,12 +681,12 @@ /* happens only with strange program versions or non-existing dissectors */ dissect_function = NULL; - sprintf(procname_static, "proc-%d", proc); + sprintf(procname_static, "proc-%u", proc); procname = procname_static; } if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+12,4, - "Procedure: %s (%d)", procname, proc); + "Procedure: %s (%u)", procname, proc); } if (check_col(fd, COL_INFO)) { @@ -674,13 +749,13 @@ procname = rpc_call->proc_info->name; } else { - sprintf(procname_static, "proc-%d", proc); + sprintf(procname_static, "proc-%u", proc); procname = procname_static; } } else { dissect_function = NULL; - sprintf(procname_static, "proc-%d", proc); + sprintf(procname_static, "proc-%u", proc); procname = procname_static; } rpc_call->replies++; @@ -714,12 +789,12 @@ if (rpc_tree) { proto_tree_add_text(rpc_tree,0,0, - "Program: %s (%d)", + "Program: %s (%u)", progname, prog); proto_tree_add_text(rpc_tree,0,0, "Program Version: %u", vers); proto_tree_add_text(rpc_tree,0,0, - "Procedure: %s (%d)", procname, proc); + "Procedure: %s (%u)", procname, proc); } if (rpc_call->replies>1) { @@ -732,7 +807,7 @@ reply_state = EXTRACT_UINT(pd,offset+0); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+0, 4, - "Reply State: %s (%d)", + "Reply State: %s (%u)", val_to_str(reply_state,rpc_reply_state,"Unknown"), reply_state); } @@ -744,7 +819,7 @@ accept_state = EXTRACT_UINT(pd,offset+0); if (rpc_tree) { proto_tree_add_text(rpc_tree,offset+0, 4, - "Accept State: %s (%d)", + "Accept State: %s (%u)", val_to_str(accept_state,rpc_accept_state,"Unknown"), accept_state); } @@ -761,11 +836,11 @@ if (rpc_tree) { proto_tree_add_text(rpc_tree, offset+0, 4, - "min. Program Version: %d", + "min. Program Version: %u", vers_low); proto_tree_add_text(rpc_tree, offset+4, 4, - "max. Program Version: %d", + "max. Program Version: %u", vers_high); } offset += 8; @@ -779,7 +854,7 @@ reject_state = EXTRACT_UINT(pd,offset+0); if (rpc_tree) { proto_tree_add_text(rpc_tree, offset+0, 4, - "Reject State: %s (%d)", + "Reject State: %s (%u)", val_to_str(reject_state,rpc_reject_state,"Unknown"), reject_state); } @@ -792,11 +867,11 @@ if (rpc_tree) { proto_tree_add_text(rpc_tree, offset+0, 4, - "min. RPC Version: %d", + "min. RPC Version: %u", vers_low); proto_tree_add_text(rpc_tree, offset+4, 4, - "max. RPC Version: %d", + "max. RPC Version: %u", vers_high); } offset += 8; @@ -806,7 +881,7 @@ if (rpc_tree) { proto_tree_add_text(rpc_tree, offset+0, 4, - "Authentication error: %s (%d)", + "Authentication error: %s (%u)", val_to_str(auth_state,rpc_auth_state,"Unknown"), auth_state); } Index: packet-rpc.h =================================================================== RCS file: /cvsroot/ethereal/packet-rpc.h,v retrieving revision 1.1 diff -u -r1.1 packet-rpc.h --- packet-rpc.h 1999/10/29 01:11:22 1.1 +++ packet-rpc.h 1999/11/04 13:11:06 @@ -96,7 +96,10 @@ extern void cleanup_dissect_rpc(); extern unsigned int roundup(unsigned int a); - +extern int dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, + proto_tree *tree, char* name, char* type); +extern int dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, + proto_tree *tree, char* name, char* type); #endif /* packet-rpc.h */ Index: packet.h =================================================================== RCS file: /cvsroot/ethereal/packet.h,v retrieving revision 1.124 diff -u -r1.124 packet.h --- packet.h 1999/10/30 06:10:32 1.124 +++ packet.h 1999/11/04 13:11:11 @@ -424,12 +424,20 @@ ETT_SNA_RU, ETT_YHOO, ETT_RPC, + ETT_RPC_STRING, ETT_RPC_CRED, ETT_RPC_VERF, ETT_RPC_GIDS, ETT_NFS, - ETT_NFS2_FH, - ETT_NFS3_FH, + ETT_NFS_FHANDLE, + ETT_NFS_TIMEVAL, + ETT_NFS_MODE, + ETT_NFS_FATTR, + ETT_NFS_MODE3, + ETT_NFS_SPECDATA3, + ETT_NFS_FH3, + ETT_NFS_NFSTIME3, + ETT_NFS_FATTR3, ETT_BOOT, ETT_MNT, ETT_NLM,
Attachment:
nfs-v2
Description: Binary data
Attachment:
nfs-v3
Description: Binary data
- Follow-Ups:
- Re: [ethereal-dev] NFS dissector continued
- From: Guy Harris
- Re: [ethereal-dev] NFS dissector continued
- From: Guy Harris
- Re: [ethereal-dev] NFS dissector continued
- From: Guy Harris
- Re: [ethereal-dev] NFS dissector continued
- From: Guy Harris
- Re: [ethereal-dev] NFS dissector continued
- Prev by Date: Re[2]: [ethereal-dev] ethereal-0.7.7 - hangs in recvfrom() on RH6.1
- Next by Date: Re: [ethereal-dev] ethereal-0.7.7 - hangs in recvfrom() on RH6.1
- Previous by thread: Re: [ethereal-dev] Adding entries to dissectors on the fly
- Next by thread: Re: [ethereal-dev] NFS dissector continued
- Index(es):