📄 _nfs.c
字号:
if (vflag && (type == NFCHR || type == NFBLK))
{
if (dp + 2 > (u_int32_t*)snapend)
break;
PRINTF (" %lu/%lu", ntohl (dp[0]), ntohl (dp[1]));
dp += 2;
}
if (vflag)
print_sattr3 (&sa3, vflag);
return;
}
break;
case NFSPROC_REMOVE:
PUTS (" remove");
if ((dp = parsereq (rp, length)) != NULL && parsefhn (dp, v3))
return;
break;
case NFSPROC_RMDIR:
PUTS (" rmdir");
if ((dp = parsereq (rp, length)) != NULL && parsefhn (dp, v3))
return;
break;
case NFSPROC_RENAME:
PUTS (" rename");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefhn (dp, v3)) != NULL)
{
PUTS (" ->");
if (parsefhn (dp, v3))
return;
}
break;
case NFSPROC_LINK:
PUTS (" link");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefh (dp, v3)) != NULL)
{
PUTS (" ->");
if (parsefhn (dp, v3))
return;
}
break;
case NFSPROC_READDIR:
PUTS (" readdir");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefh (dp, v3)) != NULL)
{
if (v3)
{
TCHECK2 (*dp, 20);
/*
* We shouldn't really try to interpret the
* offset cookie here.
*/
PRINTF (" %lu bytes @ ", ntohl (dp[4]));
print_int64 (dp, SIGNED);
if (vflag)
PRINTF (" verf %08x%08x", dp[2], dp[3]);
}
else
{
TCHECK2 (*dp, 2 * sizeof(*dp));
/*
* Print the offset as signed, since -1 is
* common, but offsets > 2^31 aren't.
*/
PRINTF (" %lu bytes @ %ld", ntohl (dp[1]), ntohl (dp[0]));
}
return;
}
break;
case NFSPROC_READDIRPLUS:
PUTS (" readdirplus");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefh (dp, v3)) != NULL)
{
TCHECK2 (*dp, 20);
/*
* We don't try to interpret the offset
* cookie here.
*/
PRINTF (" %lu bytes @ ", ntohl (dp[4]));
print_int64 (dp, SIGNED);
if (vflag)
PRINTF (" max %lu verf %08x%08x", ntohl (dp[5]), dp[2], dp[3]);
return;
}
break;
case NFSPROC_FSSTAT:
PUTS (" fsstat");
if ((dp = parsereq (rp, length)) != NULL && parsefh (dp, v3))
return;
break;
case NFSPROC_FSINFO:
PUTS (" fsinfo");
break;
case NFSPROC_PATHCONF:
PUTS (" pathconf");
break;
case NFSPROC_COMMIT:
PUTS (" commit");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefh (dp, v3)) != NULL)
{
PRINTF (" %lu bytes @ ", ntohl (dp[2]));
print_int64 (dp, UNSIGNED);
return;
}
break;
default:
PRINTF (" proc-%lu", proc);
return;
}
trunc:
if (!nfserr)
PUTS (" [|nfs]");
}
/*
* Print out an NFS file handle.
* We assume packet was not truncated before the end of the
* file handle pointed to by dp.
*
* Note: new version (using portable file-handle parser) doesn't produce
* generation number. It probably could be made to do that, with some
* additional hacking on the parser code.
*/
static void nfs_printfh (const u_int32_t * dp, const int len)
{
my_fsid fsid;
ino_t ino;
char *sfsname = NULL;
Parse_fh ((caddr_t*)dp, len, &fsid, &ino, NULL, &sfsname, 0);
if (sfsname)
{
/* file system ID is ASCII, not numeric, for this server OS */
static char temp[NFSX_V3FHMAX + 1];
/* Make sure string is null-terminated */
strncpy (temp, sfsname, NFSX_V3FHMAX);
/* Remove trailing spaces */
sfsname = strchr (temp, ' ');
if (sfsname)
*sfsname = 0;
PRINTF (" fh %s/%u", temp, (u_int32_t) ino);
if (fsid.Fsid_dev.Minor == 257 && uflag == 1)
PRINTF (" fh %s/%s", temp, fsid.Opaque_Handle); /* Print the undecoded handle */
else PRINTF (" fh %s/%ld", temp, (long)ino);
}
else
PRINTF (" fh %u,%u/%u", fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor,
(u_int32_t)ino);
}
/*
* Maintain a small cache of recent client.XID.server/proc pairs, to allow
* us to match up replies with requests and thus to know how to parse
* the reply.
*/
struct xid_map_entry {
u_int32_t xid; /* transaction ID (net order) */
struct in_addr client; /* client IP address (net order) */
struct in_addr server; /* server IP address (net order) */
u_int32_t proc; /* call proc number (host order) */
u_int32_t vers; /* program version (host order) */
};
/*
* Map entries are kept in an array that we manage as a ring;
* new entries are always added at the tail of the ring. Initially,
* all the entries are zero and hence don't match anything.
*/
#define XIDMAPSIZE 64
static struct xid_map_entry xid_map[XIDMAPSIZE];
static int xid_map_next = 0;
static int xid_map_hint = 0;
static void xid_map_enter (const struct rpc_msg *rp, const struct ip *ip)
{
struct xid_map_entry *xmep = &xid_map[xid_map_next];
if (++xid_map_next >= XIDMAPSIZE)
xid_map_next = 0;
xmep->xid = rp->rm_xid;
xmep->client = ip->ip_src;
xmep->server = ip->ip_dst;
xmep->proc = ntohl (rp->rm_call.cb_proc);
xmep->vers = ntohl (rp->rm_call.cb_vers);
}
/*
* Returns 0 and puts NFSPROC_xxx in proc return and
* version in vers return, or returns -1 on failure
*/
static int xid_map_find (const struct rpc_msg *rp, const struct ip *ip,
u_int32_t * proc, u_int32_t * vers)
{
struct xid_map_entry *xmep;
u_int32_t xid = rp->rm_xid;
u_int32_t clip = ip->ip_dst.s_addr;
u_int32_t sip = ip->ip_src.s_addr;
int i;
/* Start searching from where we last left off
*/
i = xid_map_hint;
do
{
xmep = &xid_map[i];
if (xmep->xid == xid &&
xmep->client.s_addr == clip &&
xmep->server.s_addr == sip)
{
/* match */
xid_map_hint = i;
*proc = xmep->proc;
*vers = xmep->vers;
return 0;
}
if (++i >= XIDMAPSIZE)
i = 0;
}
while (i != xid_map_hint);
/* search failed */
return (0);
}
/*
* Routines for parsing reply packets
*/
/*
* Return a pointer to the beginning of the actual results.
* If the packet was truncated, return NULL.
*/
static const u_int32_t *parserep (const struct rpc_msg *rp, int length)
{
const u_int32_t *dp;
enum accept_stat astat;
int len;
/*
* Portability note:
* Here we find the address of the ar_verf credentials.
* Originally, this calculation was
* dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
* On the wire, the rp_acpt field starts immediately after
* the (32 bit) rp_stat field. However, rp_acpt (which is a
* "struct accepted_reply") contains a "struct opaque_auth",
* whose internal representation contains a pointer, so on a
* 64-bit machine the compiler inserts 32 bits of padding
* before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
* the internal representation to parse the on-the-wire
* representation. Instead, we skip past the rp_stat field,
* which is an "enum" and so occupies one 32-bit word.
*/
dp = ((const u_int32_t*)&rp->rm_reply) + 1;
TCHECK2 (dp[0], 1);
len = ntohl (dp[1]);
if (len >= length)
return (NULL);
/* skip past the ar_verf credentials.
*/
dp += (len + (2 * sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
TCHECK2 (dp[0], 0);
/* now we can check the ar_stat field
*/
astat = ntohl (*(enum accept_stat*)dp);
switch (astat)
{
case SUCCESS:
break;
case PROG_UNAVAIL:
PUTS (" PROG_UNAVAIL");
nfserr = 1; /* suppress trunc string */
return (NULL);
case PROG_MISMATCH:
PUTS (" PROG_MISMATCH");
nfserr = 1; /* suppress trunc string */
return (NULL);
case PROC_UNAVAIL:
PUTS (" PROC_UNAVAIL");
nfserr = 1; /* suppress trunc string */
return (NULL);
case GARBAGE_ARGS:
PUTS (" GARBAGE_ARGS");
nfserr = 1; /* suppress trunc string */
return (NULL);
case SYSTEM_ERR:
PUTS (" SYSTEM_ERR");
nfserr = 1; /* suppress trunc string */
return (NULL);
default:
PRINTF (" ar_stat %d", astat);
nfserr = 1; /* suppress trunc string */
return (NULL);
}
/* successful return */
if ((sizeof(astat) + ((u_char*)dp)) < snapend)
return ((u_int32_t*)(sizeof(astat) + ((char*)dp)));
trunc:
return (NULL);
}
static const u_int32_t *parsestatus (const u_int32_t *dp, int *er)
{
int errnum;
TCHECK (dp[0]);
errnum = ntohl (dp[0]);
if (er)
*er = errnum;
if (errnum)
{
if (!qflag)
PRINTF (" ERROR: %s", pcap_strerror (errnum));
nfserr = 1;
return (NULL);
}
return (dp + 1);
trunc:
return (NULL);
}
static const u_int32_t *parsefattr (const u_int32_t *dp, int verbose, int v3)
{
const struct nfs_fattr *fap = (const struct nfs_fattr*)dp;
TCHECK (fap->fa_gid);
if (verbose)
{
PRINTF (" %s %lo ids %ld/%ld",
tok2str (type2str, "unk-ft %d ", ntohl (fap->fa_type)),
ntohl (fap->fa_mode), ntohl (fap->fa_uid), ntohl (fap->fa_gid));
if (v3)
{
TCHECK (fap->fa3_size);
PUTS (" sz ");
print_int64 ((u_int32_t*) &fap->fa3_size, UNSIGNED);
PUTCHAR (' ');
}
else
{
TCHECK (fap->fa2_size);
PRINTF (" sz %ld ", ntohl (fap->fa2_size));
}
}
/* print lots more stuff
*/
if (verbose > 1)
{
if (v3)
{
TCHECK (fap->fa3_ctime);
PRINTF ("nlink %ld rdev %ld/%ld fsid",
ntohl (fap->fa_nlink),
ntohl (fap->fa3_rdev.specdata1),
ntohl (fap->fa3_rdev.specdata2));
print_int64 ((u_int32_t*)&fap->fa2_fsid, HEX);
PUTS (" nodeid ");
print_int64 ((u_int32_t*)&fap->fa2_fileid, HEX);
PRINTF (" a/m/ctime %lu.%06lu %lu.%06lu %lu.%06lu ",
ntohl (fap->fa3_atime.nfsv3_sec),
ntohl (fap->fa3_atime.nfsv3_nsec),
ntohl (fap->fa3_mtime.nfsv3_sec),
ntohl (fap->fa3_mtime.nfsv3_nsec),
ntohl (fap->fa3_ctime.nfsv3_sec),
ntohl (fap->fa3_ctime.nfsv3_nsec));
}
else
{
TCHECK (fap->fa2_ctime);
PRINTF ("nlink %ld rdev %lx fsid %lx nodeid %lx a/m/ctime ",
ntohl (fap->fa_nlink),
ntohl (fap->fa2_rdev),
ntohl (fap->fa2_fsid),
ntohl (fap->fa2_fileid));
PRINTF ("%lu.%06lu %lu.%06lu %lu.%06lu ",
ntohl (fap->fa2_atime.nfsv2_sec),
ntohl (fap->fa2_atime.nfsv2_usec),
ntohl (fap->fa2_mtime.nfsv2_sec),
ntohl (fap->fa2_mtime.nfsv2_usec),
ntohl (fap->fa2_ctime.nfsv2_sec),
ntohl (fap->fa2_ctime.nfsv2_usec));
}
}
return ((const u_int32_t*) ((unsigned char*) dp +
(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
trunc:
return (NULL);
}
static __inline int parseattrstat (const u_int32_t *dp, int verbose, int v3)
{
int er;
dp = parsestatus (dp, &er);
if (dp == NULL || er)
return (0);
return (parsefattr (dp, verbose, v3) != NULL);
}
static __inline int parsediropres (const u_int32_t *dp)
{
int er;
dp = parsestatus (dp, &er);
if (dp == NULL || er)
return (0);
dp = parsefh (dp, 0);
if (dp == NULL)
return (0);
return (parsefattr (dp, vflag, 0) != NULL);
}
static __inline int parselinkres (const u_int32_t *dp, int v3)
{
int er;
dp = parsestatus (dp, &er);
if (dp == NULL || er)
return (0);
if (v3 && ((dp = parse_post_op_attr (dp, vflag)) != NULL))
return (0);
PUTCHAR (' ');
return (parsefn (dp) != NULL);
}
static int parsestatfs (const u_int32_t *dp, int v3)
{
const struct nfs_statfs *sfsp;
int er;
dp = parsestatus (dp, &er);
if (dp == NULL || (!v3 && er))
return (0);
if (qflag)
return (1);
if (v3)
{
if (vflag)
PUTS (" POST:");
if ((dp = parse_post_op_attr (dp, vflag)) == NULL)
return (0);
}
TCHECK2 (dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
sfsp = (const struct nfs_statfs*)dp;
if (v3)
{
PUTS (" tbytes ");
print_int64 ((u_int32_t*)&sfsp->sf_tbytes, UNSIGNED);
PUTS (" fbytes ");
print_int64 ((u_int32_t*)&sfsp->sf_fbytes, UNSIGNED);
PUTS (" abytes ");
print_int64 ((u_int32_t*)&sfsp->sf_abytes, UNSIGNED);
if (vflag)
{
PUTS (" tfiles ");
print_int64 ((u_int32_t*)&sfsp->sf_tfiles, UNSIGNED);
PUTS (" ffiles ");
print_int64 ((u_int32_t*)&sfsp->sf_ffiles, UNSIGNED);
PUTS (" afiles ");
print_int64 ((u_int32_t*)&sfsp->sf_afiles, UNSIGNED);
PRINTF (" invar %lu", ntohl (sfsp->sf_invarsec));
}
}
else
PRINTF (" tsize %ld bsize %ld blocks %ld bfree %ld bavail %ld",
ntohl (sfsp->sf_tsize),
ntohl (sfsp->sf_bsize),
ntohl (sfsp->sf_blocks),
ntohl (sfsp->sf_bfree),
ntohl (sfsp->sf_bavail));
return (1);
trunc:
return (0);
}
static int parserddires (const u_int32_t * dp)
{
int er;
dp = parsestatus (dp, &er);
if (dp == NULL || er)
return (0);
if (qflag)
return (1);
TCHECK (dp[2]);
PRINTF (" offset %lx size %ld ", ntohl (dp[0]), ntohl (dp[1]));
if (dp[2])
PUTS ("eof");
return (1);
trunc:
return (0);
}
static __inline const u_int32_t *parse_wcc_attr (const u_int32_t *dp)
{
PUTS (" sz ");
print_int64 (dp, UNSIGNED);
PRINTF (" mtime %lu.%06lu ctime %lu.%06lu",
ntohl (dp[2]), ntohl (dp[3]), ntohl (dp[4]), ntohl (dp[5]));
return (dp + 6);
}
/*
* Pre operation attributes. Print only if vflag > 1.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -