📄 _nfs.c
字号:
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if 0
static const char rcsid[] = "@(#) $Header: print-nfs.c,v 1.65 97/08/17 13:24:22 leres Exp $ (LBL)";
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <rpc/rpc.h>
#include <pcap.h>
#include "interfac.h"
#include "a2name.h"
#include "extract.h" /* must come after interface.h */
#include "nfs.h"
#include "nfsfh.h"
static void nfs_printfh (const u_int32_t *, const int);
static void xid_map_enter (const struct rpc_msg *, const struct ip *);
static int xid_map_find (const struct rpc_msg *, const struct ip *,
u_int32_t *, u_int32_t *);
static void interp_reply (const struct rpc_msg *, u_int32_t, u_int32_t, int);
static const u_int32_t *parse_post_op_attr (const u_int32_t *, int);
static int nfserr; /* true if we error rather than trunc */
/*
* Mapping of old NFS Version 2 RPC numbers to generic numbers.
*/
static u_int32_t nfsv3_procid[NFS_NPROCS] = {
NFSPROC_NULL,
NFSPROC_GETATTR,
NFSPROC_SETATTR,
NFSPROC_NOOP,
NFSPROC_LOOKUP,
NFSPROC_READLINK,
NFSPROC_READ,
NFSPROC_NOOP,
NFSPROC_WRITE,
NFSPROC_CREATE,
NFSPROC_REMOVE,
NFSPROC_RENAME,
NFSPROC_LINK,
NFSPROC_SYMLINK,
NFSPROC_MKDIR,
NFSPROC_RMDIR,
NFSPROC_READDIR,
NFSPROC_FSSTAT,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP
};
static const char *nfsv3_writemodes[NFSV3WRITE_NMODES] = {
"unstable", "datasync", "filesync"
};
static struct tok type2str[] = {
{ NFNON, "NON" },
{ NFREG, "REG" },
{ NFDIR, "DIR" },
{ NFBLK, "BLK" },
{ NFCHR, "CHR" },
{ NFLNK, "LNK" },
{ NFFIFO,"FIFO" },
{ 0, NULL }
};
/*
* Print out a 64-bit integer. This appears to be different on each system,
* try to make the best of it. The integer stored as 2 consecutive XDR
* encoded 32-bit integers, to which a pointer is passed.
*
* Assume that a system that has INT64_FORMAT defined, has a 64-bit
* integer datatype and can print it.
*/
#define UNSIGNED 0
#define SIGNED 1
#define HEX 2
#if defined(__GNUC__) && defined(__DJGPP__)
#define INT64_FORMAT "%Ld"
#define U_INT64_FORMAT "%Lu"
#define HEX_INT64_FORMAT "%Lx"
#else
#define INT64_FORMAT "%qd"
#define U_INT64_FORMAT "%qu"
#define HEX_INT64_FORMAT "%qx"
#endif
static int print_int64 (const u_int32_t *dp, int how)
{
#ifdef INT64_FORMAT
u_int64_t res;
res = ((u_int64_t) ntohl (dp[0]) << 32) | (u_int64_t) ntohl (dp[1]);
switch (how)
{
case SIGNED:
PRINTF (INT64_FORMAT, res);
break;
case UNSIGNED:
PRINTF (U_INT64_FORMAT, res);
break;
case HEX:
PRINTF (HEX_INT64_FORMAT, res);
break;
default:
return (0);
}
#else
/*
* XXX - throw upper 32 bits away.
* Could also go for hex: printf("0x%x%x", dp[0], dp[1]);
*/
if (how == SIGNED)
PRINTF ("%ld", (int) dp[1]);
else PRINTF ("%lu", (unsigned int)dp[1]);
#endif
return (1);
}
static const u_int32_t *parse_sattr3 (const u_int32_t *dp,
struct nfsv3_sattr *sa3)
{
const u_int32_t *ep = (u_int32_t*)snapend;
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_modeset = ntohl(*dp++)) != 0)
{
if (dp + 1 > ep)
return (NULL);
sa3->sa_mode = ntohl (*dp++);
}
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_uidset = ntohl(*dp++)) != 0)
{
if (dp + 1 > ep)
return (NULL);
sa3->sa_uid = ntohl (*dp++);
}
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_gidset = ntohl(*dp++)) != 0)
{
if (dp + 1 > ep)
return (NULL);
sa3->sa_gid = ntohl (*dp++);
}
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_sizeset = ntohl(*dp++)) != 0)
{
if (dp + 1 > ep)
return (NULL);
sa3->sa_size = ntohl (*dp++);
}
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_atimetype = ntohl (*dp++)) == NFSV3SATTRTIME_TOCLIENT)
{
if (dp + 2 > ep)
return (NULL);
sa3->sa_atime.nfsv3_sec = ntohl (*dp++);
sa3->sa_atime.nfsv3_nsec = ntohl (*dp++);
}
if (dp + 1 > ep)
return (NULL);
if ((sa3->sa_mtimetype = ntohl (*dp++)) == NFSV3SATTRTIME_TOCLIENT)
{
if (dp + 2 > ep)
return (NULL);
sa3->sa_mtime.nfsv3_sec = ntohl (*dp++);
sa3->sa_mtime.nfsv3_nsec = ntohl (*dp++);
}
return dp;
}
static void print_sattr3 (const struct nfsv3_sattr *sa3, int verbose)
{
if (sa3->sa_modeset)
PRINTF (" mode %o", sa3->sa_mode);
if (sa3->sa_uidset)
PRINTF (" uid %u", sa3->sa_uid);
if (sa3->sa_gidset)
PRINTF (" gid %u", sa3->sa_gid);
if (verbose > 1)
{
if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
PRINTF (" atime %u.%06u",
sa3->sa_atime.nfsv3_sec,
sa3->sa_atime.nfsv3_nsec);
if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
PRINTF (" mtime %u.%06u",
sa3->sa_mtime.nfsv3_sec,
sa3->sa_mtime.nfsv3_nsec);
}
}
void nfsreply_print (const u_char * bp, u_int length, const u_char * bp2)
{
const struct rpc_msg *rp;
const struct ip *ip;
u_int32_t proc, vers;
nfserr = 0; /* assume no error */
rp = (const struct rpc_msg*) bp;
ip = (const struct ip*) bp2;
if (!nflag)
PRINTF ("%s.nfs > %s.%u: reply %s %d",
ipaddr_string (&ip->ip_src),
ipaddr_string (&ip->ip_dst),
ntohl (rp->rm_xid),
ntohl (rp->rm_reply.rp_stat) == MSG_ACCEPTED ? "ok" : "ERR",
length);
else PRINTF ("%s.%u > %s.%u: reply %s %d",
ipaddr_string (&ip->ip_src),
NFS_PORT,
ipaddr_string (&ip->ip_dst),
ntohl (rp->rm_xid),
ntohl (rp->rm_reply.rp_stat) == MSG_ACCEPTED ? "ok" : "ERR",
length);
if (xid_map_find (rp, ip, &proc, &vers) >= 0)
interp_reply (rp, proc, vers, length);
}
/*
* Return a pointer to the first file handle in the packet.
* If the packet was truncated, return NULL.
*/
static const u_int32_t *parsereq (const struct rpc_msg *rp, int length)
{
const u_int32_t *dp;
u_int len;
/* find the start of the req data (if we captured it)
*/
dp = (u_int32_t*) &rp->rm_call.cb_cred;
TCHECK (dp[1]);
len = ntohl (dp[1]);
if (len < length)
{
dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
TCHECK (dp[1]);
len = ntohl (dp[1]);
if (len < length)
{
dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
TCHECK2 (dp[0], 0);
return (dp);
}
}
trunc:
return (NULL);
}
/*
* Print out an NFS file handle and return a pointer to following word.
* If packet was truncated, return NULL.
*/
static const u_int32_t *parsefh (const u_int32_t *dp, int v3)
{
int len;
if (v3)
{
TCHECK (dp[0]);
len = (int) ntohl (*dp) / 4;
dp++;
}
else
len = NFSX_V2FH / 4;
if (TTEST2 (*dp, len * sizeof(*dp)))
{
nfs_printfh (dp, len);
return (dp + len);
}
trunc:
return (NULL);
}
/*
* Print out a file name and return pointer to 32-bit word past it.
* If packet was truncated, return NULL.
*/
static const u_int32_t *parsefn (const u_int32_t *dp)
{
u_int32_t len;
const u_char *cp;
/* Bail if we don't have the string length
*/
if ((u_char*)dp > snapend - sizeof(*dp))
return (NULL);
/* Fetch string length; convert to host order
*/
len = *dp++;
NTOHL (len);
cp = (u_char*)dp;
/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries)
*/
dp += ((len + 3) & ~3) / sizeof(*dp);
if ((u_char*)dp > snapend)
return (NULL);
/* XXX seems like we should be checking the length
*/
PUTCHAR ('"');
fn_printn ((char*)cp, len, NULL);
PUTCHAR ('"');
return (dp);
}
/*
* Print out file handle and file name.
* Return pointer to 32-bit word past file name.
* If packet was truncated (or there was some other error), return NULL.
*/
static __inline const u_int32_t *parsefhn (const u_int32_t * dp, int v3)
{
dp = parsefh (dp, v3);
if (dp == NULL)
return (NULL);
PUTCHAR (' ');
return (parsefn (dp));
}
void nfsreq_print (const u_char * bp, u_int length, const u_char * bp2)
{
struct nfsv3_sattr sa3;
const struct rpc_msg *rp;
const struct ip *ip;
const u_int32_t *dp;
nfstype type;
unsigned proc, v3;
nfserr = 0; /* assume no error */
rp = (const struct rpc_msg*)bp;
ip = (const struct ip*)bp2;
if (!nflag)
PRINTF ("%s.%u > %s.nfs: %d",
ipaddr_string (&ip->ip_src), ntohl (rp->rm_xid),
ipaddr_string (&ip->ip_dst), length);
else PRINTF ("%s.%u > %s.%u: %d",
ipaddr_string (&ip->ip_src), ntohl (rp->rm_xid),
ipaddr_string (&ip->ip_dst), NFS_PORT, length);
xid_map_enter (rp, ip); /* record proc number for later on */
v3 = (ntohl (rp->rm_call.cb_vers) == NFS_VER3);
proc = ntohl (rp->rm_call.cb_proc);
if (!v3 && proc < DIM(nfsv3_procid))
proc = nfsv3_procid[proc];
switch (proc)
{
case NFSPROC_NOOP:
PUTS (" nop");
return;
case NFSPROC_NULL:
PUTS (" null");
return;
case NFSPROC_GETATTR:
PUTS (" getattr");
dp = parsereq (rp, length);
if (dp && parsefh (dp, v3))
return;
break;
case NFSPROC_SETATTR:
PUTS (" setattr");
dp = parsereq (rp, length);
if (dp && parsefh (dp, v3))
return;
break;
case NFSPROC_LOOKUP:
PUTS (" lookup");
dp = parsereq (rp, length);
if (dp && parsefhn (dp, v3))
return;
break;
case NFSPROC_ACCESS:
PUTS (" access");
dp = parsereq (rp, length);
if (dp && (dp = parsefh (dp, v3)) != NULL)
{
TCHECK (*dp);
PRINTF (" %04lx", ntohl (dp[0]));
return;
}
break;
case NFSPROC_READLINK:
PUTS (" readlink");
dp = parsereq (rp, length);
if (dp && parsefh (dp, v3))
return;
break;
case NFSPROC_READ:
PUTS (" read");
dp = parsereq (rp, length);
if (dp && (dp = parsefh (dp, v3)) != NULL)
{
if (v3)
{
TCHECK2 (*dp, 3 * sizeof(*dp));
PRINTF (" %lu bytes @ ", ntohl (dp[2]));
print_int64 (dp, UNSIGNED);
}
else
{
TCHECK2 (*dp, 2 * sizeof(*dp));
PRINTF (" %lu bytes @ %lu", ntohl (dp[1]), ntohl (dp[0]));
}
return;
}
break;
case NFSPROC_WRITE:
PUTS (" write");
dp = parsereq (rp, length);
if (dp && (dp = parsefh (dp, v3)) != NULL)
{
if (v3)
{
TCHECK2 (*dp, 3 * sizeof(*dp));
PRINTF (" %lu bytes @ ", ntohl (dp[4]));
print_int64 (dp, UNSIGNED);
if (vflag)
{
dp += 3;
TCHECK2 (*dp, sizeof(*dp));
PRINTF (" <%s>", nfsv3_writemodes[ntohl (*dp)]);
}
}
else
{
TCHECK2 (*dp, 4 * sizeof(*dp));
PRINTF (" %lu (%lu) bytes @ %lu (%lu)",
ntohl (dp[3]), ntohl (dp[2]),
ntohl (dp[1]), ntohl (dp[0]));
}
return;
}
break;
case NFSPROC_CREATE:
PUTS (" create");
if ((dp = parsereq (rp, length)) != NULL && parsefhn (dp, v3))
return;
break;
case NFSPROC_MKDIR:
PUTS (" mkdir");
if ((dp = parsereq (rp, length)) != NULL && parsefhn (dp, v3))
return;
break;
case NFSPROC_SYMLINK:
PUTS (" symlink");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefhn (dp, v3)) != NULL)
{
PUTS (" -> ");
if (v3 && (dp = parse_sattr3 (dp, &sa3)) == NULL)
break;
if (parsefn (dp) == NULL)
break;
if (v3 && vflag)
print_sattr3 (&sa3, vflag);
return;
}
break;
case NFSPROC_MKNOD:
PUTS (" mknod");
if ((dp = parsereq (rp, length)) != NULL && (dp = parsefhn (dp, v3)) != NULL)
{
if (dp + 1 > (u_int32_t*)snapend)
break;
type = (nfstype) ntohl (*dp++);
if ((dp = parse_sattr3 (dp, &sa3)) == NULL)
break;
PRINTF (" %s", tok2str (type2str, "unk-ft %d", type));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -