Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1990, 1991, 1992 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
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 | |
16 | * written permission. | |
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. | |
20 | */ | |
21 | ||
22 | #ifndef lint | |
23 | static char rcsid[] = | |
78ed81a3 | 24 | "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-nfs.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)"; |
15637ed4 RG |
25 | #endif |
26 | ||
27 | #include <stdio.h> | |
28 | #include <sys/param.h> | |
29 | #include <sys/types.h> | |
30 | #include <sys/socket.h> | |
31 | #include <net/if.h> | |
32 | #include <netinet/in.h> | |
33 | #include <netinet/if_ether.h> | |
34 | #include <netinet/in_systm.h> | |
35 | #include <netinet/ip.h> | |
36 | #include <netinet/ip_var.h> | |
37 | ||
38 | #include <sys/time.h> | |
39 | #include <errno.h> | |
78ed81a3 | 40 | #include <rpc/rpc.h> |
15637ed4 RG |
41 | |
42 | #include <ctype.h> | |
43 | ||
44 | #include "interface.h" | |
45 | /* These must come after interface.h for BSD. */ | |
46 | #if BSD >= 199006 | |
47 | #include <sys/ucred.h> | |
48 | #include <nfs/nfsv2.h> | |
49 | #endif | |
50 | #include <nfs/nfs.h> | |
51 | ||
52 | #include "addrtoname.h" | |
53 | #include "extract.h" | |
54 | ||
55 | static void nfs_printfh(); | |
56 | static void nfs_printfn(); | |
57 | ||
58 | #if BYTE_ORDER == LITTLE_ENDIAN | |
59 | /* | |
60 | * Byte swap an array of n words. | |
61 | * Assume input is word-aligned. | |
62 | * Check that buffer is bounded by "snapend". | |
63 | */ | |
64 | static void | |
65 | bswap(bp, n) | |
66 | register u_long *bp; | |
67 | register u_int n; | |
68 | { | |
69 | register int nwords = ((char *)snapend - (char *)bp) / sizeof(*bp); | |
70 | ||
71 | if (nwords > n) | |
72 | nwords = n; | |
73 | for (; --nwords >= 0; ++bp) | |
74 | *bp = ntohl(*bp); | |
75 | } | |
76 | #endif | |
77 | ||
78 | void | |
79 | nfsreply_print(rp, length, ip) | |
80 | register struct rpc_msg *rp; | |
81 | int length; | |
82 | register struct ip *ip; | |
83 | { | |
84 | #if BYTE_ORDER == LITTLE_ENDIAN | |
85 | bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long)); | |
86 | #endif | |
87 | if (!nflag) | |
88 | (void)printf("%s.nfs > %s.%x: reply %s %d", | |
89 | ipaddr_string(&ip->ip_src), | |
90 | ipaddr_string(&ip->ip_dst), | |
91 | rp->rm_xid, | |
92 | rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR", | |
93 | length); | |
94 | else | |
95 | (void)printf("%s.%x > %s.%x: reply %s %d", | |
96 | ipaddr_string(&ip->ip_src), | |
97 | NFS_PORT, | |
98 | ipaddr_string(&ip->ip_dst), | |
99 | rp->rm_xid, | |
100 | rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR", | |
101 | length); | |
102 | } | |
103 | ||
104 | /* | |
105 | * Return a pointer to the first file handle in the packet. | |
106 | * If the packet was truncated, return 0. | |
107 | */ | |
108 | static u_long * | |
109 | parsereq(rp, length) | |
110 | register struct rpc_msg *rp; | |
111 | register int length; | |
112 | { | |
113 | register u_long *dp = (u_long *)&rp->rm_call.cb_cred; | |
114 | register u_long *ep = (u_long *)snapend; | |
115 | ||
116 | /* | |
117 | * find the start of the req data (if we captured it) | |
118 | * note that dp[1] was already byte swapped by bswap() | |
119 | */ | |
120 | if (dp < ep && dp[1] < length) { | |
121 | dp += (dp[1] + (2*sizeof(u_long) + 3)) / sizeof(u_long); | |
122 | if ((dp < ep) && (dp[1] < length)) { | |
123 | dp += (dp[1] + (2*sizeof(u_long) + 3)) / | |
124 | sizeof(u_long); | |
125 | if (dp < ep) | |
126 | return (dp); | |
127 | } | |
128 | } | |
129 | return (0); | |
130 | } | |
131 | ||
132 | /* | |
133 | * Print out an NFS file handle and return a pointer to following word. | |
134 | * If packet was truncated, return 0. | |
135 | */ | |
136 | static u_long * | |
137 | parsefh(dp) | |
138 | register u_long *dp; | |
139 | { | |
140 | if (dp + 8 <= (u_long *)snapend) { | |
141 | nfs_printfh(dp); | |
142 | return (dp + 8); | |
143 | } | |
144 | return (0); | |
145 | } | |
146 | ||
147 | /* | |
148 | * Print out a file name and return pointer to longword past it. | |
149 | * If packet was truncated, return 0. | |
150 | */ | |
151 | static u_long * | |
152 | parsefn(dp) | |
153 | register u_long *dp; | |
154 | { | |
155 | register int len; | |
156 | register u_char *cp; | |
157 | ||
158 | /* Bail if we don't have the string length */ | |
159 | if ((u_char *)dp > snapend - sizeof(*dp)) | |
160 | return(0); | |
161 | ||
162 | /* Fetch string length; convert to host order */ | |
163 | len = *dp++; | |
164 | NTOHL(len); | |
165 | ||
166 | cp = (u_char *)dp; | |
167 | /* Update long pointer (NFS filenames are padded to long) */ | |
168 | dp += ((len + 3) & ~3) / sizeof(*dp); | |
169 | if ((u_char *)dp > snapend) | |
170 | return (0); | |
171 | nfs_printfn(cp, len); | |
172 | ||
173 | return (dp); | |
174 | } | |
175 | ||
176 | /* | |
177 | * Print out file handle and file name. | |
178 | * Return pointer to longword past file name. | |
179 | * If packet was truncated (or there was some other error), return 0. | |
180 | */ | |
181 | static u_long * | |
182 | parsefhn(dp) | |
183 | register u_long *dp; | |
184 | { | |
185 | dp = parsefh(dp); | |
186 | if (dp == 0) | |
187 | return (0); | |
188 | putchar(' '); | |
189 | return (parsefn(dp)); | |
190 | } | |
191 | ||
192 | void | |
193 | nfsreq_print(rp, length, ip) | |
194 | register struct rpc_msg *rp; | |
195 | int length; | |
196 | register struct ip *ip; | |
197 | { | |
198 | register u_long *dp; | |
199 | register u_char *ep = snapend; | |
200 | #define TCHECK(p, l) if ((u_char *)(p) > ep - l) break | |
201 | ||
202 | #if BYTE_ORDER == LITTLE_ENDIAN | |
203 | bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long)); | |
204 | #endif | |
205 | ||
206 | if (!nflag) | |
207 | (void)printf("%s.%x > %s.nfs: %d", | |
208 | ipaddr_string(&ip->ip_src), | |
209 | rp->rm_xid, | |
210 | ipaddr_string(&ip->ip_dst), | |
211 | length); | |
212 | else | |
213 | (void)printf("%s.%x > %s.%x: %d", | |
214 | ipaddr_string(&ip->ip_src), | |
215 | rp->rm_xid, | |
216 | ipaddr_string(&ip->ip_dst), | |
217 | NFS_PORT, | |
218 | length); | |
219 | ||
220 | switch (rp->rm_call.cb_proc) { | |
221 | #ifdef NFSPROC_NOOP | |
222 | case NFSPROC_NOOP: | |
223 | printf(" nop"); | |
224 | return; | |
225 | #else | |
226 | #define NFSPROC_NOOP -1 | |
227 | #endif | |
228 | case RFS_NULL: | |
229 | printf(" null"); | |
230 | return; | |
231 | ||
232 | case RFS_GETATTR: | |
233 | printf(" getattr"); | |
234 | if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) | |
235 | return; | |
236 | break; | |
237 | ||
238 | case RFS_SETATTR: | |
239 | printf(" setattr"); | |
240 | if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) | |
241 | return; | |
242 | break; | |
243 | ||
244 | #if RFS_ROOT != NFSPROC_NOOP | |
245 | case RFS_ROOT: | |
246 | printf(" root"); | |
247 | break; | |
248 | #endif | |
249 | case RFS_LOOKUP: | |
250 | printf(" lookup"); | |
251 | if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) | |
252 | return; | |
253 | break; | |
254 | ||
255 | case RFS_READLINK: | |
256 | printf(" readlink"); | |
257 | if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) | |
258 | return; | |
259 | break; | |
260 | ||
261 | case RFS_READ: | |
262 | printf(" read"); | |
263 | if ((dp = parsereq(rp, length)) != 0 && | |
264 | (dp = parsefh(dp)) != 0) { | |
265 | TCHECK(dp, 3 * sizeof(*dp)); | |
266 | printf(" %lu (%lu) bytes @ %lu", | |
267 | ntohl(dp[1]), ntohl(dp[2]), ntohl(dp[0])); | |
268 | return; | |
269 | } | |
270 | break; | |
271 | ||
272 | #if RFS_WRITECACHE != NFSPROC_NOOP | |
273 | case RFS_WRITECACHE: | |
274 | printf(" writecache"); | |
275 | if ((dp = parsereq(rp, length)) != 0 && | |
276 | (dp = parsefh(dp)) != 0) { | |
277 | TCHECK(dp, 4 * sizeof(*dp)); | |
278 | printf(" %lu (%lu) bytes @ %lu (%lu)", | |
279 | ntohl(dp[3]), ntohl(dp[2]), | |
280 | ntohl(dp[1]), ntohl(dp[0])); | |
281 | return; | |
282 | } | |
283 | break; | |
284 | #endif | |
285 | case RFS_WRITE: | |
286 | printf(" write"); | |
287 | if ((dp = parsereq(rp, length)) != 0 && | |
288 | (dp = parsefh(dp)) != 0) { | |
289 | TCHECK(dp, 4 * sizeof(*dp)); | |
290 | printf(" %lu (%lu) bytes @ %lu (%lu)", | |
291 | ntohl(dp[3]), ntohl(dp[2]), | |
292 | ntohl(dp[1]), ntohl(dp[0])); | |
293 | return; | |
294 | } | |
295 | break; | |
296 | ||
297 | case RFS_CREATE: | |
298 | printf(" create"); | |
299 | if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) | |
300 | return; | |
301 | break; | |
302 | ||
303 | case RFS_REMOVE: | |
304 | printf(" remove"); | |
305 | if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) | |
306 | return; | |
307 | break; | |
308 | ||
309 | case RFS_RENAME: | |
310 | printf(" rename"); | |
311 | if ((dp = parsereq(rp, length)) != 0 && | |
312 | (dp = parsefhn(dp)) != 0) { | |
313 | fputs(" ->", stdout); | |
314 | if (parsefhn(dp) != 0) | |
315 | return; | |
316 | } | |
317 | break; | |
318 | ||
319 | case RFS_LINK: | |
320 | printf(" link"); | |
321 | if ((dp = parsereq(rp, length)) != 0 && | |
322 | (dp = parsefh(dp)) != 0) { | |
323 | fputs(" ->", stdout); | |
324 | if (parsefhn(dp) != 0) | |
325 | return; | |
326 | } | |
327 | break; | |
328 | ||
329 | case RFS_SYMLINK: | |
330 | printf(" symlink"); | |
331 | if ((dp = parsereq(rp, length)) != 0 && | |
332 | (dp = parsefhn(dp)) != 0) { | |
333 | fputs(" -> ", stdout); | |
334 | if (parsefn(dp) != 0) | |
335 | return; | |
336 | } | |
337 | break; | |
338 | ||
339 | case RFS_MKDIR: | |
340 | printf(" mkdir"); | |
341 | if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) | |
342 | return; | |
343 | break; | |
344 | ||
345 | case RFS_RMDIR: | |
346 | printf(" rmdir"); | |
347 | if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0) | |
348 | return; | |
349 | break; | |
350 | ||
351 | case RFS_READDIR: | |
352 | printf(" readdir"); | |
353 | if ((dp = parsereq(rp, length)) != 0 && | |
354 | (dp = parsefh(dp)) != 0) { | |
355 | TCHECK(dp, 2 * sizeof(*dp)); | |
356 | printf(" %lu bytes @ %lu", ntohl(dp[1]), ntohl(dp[0])); | |
357 | return; | |
358 | } | |
359 | break; | |
360 | ||
361 | case RFS_STATFS: | |
362 | printf(" statfs"); | |
363 | if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0) | |
364 | return; | |
365 | break; | |
366 | ||
367 | default: | |
368 | printf(" proc-%lu", rp->rm_call.cb_proc); | |
369 | return; | |
370 | } | |
371 | fputs(" [|nfs]", stdout); | |
372 | #undef TCHECK | |
373 | } | |
374 | ||
375 | /* | |
376 | * Print out an NFS file handle. | |
377 | * We assume packet was not truncated before the end of the | |
378 | * file handle pointed to by dp. | |
379 | */ | |
380 | static void | |
381 | nfs_printfh(dp) | |
382 | register u_long *dp; | |
383 | { | |
384 | /* | |
385 | * take a wild guess at the structure of file handles. | |
386 | * On sun 3s, there are 2 longs of fsid, a short | |
387 | * len == 8, a long of inode & a long of generation number. | |
388 | * On sun 4s, the len == 10 & there are 2 bytes of | |
389 | * padding immediately following it. | |
390 | */ | |
391 | if (dp[2] == 0xa0000) { | |
392 | if (dp[1]) | |
393 | (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], dp[3]); | |
394 | else | |
395 | (void) printf(" fh %ld.%ld", dp[0], dp[3]); | |
396 | } else if ((dp[2] >> 16) == 8) | |
397 | /* | |
398 | * 'dp' is longword aligned, so we must use the extract | |
399 | * macros below for dp+10 which cannot possibly be aligned. | |
400 | */ | |
401 | if (dp[1]) | |
402 | (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], | |
403 | EXTRACT_LONG((u_char *)dp + 10)); | |
404 | else | |
405 | (void) printf(" fh %ld.%ld", dp[0], | |
406 | EXTRACT_LONG((u_char *)dp + 10)); | |
407 | /* On Ultrix pre-4.0, three longs: fsid, fno, fgen and then zeros */ | |
408 | else if (dp[3] == 0) { | |
409 | (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]), | |
410 | dp[1], dp[2]); | |
411 | } | |
412 | /* | |
413 | * On Ultrix 4.0, | |
414 | * five longs: fsid, fno, fgen, eno, egen and then zeros | |
415 | */ | |
416 | else if (dp[5] == 0) { | |
417 | (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]), | |
418 | dp[1], dp[2]); | |
419 | if (vflag) { | |
420 | /* print additional info */ | |
421 | (void)printf("[%ld.%ld]", dp[3], dp[4]); | |
422 | } | |
423 | } | |
424 | else | |
425 | (void) printf(" fh %lu.%lu.%lu.%lu", | |
426 | dp[0], dp[1], dp[2], dp[3]); | |
427 | } | |
428 | ||
429 | /* | |
430 | * Print out an NFS filename. | |
431 | * Assumes that len bytes from cp are present in packet. | |
432 | */ | |
433 | static void | |
434 | nfs_printfn(cp, len) | |
435 | register u_char *cp; | |
436 | register int len; | |
437 | { | |
438 | register char c; | |
439 | ||
440 | /* Sanity */ | |
441 | if (len >= 64) { | |
442 | fputs("[\">]", stdout); | |
443 | return; | |
444 | } | |
445 | /* Print out the filename */ | |
446 | putchar('"'); | |
447 | while (--len >= 0) { | |
448 | c = toascii(*cp++); | |
449 | if (!isascii(c)) { | |
450 | c = toascii(c); | |
451 | putchar('M'); | |
452 | putchar('-'); | |
453 | } | |
454 | if (!isprint(c)) { | |
455 | c ^= 0x40; /* DEL to ?, others to alpha */ | |
456 | putchar('^'); | |
457 | } | |
458 | putchar(c); | |
459 | } | |
460 | putchar('"'); | |
461 | } |