]>
The Tcpdump Group git mirrors - tcpdump/blob - print-nfs.c
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 static const char rcsid
[] =
24 "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.65 1999-10-07 23:47:12 mcr Exp $ (LBL)";
27 #include <sys/param.h>
29 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/if_ether.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip_var.h>
50 #include "interface.h"
51 #include "addrtoname.h"
56 static void nfs_printfh(const u_int32_t
*);
57 static void xid_map_enter(const struct rpc_msg
*, const struct ip
*);
58 static u_int32_t
xid_map_find(const struct rpc_msg
*, const struct ip
*,
60 static void interp_reply(const struct rpc_msg
*, u_int32_t
, u_int
);
62 static int nfserr
; /* true if we error rather than trunc */
65 nfsreply_print(register const u_char
*bp
, u_int length
,
66 register const u_char
*bp2
)
68 register const struct rpc_msg
*rp
;
69 register const struct ip
*ip
;
72 nfserr
= 0; /* assume no error */
73 rp
= (const struct rpc_msg
*)bp
;
74 ip
= (const struct ip
*)bp2
;
77 (void)printf("%s.nfs > %s.%u: reply %s %d",
78 ipaddr_string(&ip
->ip_src
),
79 ipaddr_string(&ip
->ip_dst
),
80 (u_int32_t
)ntohl(rp
->rm_xid
),
81 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
85 (void)printf("%s.%u > %s.%u: reply %s %d",
86 ipaddr_string(&ip
->ip_src
),
88 ipaddr_string(&ip
->ip_dst
),
89 (u_int32_t
)ntohl(rp
->rm_xid
),
90 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
94 if (xid_map_find(rp
, ip
, &proc
))
95 interp_reply(rp
, proc
, length
);
99 * Return a pointer to the first file handle in the packet.
100 * If the packet was truncated, return 0.
102 static const u_int32_t
*
103 parsereq(register const struct rpc_msg
*rp
, register u_int length
)
105 register const u_int32_t
*dp
;
109 * find the start of the req data (if we captured it)
111 dp
= (u_int32_t
*)&rp
->rm_call
.cb_cred
;
115 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
119 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
129 * Print out an NFS file handle and return a pointer to following word.
130 * If packet was truncated, return 0.
132 static const u_int32_t
*
133 parsefh(register const u_int32_t
*dp
)
135 if (dp
+ 8 <= (u_int32_t
*)snapend
) {
143 * Print out a file name and return pointer to 32-bit word past it.
144 * If packet was truncated, return 0.
146 static const u_int32_t
*
147 parsefn(register const u_int32_t
*dp
)
149 register u_int32_t len
;
150 register const u_char
*cp
;
152 /* Bail if we don't have the string length */
153 if ((u_char
*)dp
> snapend
- sizeof(*dp
))
156 /* Fetch string length; convert to host order */
161 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
162 dp
+= ((len
+ 3) & ~3) / sizeof(*dp
);
163 if ((u_char
*)dp
> snapend
)
165 /* XXX seems like we should be checking the length */
167 (void) fn_printn(cp
, len
, NULL
);
174 * Print out file handle and file name.
175 * Return pointer to 32-bit word past file name.
176 * If packet was truncated (or there was some other error), return 0.
178 static const u_int32_t
*
179 parsefhn(register const u_int32_t
*dp
)
185 return (parsefn(dp
));
189 nfsreq_print(register const u_char
*bp
, u_int length
,
190 register const u_char
*bp2
)
192 register const struct rpc_msg
*rp
;
193 register const struct ip
*ip
;
194 register const u_int32_t
*dp
;
196 nfserr
= 0; /* assume no error */
197 rp
= (const struct rpc_msg
*)bp
;
198 ip
= (const struct ip
*)bp2
;
200 (void)printf("%s.%u > %s.nfs: %d",
201 ipaddr_string(&ip
->ip_src
),
202 (u_int32_t
)ntohl(rp
->rm_xid
),
203 ipaddr_string(&ip
->ip_dst
),
206 (void)printf("%s.%u > %s.%u: %d",
207 ipaddr_string(&ip
->ip_src
),
208 (u_int32_t
)ntohl(rp
->rm_xid
),
209 ipaddr_string(&ip
->ip_dst
),
213 xid_map_enter(rp
, ip
); /* record proc number for later on */
215 switch (ntohl(rp
->rm_call
.cb_proc
)) {
221 #define NFSPROC_NOOP -1
227 case NFSPROC_GETATTR
:
229 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
233 case NFSPROC_SETATTR
:
235 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
239 #if NFSPROC_ROOT != NFSPROC_NOOP
246 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
250 case NFSPROC_READLINK
:
252 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
258 if ((dp
= parsereq(rp
, length
)) != NULL
&&
259 (dp
= parsefh(dp
)) != NULL
) {
260 TCHECK2(dp
[0], 3 * sizeof(*dp
));
261 printf(" %u bytes @ %u",
262 (u_int32_t
)ntohl(dp
[1]),
263 (u_int32_t
)ntohl(dp
[0]));
268 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
269 case NFSPROC_WRITECACHE
:
270 printf(" writecache");
271 if ((dp
= parsereq(rp
, length
)) != NULL
&&
272 (dp
= parsefh(dp
)) != NULL
) {
273 TCHECK2(dp
[0], 4 * sizeof(*dp
));
274 printf(" %u (%u) bytes @ %u (%u)",
275 (u_int32_t
)ntohl(dp
[3]),
276 (u_int32_t
)ntohl(dp
[2]),
277 (u_int32_t
)ntohl(dp
[1]),
278 (u_int32_t
)ntohl(dp
[0]));
285 if ((dp
= parsereq(rp
, length
)) != NULL
&&
286 (dp
= parsefh(dp
)) != NULL
) {
287 TCHECK2(dp
[0], 4 * sizeof(*dp
));
288 printf(" %u (%u) bytes @ %u (%u)",
289 (u_int32_t
)ntohl(dp
[3]),
290 (u_int32_t
)ntohl(dp
[2]),
291 (u_int32_t
)ntohl(dp
[1]),
292 (u_int32_t
)ntohl(dp
[0]));
299 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
305 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
311 if ((dp
= parsereq(rp
, length
)) != NULL
&&
312 (dp
= parsefhn(dp
)) != NULL
) {
313 fputs(" ->", stdout
);
314 if (parsefhn(dp
) != NULL
)
321 if ((dp
= parsereq(rp
, length
)) != NULL
&&
322 (dp
= parsefh(dp
)) != NULL
) {
323 fputs(" ->", stdout
);
324 if (parsefhn(dp
) != NULL
)
329 case NFSPROC_SYMLINK
:
331 if ((dp
= parsereq(rp
, length
)) != NULL
&&
332 (dp
= parsefhn(dp
)) != NULL
) {
333 fputs(" -> ", stdout
);
334 if (parsefn(dp
) != NULL
)
341 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
347 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
351 case NFSPROC_READDIR
:
353 if ((dp
= parsereq(rp
, length
)) != NULL
&&
354 (dp
= parsefh(dp
)) != NULL
) {
355 TCHECK2(dp
[0], 2 * sizeof(*dp
));
357 * Print the offset as signed, since -1 is common,
358 * but offsets > 2^31 aren't.
360 printf(" %u bytes @ %d",
361 (u_int32_t
)ntohl(dp
[1]),
362 (u_int32_t
)ntohl(dp
[0]));
369 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
374 printf(" proc-%u", (u_int32_t
)ntohl(rp
->rm_call
.cb_proc
));
379 fputs(" [|nfs]", stdout
);
383 * Print out an NFS file handle.
384 * We assume packet was not truncated before the end of the
385 * file handle pointed to by dp.
387 * Note: new version (using portable file-handle parser) doesn't produce
388 * generation number. It probably could be made to do that, with some
389 * additional hacking on the parser code.
392 nfs_printfh(register const u_int32_t
*dp
)
396 char *sfsname
= NULL
;
398 Parse_fh((caddr_t
*)dp
, &fsid
, &ino
, NULL
, &sfsname
, 0);
401 /* file system ID is ASCII, not numeric, for this server OS */
402 static char temp
[NFS_FHSIZE
+1];
404 /* Make sure string is null-terminated */
405 strncpy(temp
, sfsname
, NFS_FHSIZE
);
406 /* Remove trailing spaces */
407 sfsname
= strchr(temp
, ' ');
411 (void)printf(" fh %s/%u", temp
, (u_int32_t
)ino
);
413 (void)printf(" fh %u,%u/%u",
414 fsid
.Fsid_dev
.Major
, fsid
.Fsid_dev
.Minor
, (u_int32_t
)ino
);
419 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
420 * us to match up replies with requests and thus to know how to parse
424 struct xid_map_entry
{
425 u_int32_t xid
; /* transaction ID (net order) */
426 struct in_addr client
; /* client IP address (net order) */
427 struct in_addr server
; /* server IP address (net order) */
428 u_int32_t proc
; /* call proc number (host order) */
432 * Map entries are kept in an array that we manage as a ring;
433 * new entries are always added at the tail of the ring. Initially,
434 * all the entries are zero and hence don't match anything.
437 #define XIDMAPSIZE 64
439 struct xid_map_entry xid_map
[XIDMAPSIZE
];
441 int xid_map_next
= 0;
442 int xid_map_hint
= 0;
445 xid_map_enter(const struct rpc_msg
*rp
, const struct ip
*ip
)
447 struct xid_map_entry
*xmep
;
449 xmep
= &xid_map
[xid_map_next
];
451 if (++xid_map_next
>= XIDMAPSIZE
)
454 xmep
->xid
= rp
->rm_xid
;
455 xmep
->client
= ip
->ip_src
;
456 xmep
->server
= ip
->ip_dst
;
457 xmep
->proc
= ntohl(rp
->rm_call
.cb_proc
);
460 /* Returns true and sets proc success or false on failure */
462 xid_map_find(const struct rpc_msg
*rp
, const struct ip
*ip
, u_int32_t
*proc
)
465 struct xid_map_entry
*xmep
;
466 u_int32_t xid
= rp
->rm_xid
;
467 u_int32_t clip
= ip
->ip_dst
.s_addr
;
468 u_int32_t sip
= ip
->ip_src
.s_addr
;
470 /* Start searching from where we last left off */
474 if (xmep
->xid
== xid
&& xmep
->client
.s_addr
== clip
&&
475 xmep
->server
.s_addr
== sip
) {
481 if (++i
>= XIDMAPSIZE
)
483 } while (i
!= xid_map_hint
);
490 * Routines for parsing reply packets
494 * Return a pointer to the beginning of the actual results.
495 * If the packet was truncated, return 0.
497 static const u_int32_t
*
498 parserep(register const struct rpc_msg
*rp
, register u_int length
)
500 register const u_int32_t
*dp
;
502 enum accept_stat astat
;
506 * Here we find the address of the ar_verf credentials.
507 * Originally, this calculation was
508 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
509 * On the wire, the rp_acpt field starts immediately after
510 * the (32 bit) rp_stat field. However, rp_acpt (which is a
511 * "struct accepted_reply") contains a "struct opaque_auth",
512 * whose internal representation contains a pointer, so on a
513 * 64-bit machine the compiler inserts 32 bits of padding
514 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
515 * the internal representation to parse the on-the-wire
516 * representation. Instead, we skip past the rp_stat field,
517 * which is an "enum" and so occupies one 32-bit word.
519 dp
= ((const u_int32_t
*)&rp
->rm_reply
) + 1;
525 * skip past the ar_verf credentials.
527 dp
+= (len
+ (2*sizeof(u_int32_t
) + 3)) / sizeof(u_int32_t
);
531 * now we can check the ar_stat field
533 astat
= ntohl(*(enum accept_stat
*)dp
);
540 printf(" PROG_UNAVAIL");
541 nfserr
= 1; /* suppress trunc string */
545 printf(" PROG_MISMATCH");
546 nfserr
= 1; /* suppress trunc string */
550 printf(" PROC_UNAVAIL");
551 nfserr
= 1; /* suppress trunc string */
555 printf(" GARBAGE_ARGS");
556 nfserr
= 1; /* suppress trunc string */
560 printf(" SYSTEM_ERR");
561 nfserr
= 1; /* suppress trunc string */
565 printf(" ar_stat %d", astat
);
566 nfserr
= 1; /* suppress trunc string */
569 /* successful return */
570 if ((sizeof(astat
) + ((u_char
*)dp
)) < snapend
)
571 return ((u_int32_t
*) (sizeof(astat
) + ((char *)dp
)));
577 static const u_int32_t
*
578 parsestatus(const u_int32_t
*dp
)
583 errnum
= ntohl(dp
[0]);
586 printf(" ERROR: %s", pcap_strerror(errnum
));
587 nfserr
= 1; /* suppress trunc string */
595 static struct tok type2str
[] = {
605 static const u_int32_t
*
606 parsefattr(const u_int32_t
*dp
, int verbose
)
608 const struct nfsv2_fattr
*fap
;
610 fap
= (const struct nfsv2_fattr
*)dp
;
612 TCHECK(fap
->fa_nfssize
);
613 printf(" %s %o ids %u/%u sz %u ",
614 tok2str(type2str
, "unk-ft %d ",
615 (u_int32_t
)ntohl(fap
->fa_type
)),
616 (u_int32_t
)ntohl(fap
->fa_mode
),
617 (u_int32_t
)ntohl(fap
->fa_uid
),
618 (u_int32_t
)ntohl(fap
->fa_gid
),
619 (u_int32_t
)ntohl(fap
->fa_nfssize
));
621 /* print lots more stuff */
623 TCHECK(fap
->fa_nfsfileid
);
624 printf("nlink %u rdev %x fsid %x nodeid %x a/m/ctime ",
625 (u_int32_t
)ntohl(fap
->fa_nlink
),
626 (u_int32_t
)ntohl(fap
->fa_nfsrdev
),
627 (u_int32_t
)ntohl(fap
->fa_nfsfsid
),
628 (u_int32_t
)ntohl(fap
->fa_nfsfileid
));
629 TCHECK(fap
->fa_nfsatime
);
631 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_sec
),
632 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_usec
));
633 TCHECK(fap
->fa_nfsmtime
);
635 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_sec
),
636 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_usec
));
637 TCHECK(fap
->fa_nfsctime
);
639 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_sec
),
640 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_usec
));
642 return ((const u_int32_t
*)&fap
[1]);
648 parseattrstat(const u_int32_t
*dp
, int verbose
)
651 dp
= parsestatus(dp
);
655 return (parsefattr(dp
, verbose
) != NULL
);
659 parsediropres(const u_int32_t
*dp
)
662 dp
= parsestatus(dp
);
670 return (parsefattr(dp
, vflag
) != NULL
);
674 parselinkres(const u_int32_t
*dp
)
676 dp
= parsestatus(dp
);
681 return (parsefn(dp
) != NULL
);
685 parsestatfs(const u_int32_t
*dp
)
687 const struct nfsv2_statfs
*sfsp
;
689 dp
= parsestatus(dp
);
694 sfsp
= (const struct nfsv2_statfs
*)dp
;
695 TCHECK(sfsp
->sf_bavail
);
696 printf(" tsize %u bsize %u blocks %u bfree %u bavail %u",
697 (u_int32_t
)ntohl(sfsp
->sf_tsize
),
698 (u_int32_t
)ntohl(sfsp
->sf_bsize
),
699 (u_int32_t
)ntohl(sfsp
->sf_blocks
),
700 (u_int32_t
)ntohl(sfsp
->sf_bfree
),
701 (u_int32_t
)ntohl(sfsp
->sf_bavail
));
710 parserddires(const u_int32_t
*dp
)
712 dp
= parsestatus(dp
);
717 printf(" offset %x", (u_int32_t
)ntohl(dp
[0]));
719 printf(" size %u", (u_int32_t
)ntohl(dp
[1]));
731 interp_reply(const struct rpc_msg
*rp
, u_int32_t proc
, u_int length
)
733 register const u_int32_t
*dp
;
742 #define NFSPROC_NOOP -1
748 case NFSPROC_GETATTR
:
750 dp
= parserep(rp
, length
);
751 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
755 case NFSPROC_SETATTR
:
757 dp
= parserep(rp
, length
);
758 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
762 #if NFSPROC_ROOT != NFSPROC_NOOP
769 dp
= parserep(rp
, length
);
770 if (dp
!= NULL
&& parsediropres(dp
) != 0)
774 case NFSPROC_READLINK
:
776 dp
= parserep(rp
, length
);
777 if (dp
!= NULL
&& parselinkres(dp
) != 0)
783 dp
= parserep(rp
, length
);
784 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
788 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
789 case NFSPROC_WRITECACHE
:
790 printf(" writecache");
795 dp
= parserep(rp
, length
);
796 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
802 dp
= parserep(rp
, length
);
803 if (dp
!= NULL
&& parsediropres(dp
) != 0)
809 dp
= parserep(rp
, length
);
810 if (dp
!= NULL
&& parsestatus(dp
) != 0)
816 dp
= parserep(rp
, length
);
817 if (dp
!= NULL
&& parsestatus(dp
) != 0)
823 dp
= parserep(rp
, length
);
824 if (dp
!= NULL
&& parsestatus(dp
) != 0)
828 case NFSPROC_SYMLINK
:
830 dp
= parserep(rp
, length
);
831 if (dp
!= NULL
&& parsestatus(dp
) != 0)
837 dp
= parserep(rp
, length
);
838 if (dp
!= NULL
&& parsediropres(dp
) != 0)
844 dp
= parserep(rp
, length
);
845 if (dp
!= NULL
&& parsestatus(dp
) != 0)
849 case NFSPROC_READDIR
:
851 dp
= parserep(rp
, length
);
852 if (dp
!= NULL
&& parserddires(dp
) != 0)
858 dp
= parserep(rp
, length
);
859 if (dp
!= NULL
&& parsestatfs(dp
) != 0)
864 printf(" proc-%u", proc
);
868 fputs(" [|nfs]", stdout
);