]>
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.66 1999-10-17 21:37:14 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>
49 #include "interface.h"
50 #include "addrtoname.h"
55 static void nfs_printfh(const u_int32_t
*);
56 static void xid_map_enter(const struct rpc_msg
*, const struct ip
*);
57 static u_int32_t
xid_map_find(const struct rpc_msg
*, const struct ip
*,
59 static void interp_reply(const struct rpc_msg
*, u_int32_t
, u_int
);
61 static int nfserr
; /* true if we error rather than trunc */
64 nfsreply_print(register const u_char
*bp
, u_int length
,
65 register const u_char
*bp2
)
67 register const struct rpc_msg
*rp
;
68 register const struct ip
*ip
;
71 nfserr
= 0; /* assume no error */
72 rp
= (const struct rpc_msg
*)bp
;
73 ip
= (const struct ip
*)bp2
;
76 (void)printf("%s.nfs > %s.%u: reply %s %d",
77 ipaddr_string(&ip
->ip_src
),
78 ipaddr_string(&ip
->ip_dst
),
79 (u_int32_t
)ntohl(rp
->rm_xid
),
80 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
84 (void)printf("%s.%u > %s.%u: reply %s %d",
85 ipaddr_string(&ip
->ip_src
),
87 ipaddr_string(&ip
->ip_dst
),
88 (u_int32_t
)ntohl(rp
->rm_xid
),
89 ntohl(rp
->rm_reply
.rp_stat
) == MSG_ACCEPTED
?
93 if (xid_map_find(rp
, ip
, &proc
))
94 interp_reply(rp
, proc
, length
);
98 * Return a pointer to the first file handle in the packet.
99 * If the packet was truncated, return 0.
101 static const u_int32_t
*
102 parsereq(register const struct rpc_msg
*rp
, register u_int length
)
104 register const u_int32_t
*dp
;
108 * find the start of the req data (if we captured it)
110 dp
= (u_int32_t
*)&rp
->rm_call
.cb_cred
;
114 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
118 dp
+= (len
+ (2 * sizeof(*dp
) + 3)) / sizeof(*dp
);
128 * Print out an NFS file handle and return a pointer to following word.
129 * If packet was truncated, return 0.
131 static const u_int32_t
*
132 parsefh(register const u_int32_t
*dp
)
134 if (dp
+ 8 <= (u_int32_t
*)snapend
) {
142 * Print out a file name and return pointer to 32-bit word past it.
143 * If packet was truncated, return 0.
145 static const u_int32_t
*
146 parsefn(register const u_int32_t
*dp
)
148 register u_int32_t len
;
149 register const u_char
*cp
;
151 /* Bail if we don't have the string length */
152 if ((u_char
*)dp
> snapend
- sizeof(*dp
))
155 /* Fetch string length; convert to host order */
160 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
161 dp
+= ((len
+ 3) & ~3) / sizeof(*dp
);
162 if ((u_char
*)dp
> snapend
)
164 /* XXX seems like we should be checking the length */
166 (void) fn_printn(cp
, len
, NULL
);
173 * Print out file handle and file name.
174 * Return pointer to 32-bit word past file name.
175 * If packet was truncated (or there was some other error), return 0.
177 static const u_int32_t
*
178 parsefhn(register const u_int32_t
*dp
)
184 return (parsefn(dp
));
188 nfsreq_print(register const u_char
*bp
, u_int length
,
189 register const u_char
*bp2
)
191 register const struct rpc_msg
*rp
;
192 register const struct ip
*ip
;
193 register const u_int32_t
*dp
;
195 nfserr
= 0; /* assume no error */
196 rp
= (const struct rpc_msg
*)bp
;
197 ip
= (const struct ip
*)bp2
;
199 (void)printf("%s.%u > %s.nfs: %d",
200 ipaddr_string(&ip
->ip_src
),
201 (u_int32_t
)ntohl(rp
->rm_xid
),
202 ipaddr_string(&ip
->ip_dst
),
205 (void)printf("%s.%u > %s.%u: %d",
206 ipaddr_string(&ip
->ip_src
),
207 (u_int32_t
)ntohl(rp
->rm_xid
),
208 ipaddr_string(&ip
->ip_dst
),
212 xid_map_enter(rp
, ip
); /* record proc number for later on */
214 switch (ntohl(rp
->rm_call
.cb_proc
)) {
220 #define NFSPROC_NOOP -1
226 case NFSPROC_GETATTR
:
228 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
232 case NFSPROC_SETATTR
:
234 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
238 #if NFSPROC_ROOT != NFSPROC_NOOP
245 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
249 case NFSPROC_READLINK
:
251 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
257 if ((dp
= parsereq(rp
, length
)) != NULL
&&
258 (dp
= parsefh(dp
)) != NULL
) {
259 TCHECK2(dp
[0], 3 * sizeof(*dp
));
260 printf(" %u bytes @ %u",
261 (u_int32_t
)ntohl(dp
[1]),
262 (u_int32_t
)ntohl(dp
[0]));
267 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
268 case NFSPROC_WRITECACHE
:
269 printf(" writecache");
270 if ((dp
= parsereq(rp
, length
)) != NULL
&&
271 (dp
= parsefh(dp
)) != NULL
) {
272 TCHECK2(dp
[0], 4 * sizeof(*dp
));
273 printf(" %u (%u) bytes @ %u (%u)",
274 (u_int32_t
)ntohl(dp
[3]),
275 (u_int32_t
)ntohl(dp
[2]),
276 (u_int32_t
)ntohl(dp
[1]),
277 (u_int32_t
)ntohl(dp
[0]));
284 if ((dp
= parsereq(rp
, length
)) != NULL
&&
285 (dp
= parsefh(dp
)) != NULL
) {
286 TCHECK2(dp
[0], 4 * sizeof(*dp
));
287 printf(" %u (%u) bytes @ %u (%u)",
288 (u_int32_t
)ntohl(dp
[3]),
289 (u_int32_t
)ntohl(dp
[2]),
290 (u_int32_t
)ntohl(dp
[1]),
291 (u_int32_t
)ntohl(dp
[0]));
298 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
304 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
310 if ((dp
= parsereq(rp
, length
)) != NULL
&&
311 (dp
= parsefhn(dp
)) != NULL
) {
312 fputs(" ->", stdout
);
313 if (parsefhn(dp
) != NULL
)
320 if ((dp
= parsereq(rp
, length
)) != NULL
&&
321 (dp
= parsefh(dp
)) != NULL
) {
322 fputs(" ->", stdout
);
323 if (parsefhn(dp
) != NULL
)
328 case NFSPROC_SYMLINK
:
330 if ((dp
= parsereq(rp
, length
)) != NULL
&&
331 (dp
= parsefhn(dp
)) != NULL
) {
332 fputs(" -> ", stdout
);
333 if (parsefn(dp
) != NULL
)
340 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
346 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefhn(dp
) != NULL
)
350 case NFSPROC_READDIR
:
352 if ((dp
= parsereq(rp
, length
)) != NULL
&&
353 (dp
= parsefh(dp
)) != NULL
) {
354 TCHECK2(dp
[0], 2 * sizeof(*dp
));
356 * Print the offset as signed, since -1 is common,
357 * but offsets > 2^31 aren't.
359 printf(" %u bytes @ %d",
360 (u_int32_t
)ntohl(dp
[1]),
361 (u_int32_t
)ntohl(dp
[0]));
368 if ((dp
= parsereq(rp
, length
)) != NULL
&& parsefh(dp
) != NULL
)
373 printf(" proc-%u", (u_int32_t
)ntohl(rp
->rm_call
.cb_proc
));
378 fputs(" [|nfs]", stdout
);
382 * Print out an NFS file handle.
383 * We assume packet was not truncated before the end of the
384 * file handle pointed to by dp.
386 * Note: new version (using portable file-handle parser) doesn't produce
387 * generation number. It probably could be made to do that, with some
388 * additional hacking on the parser code.
391 nfs_printfh(register const u_int32_t
*dp
)
395 char *sfsname
= NULL
;
397 Parse_fh((caddr_t
*)dp
, &fsid
, &ino
, NULL
, &sfsname
, 0);
400 /* file system ID is ASCII, not numeric, for this server OS */
401 static char temp
[NFS_FHSIZE
+1];
403 /* Make sure string is null-terminated */
404 strncpy(temp
, sfsname
, NFS_FHSIZE
);
405 /* Remove trailing spaces */
406 sfsname
= strchr(temp
, ' ');
410 (void)printf(" fh %s/%u", temp
, (u_int32_t
)ino
);
412 (void)printf(" fh %u,%u/%u",
413 fsid
.Fsid_dev
.Major
, fsid
.Fsid_dev
.Minor
, (u_int32_t
)ino
);
418 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
419 * us to match up replies with requests and thus to know how to parse
423 struct xid_map_entry
{
424 u_int32_t xid
; /* transaction ID (net order) */
425 struct in_addr client
; /* client IP address (net order) */
426 struct in_addr server
; /* server IP address (net order) */
427 u_int32_t proc
; /* call proc number (host order) */
431 * Map entries are kept in an array that we manage as a ring;
432 * new entries are always added at the tail of the ring. Initially,
433 * all the entries are zero and hence don't match anything.
436 #define XIDMAPSIZE 64
438 struct xid_map_entry xid_map
[XIDMAPSIZE
];
440 int xid_map_next
= 0;
441 int xid_map_hint
= 0;
444 xid_map_enter(const struct rpc_msg
*rp
, const struct ip
*ip
)
446 struct xid_map_entry
*xmep
;
448 xmep
= &xid_map
[xid_map_next
];
450 if (++xid_map_next
>= XIDMAPSIZE
)
453 xmep
->xid
= rp
->rm_xid
;
454 xmep
->client
= ip
->ip_src
;
455 xmep
->server
= ip
->ip_dst
;
456 xmep
->proc
= ntohl(rp
->rm_call
.cb_proc
);
459 /* Returns true and sets proc success or false on failure */
461 xid_map_find(const struct rpc_msg
*rp
, const struct ip
*ip
, u_int32_t
*proc
)
464 struct xid_map_entry
*xmep
;
465 u_int32_t xid
= rp
->rm_xid
;
466 u_int32_t clip
= ip
->ip_dst
.s_addr
;
467 u_int32_t sip
= ip
->ip_src
.s_addr
;
469 /* Start searching from where we last left off */
473 if (xmep
->xid
== xid
&& xmep
->client
.s_addr
== clip
&&
474 xmep
->server
.s_addr
== sip
) {
480 if (++i
>= XIDMAPSIZE
)
482 } while (i
!= xid_map_hint
);
489 * Routines for parsing reply packets
493 * Return a pointer to the beginning of the actual results.
494 * If the packet was truncated, return 0.
496 static const u_int32_t
*
497 parserep(register const struct rpc_msg
*rp
, register u_int length
)
499 register const u_int32_t
*dp
;
501 enum accept_stat astat
;
505 * Here we find the address of the ar_verf credentials.
506 * Originally, this calculation was
507 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
508 * On the wire, the rp_acpt field starts immediately after
509 * the (32 bit) rp_stat field. However, rp_acpt (which is a
510 * "struct accepted_reply") contains a "struct opaque_auth",
511 * whose internal representation contains a pointer, so on a
512 * 64-bit machine the compiler inserts 32 bits of padding
513 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
514 * the internal representation to parse the on-the-wire
515 * representation. Instead, we skip past the rp_stat field,
516 * which is an "enum" and so occupies one 32-bit word.
518 dp
= ((const u_int32_t
*)&rp
->rm_reply
) + 1;
524 * skip past the ar_verf credentials.
526 dp
+= (len
+ (2*sizeof(u_int32_t
) + 3)) / sizeof(u_int32_t
);
530 * now we can check the ar_stat field
532 astat
= ntohl(*(enum accept_stat
*)dp
);
539 printf(" PROG_UNAVAIL");
540 nfserr
= 1; /* suppress trunc string */
544 printf(" PROG_MISMATCH");
545 nfserr
= 1; /* suppress trunc string */
549 printf(" PROC_UNAVAIL");
550 nfserr
= 1; /* suppress trunc string */
554 printf(" GARBAGE_ARGS");
555 nfserr
= 1; /* suppress trunc string */
559 printf(" SYSTEM_ERR");
560 nfserr
= 1; /* suppress trunc string */
564 printf(" ar_stat %d", astat
);
565 nfserr
= 1; /* suppress trunc string */
568 /* successful return */
569 if ((sizeof(astat
) + ((u_char
*)dp
)) < snapend
)
570 return ((u_int32_t
*) (sizeof(astat
) + ((char *)dp
)));
576 static const u_int32_t
*
577 parsestatus(const u_int32_t
*dp
)
582 errnum
= ntohl(dp
[0]);
585 printf(" ERROR: %s", pcap_strerror(errnum
));
586 nfserr
= 1; /* suppress trunc string */
594 static struct tok type2str
[] = {
604 static const u_int32_t
*
605 parsefattr(const u_int32_t
*dp
, int verbose
)
607 const struct nfsv2_fattr
*fap
;
609 fap
= (const struct nfsv2_fattr
*)dp
;
611 TCHECK(fap
->fa_nfssize
);
612 printf(" %s %o ids %u/%u sz %u ",
613 tok2str(type2str
, "unk-ft %d ",
614 (u_int32_t
)ntohl(fap
->fa_type
)),
615 (u_int32_t
)ntohl(fap
->fa_mode
),
616 (u_int32_t
)ntohl(fap
->fa_uid
),
617 (u_int32_t
)ntohl(fap
->fa_gid
),
618 (u_int32_t
)ntohl(fap
->fa_nfssize
));
620 /* print lots more stuff */
622 TCHECK(fap
->fa_nfsfileid
);
623 printf("nlink %u rdev %x fsid %x nodeid %x a/m/ctime ",
624 (u_int32_t
)ntohl(fap
->fa_nlink
),
625 (u_int32_t
)ntohl(fap
->fa_nfsrdev
),
626 (u_int32_t
)ntohl(fap
->fa_nfsfsid
),
627 (u_int32_t
)ntohl(fap
->fa_nfsfileid
));
628 TCHECK(fap
->fa_nfsatime
);
630 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_sec
),
631 (u_int32_t
)ntohl(fap
->fa_nfsatime
.nfs_usec
));
632 TCHECK(fap
->fa_nfsmtime
);
634 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_sec
),
635 (u_int32_t
)ntohl(fap
->fa_nfsmtime
.nfs_usec
));
636 TCHECK(fap
->fa_nfsctime
);
638 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_sec
),
639 (u_int32_t
)ntohl(fap
->fa_nfsctime
.nfs_usec
));
641 return ((const u_int32_t
*)&fap
[1]);
647 parseattrstat(const u_int32_t
*dp
, int verbose
)
650 dp
= parsestatus(dp
);
654 return (parsefattr(dp
, verbose
) != NULL
);
658 parsediropres(const u_int32_t
*dp
)
661 dp
= parsestatus(dp
);
669 return (parsefattr(dp
, vflag
) != NULL
);
673 parselinkres(const u_int32_t
*dp
)
675 dp
= parsestatus(dp
);
680 return (parsefn(dp
) != NULL
);
684 parsestatfs(const u_int32_t
*dp
)
686 const struct nfsv2_statfs
*sfsp
;
688 dp
= parsestatus(dp
);
693 sfsp
= (const struct nfsv2_statfs
*)dp
;
694 TCHECK(sfsp
->sf_bavail
);
695 printf(" tsize %u bsize %u blocks %u bfree %u bavail %u",
696 (u_int32_t
)ntohl(sfsp
->sf_tsize
),
697 (u_int32_t
)ntohl(sfsp
->sf_bsize
),
698 (u_int32_t
)ntohl(sfsp
->sf_blocks
),
699 (u_int32_t
)ntohl(sfsp
->sf_bfree
),
700 (u_int32_t
)ntohl(sfsp
->sf_bavail
));
709 parserddires(const u_int32_t
*dp
)
711 dp
= parsestatus(dp
);
716 printf(" offset %x", (u_int32_t
)ntohl(dp
[0]));
718 printf(" size %u", (u_int32_t
)ntohl(dp
[1]));
730 interp_reply(const struct rpc_msg
*rp
, u_int32_t proc
, u_int length
)
732 register const u_int32_t
*dp
;
741 #define NFSPROC_NOOP -1
747 case NFSPROC_GETATTR
:
749 dp
= parserep(rp
, length
);
750 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
754 case NFSPROC_SETATTR
:
756 dp
= parserep(rp
, length
);
757 if (dp
!= NULL
&& parseattrstat(dp
, !qflag
) != 0)
761 #if NFSPROC_ROOT != NFSPROC_NOOP
768 dp
= parserep(rp
, length
);
769 if (dp
!= NULL
&& parsediropres(dp
) != 0)
773 case NFSPROC_READLINK
:
775 dp
= parserep(rp
, length
);
776 if (dp
!= NULL
&& parselinkres(dp
) != 0)
782 dp
= parserep(rp
, length
);
783 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
787 #if NFSPROC_WRITECACHE != NFSPROC_NOOP
788 case NFSPROC_WRITECACHE
:
789 printf(" writecache");
794 dp
= parserep(rp
, length
);
795 if (dp
!= NULL
&& parseattrstat(dp
, vflag
) != 0)
801 dp
= parserep(rp
, length
);
802 if (dp
!= NULL
&& parsediropres(dp
) != 0)
808 dp
= parserep(rp
, length
);
809 if (dp
!= NULL
&& parsestatus(dp
) != 0)
815 dp
= parserep(rp
, length
);
816 if (dp
!= NULL
&& parsestatus(dp
) != 0)
822 dp
= parserep(rp
, length
);
823 if (dp
!= NULL
&& parsestatus(dp
) != 0)
827 case NFSPROC_SYMLINK
:
829 dp
= parserep(rp
, length
);
830 if (dp
!= NULL
&& parsestatus(dp
) != 0)
836 dp
= parserep(rp
, length
);
837 if (dp
!= NULL
&& parsediropres(dp
) != 0)
843 dp
= parserep(rp
, length
);
844 if (dp
!= NULL
&& parsestatus(dp
) != 0)
848 case NFSPROC_READDIR
:
850 dp
= parserep(rp
, length
);
851 if (dp
!= NULL
&& parserddires(dp
) != 0)
857 dp
= parserep(rp
, length
);
858 if (dp
!= NULL
&& parsestatfs(dp
) != 0)
863 printf(" proc-%u", proc
);
867 fputs(" [|nfs]", stdout
);