?? print-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. */#ifndef lintstatic const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.110.2.1 2007-12-22 03:08:45 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <tcpdump-stdinc.h>#include <pcap.h>#include <stdio.h>#include <string.h>#include "interface.h"#include "addrtoname.h"#include "extract.h"#include "nfs.h"#include "nfsfh.h"#include "ip.h"#ifdef INET6#include "ip6.h"#endif#include "rpc_auth.h"#include "rpc_msg.h"static void nfs_printfh(const u_int32_t *, const u_int);static int xid_map_enter(const struct sunrpc_msg *, const u_char *);static int32_t xid_map_find(const struct sunrpc_msg *, const u_char *, u_int32_t *, u_int32_t *);static void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);static void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);static void print_nfsaddr(const u_char *, const char *, const char *);/* * Mapping of old NFS Version 2 RPC numbers to generic numbers. */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};/* * NFS V2 and V3 status values. * * Some of these come from the RFCs for NFS V2 and V3, with the message * strings taken from the FreeBSD C library "errlst.c". * * Others are errors that are not in the RFC but that I suspect some * NFS servers could return; the values are FreeBSD errno values, as * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS * was primarily BSD-derived. */static struct tok status2str[] = { { 1, "Operation not permitted" }, /* EPERM */ { 2, "No such file or directory" }, /* ENOENT */ { 5, "Input/output error" }, /* EIO */ { 6, "Device not configured" }, /* ENXIO */ { 11, "Resource deadlock avoided" }, /* EDEADLK */ { 12, "Cannot allocate memory" }, /* ENOMEM */ { 13, "Permission denied" }, /* EACCES */ { 17, "File exists" }, /* EEXIST */ { 18, "Cross-device link" }, /* EXDEV */ { 19, "Operation not supported by device" }, /* ENODEV */ { 20, "Not a directory" }, /* ENOTDIR */ { 21, "Is a directory" }, /* EISDIR */ { 22, "Invalid argument" }, /* EINVAL */ { 26, "Text file busy" }, /* ETXTBSY */ { 27, "File too large" }, /* EFBIG */ { 28, "No space left on device" }, /* ENOSPC */ { 30, "Read-only file system" }, /* EROFS */ { 31, "Too many links" }, /* EMLINK */ { 45, "Operation not supported" }, /* EOPNOTSUPP */ { 62, "Too many levels of symbolic links" }, /* ELOOP */ { 63, "File name too long" }, /* ENAMETOOLONG */ { 66, "Directory not empty" }, /* ENOTEMPTY */ { 69, "Disc quota exceeded" }, /* EDQUOT */ { 70, "Stale NFS file handle" }, /* ESTALE */ { 71, "Too many levels of remote in path" }, /* EREMOTE */ { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */ { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */ { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */ { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */ { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */ { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */ { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */ { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */ { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */ { 0, NULL }};static struct tok nfsv3_writemodes[] = { { 0, "unstable" }, { 1, "datasync" }, { 2, "filesync" }, { 0, NULL }};static struct tok type2str[] = { { NFNON, "NON" }, { NFREG, "REG" }, { NFDIR, "DIR" }, { NFBLK, "BLK" }, { NFCHR, "CHR" }, { NFLNK, "LNK" }, { NFFIFO, "FIFO" }, { 0, NULL }};static voidprint_nfsaddr(const u_char *bp, const char *s, const char *d){ struct ip *ip;#ifdef INET6 struct ip6_hdr *ip6; char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];#else#ifndef INET_ADDRSTRLEN#define INET_ADDRSTRLEN 16#endif char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];#endif srcaddr[0] = dstaddr[0] = '\0'; switch (IP_V((struct ip *)bp)) { case 4: ip = (struct ip *)bp; strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr)); strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr)); break;#ifdef INET6 case 6: ip6 = (struct ip6_hdr *)bp; strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src), sizeof(srcaddr)); strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst), sizeof(dstaddr)); break;#endif default: strlcpy(srcaddr, "?", sizeof(srcaddr)); strlcpy(dstaddr, "?", sizeof(dstaddr)); break; } (void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);}static const u_int32_t *parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3){ TCHECK(dp[0]); sa3->sa_modeset = EXTRACT_32BITS(dp); dp++; if (sa3->sa_modeset) { TCHECK(dp[0]); sa3->sa_mode = EXTRACT_32BITS(dp); dp++; } TCHECK(dp[0]); sa3->sa_uidset = EXTRACT_32BITS(dp); dp++; if (sa3->sa_uidset) { TCHECK(dp[0]); sa3->sa_uid = EXTRACT_32BITS(dp); dp++; } TCHECK(dp[0]); sa3->sa_gidset = EXTRACT_32BITS(dp); dp++; if (sa3->sa_gidset) { TCHECK(dp[0]); sa3->sa_gid = EXTRACT_32BITS(dp); dp++; } TCHECK(dp[0]); sa3->sa_sizeset = EXTRACT_32BITS(dp); dp++; if (sa3->sa_sizeset) { TCHECK(dp[0]); sa3->sa_size = EXTRACT_32BITS(dp); dp++; } TCHECK(dp[0]); sa3->sa_atimetype = EXTRACT_32BITS(dp); dp++; if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) { TCHECK(dp[1]); sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp); dp++; sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp); dp++; } TCHECK(dp[0]); sa3->sa_mtimetype = EXTRACT_32BITS(dp); dp++; if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) { TCHECK(dp[1]); sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp); dp++; sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp); dp++; } return dp;trunc: return NULL;}static int nfserr; /* true if we error rather than trunc */static voidprint_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); }}voidnfsreply_print(register const u_char *bp, u_int length, register const u_char *bp2){ register const struct sunrpc_msg *rp; u_int32_t proc, vers, reply_stat; char srcid[20], dstid[20]; /*fits 32bit*/ enum sunrpc_reject_stat rstat; u_int32_t rlow; u_int32_t rhigh; enum sunrpc_auth_stat rwhy; nfserr = 0; /* assume no error */ rp = (const struct sunrpc_msg *)bp; TCHECK(rp->rm_xid); if (!nflag) { strlcpy(srcid, "nfs", sizeof(srcid)); snprintf(dstid, sizeof(dstid), "%u", EXTRACT_32BITS(&rp->rm_xid)); } else { snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); snprintf(dstid, sizeof(dstid), "%u", EXTRACT_32BITS(&rp->rm_xid)); } print_nfsaddr(bp2, srcid, dstid); TCHECK(rp->rm_reply.rp_stat); reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat); switch (reply_stat) { case SUNRPC_MSG_ACCEPTED: (void)printf("reply ok %u", length); if (xid_map_find(rp, bp2, &proc, &vers) >= 0) interp_reply(rp, proc, vers, length); break; case SUNRPC_MSG_DENIED: (void)printf("reply ERR %u: ", length); TCHECK(rp->rm_reply.rp_reject.rj_stat); rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat); switch (rstat) { case SUNRPC_RPC_MISMATCH: TCHECK(rp->rm_reply.rp_reject.rj_vers.high); rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low); rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high); (void)printf("RPC Version mismatch (%u-%u)", rlow, rhigh); break; case SUNRPC_AUTH_ERROR: TCHECK(rp->rm_reply.rp_reject.rj_why); rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why); (void)printf("Auth "); switch (rwhy) { case SUNRPC_AUTH_OK: (void)printf("OK"); break; case SUNRPC_AUTH_BADCRED: (void)printf("Bogus Credentials (seal broken)"); break; case SUNRPC_AUTH_REJECTEDCRED: (void)printf("Rejected Credentials (client should begin new session)"); break; case SUNRPC_AUTH_BADVERF: (void)printf("Bogus Verifier (seal broken)"); break; case SUNRPC_AUTH_REJECTEDVERF: (void)printf("Verifier expired or was replayed"); break; case SUNRPC_AUTH_TOOWEAK: (void)printf("Credentials are too weak"); break; case SUNRPC_AUTH_INVALIDRESP: (void)printf("Bogus response verifier"); break; case SUNRPC_AUTH_FAILED: (void)printf("Unknown failure"); break; default: (void)printf("Invalid failure code %u", (unsigned int)rwhy); break; } break; default: (void)printf("Unknown reason for rejecting rpc message %u", (unsigned int)rstat); break; } break; default: (void)printf("reply Unknown rpc response code=%u %u", reply_stat, length); break; } return;trunc: if (!nfserr) fputs(" [|nfs]", stdout);}/* * Return a pointer to the first file handle in the packet. * If the packet was truncated, return 0. */static const u_int32_t *parsereq(register const struct sunrpc_msg *rp, register u_int length){ register const u_int32_t *dp; register 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 = EXTRACT_32BITS(&dp[1]); if (len < length) { dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); TCHECK(dp[1]); len = EXTRACT_32BITS(&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 0. */static const u_int32_t *parsefh(register const u_int32_t *dp, int v3){ u_int len; if (v3) { TCHECK(dp[0]); len = EXTRACT_32BITS(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 0. */static const u_int32_t *parsefn(register const u_int32_t *dp){ register u_int32_t len; register const u_char *cp; /* Bail if we don't have the string length */ TCHECK(*dp); /* Fetch string length; convert to host order */ len = *dp++; NTOHL(len); TCHECK2(*dp, ((len + 3) & ~3)); cp = (u_char *)dp; /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ dp += ((len + 3) & ~3) / sizeof(*dp); putchar('"'); if (fn_printn(cp, len, snapend)) { putchar('"'); goto trunc; } putchar('"'); return (dp);trunc: return NULL;}/* * 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 0. */static const u_int32_t *parsefhn(register const u_int32_t *dp, int v3){ dp = parsefh(dp, v3); if (dp == NULL) return (NULL); putchar(' '); return (parsefn(dp));}voidnfsreq_print(register const u_char *bp, u_int length, register const u_char *bp2){ register const struct sunrpc_msg *rp; register const u_int32_t *dp; nfs_type type; int v3; u_int32_t proc; struct nfsv3_sattr sa3; char srcid[20], dstid[20]; /*fits 32bit*/ nfserr = 0; /* assume no error */ rp = (const struct sunrpc_msg *)bp; TCHECK(rp->rm_xid); if (!nflag) { snprintf(srcid, sizeof(srcid), "%u", EXTRACT_32BITS(&rp->rm_xid)); strlcpy(dstid, "nfs", sizeof(dstid)); } else { snprintf(srcid, sizeof(srcid), "%u", EXTRACT_32BITS(&rp->rm_xid)); snprintf(dstid, sizeof(dstid), "%u", NFS_PORT); } print_nfsaddr(bp2, srcid, dstid); (void)printf("%d", length); if (!xid_map_enter(rp, bp2)) /* record proc number for later on */ goto trunc; v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3); proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); if (!v3 && proc < NFS_NPROCS) proc = nfsv3_procid[proc]; switch (proc) { case NFSPROC_NOOP: printf(" nop"); return; case NFSPROC_NULL: printf(" null"); return; case NFSPROC_GETATTR: printf(" getattr"); if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) return; break; case NFSPROC_SETATTR: printf(" setattr"); if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) return; break; case NFSPROC_LOOKUP: printf(" lookup"); if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp, v3) != NULL) return; break; case NFSPROC_ACCESS: printf(" access"); if ((dp = parsereq(rp, length)) != NULL && (dp = parsefh(dp, v3)) != NULL) { TCHECK(dp[0]); printf(" %04x", EXTRACT_32BITS(&dp[0])); return; } break; case NFSPROC_READLINK: printf(" readlink"); if ((dp = parsereq(rp, length)) != NULL && parsefh(dp, v3) != NULL) return; break; case NFSPROC_READ: printf(" read"); if ((dp = parsereq(rp, length)) != NULL && (dp = parsefh(dp, v3)) != NULL) { if (v3) { TCHECK(dp[2]); printf(" %u bytes @ %" PRIu64, EXTRACT_32BITS(&dp[2]), EXTRACT_64BITS(&dp[0])); } else { TCHECK(dp[1]); printf(" %u bytes @ %u", EXTRACT_32BITS(&dp[1]), EXTRACT_32BITS(&dp[0])); } return; } break; case NFSPROC_WRITE: printf(" write"); if ((dp = parsereq(rp, length)) != NULL && (dp = parsefh(dp, v3)) != NULL) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -