⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _nfs.c

📁 This directory contains source code for tcpdump, a tool for network monitoring and data acquisition
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -