1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. 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 #include <sys/cdefs.h> 23 #ifndef lint 24 __RCSID("$NetBSD: print-nfs.c,v 1.5 2014/11/20 03:05:03 christos Exp $"); 25 #endif 26 27 #define NETDISSECT_REWORKED 28 #ifdef HAVE_CONFIG_H 29 #include "config.h" 30 #endif 31 32 #include <tcpdump-stdinc.h> 33 34 #include <stdio.h> 35 #include <string.h> 36 37 #include "interface.h" 38 #include "addrtoname.h" 39 #include "extract.h" 40 41 #include "nfs.h" 42 #include "nfsfh.h" 43 44 #include "ip.h" 45 #ifdef INET6 46 #include "ip6.h" 47 #endif 48 #include "rpc_auth.h" 49 #include "rpc_msg.h" 50 51 static const char tstr[] = " [|nfs]"; 52 53 static void nfs_printfh(netdissect_options *, const uint32_t *, const u_int); 54 static int xid_map_enter(netdissect_options *, const struct sunrpc_msg *, const u_char *); 55 static int xid_map_find(const struct sunrpc_msg *, const u_char *, 56 uint32_t *, uint32_t *); 57 static void interp_reply(netdissect_options *, const struct sunrpc_msg *, uint32_t, uint32_t, int); 58 static const uint32_t *parse_post_op_attr(netdissect_options *, const uint32_t *, int); 59 60 /* 61 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 62 */ 63 uint32_t nfsv3_procid[NFS_NPROCS] = { 64 NFSPROC_NULL, 65 NFSPROC_GETATTR, 66 NFSPROC_SETATTR, 67 NFSPROC_NOOP, 68 NFSPROC_LOOKUP, 69 NFSPROC_READLINK, 70 NFSPROC_READ, 71 NFSPROC_NOOP, 72 NFSPROC_WRITE, 73 NFSPROC_CREATE, 74 NFSPROC_REMOVE, 75 NFSPROC_RENAME, 76 NFSPROC_LINK, 77 NFSPROC_SYMLINK, 78 NFSPROC_MKDIR, 79 NFSPROC_RMDIR, 80 NFSPROC_READDIR, 81 NFSPROC_FSSTAT, 82 NFSPROC_NOOP, 83 NFSPROC_NOOP, 84 NFSPROC_NOOP, 85 NFSPROC_NOOP, 86 NFSPROC_NOOP, 87 NFSPROC_NOOP, 88 NFSPROC_NOOP, 89 NFSPROC_NOOP 90 }; 91 92 static const struct tok nfsproc_str[] = { 93 { NFSPROC_NOOP, "nop" }, 94 { NFSPROC_NULL, "null" }, 95 { NFSPROC_GETATTR, "getattr" }, 96 { NFSPROC_SETATTR, "setattr" }, 97 { NFSPROC_LOOKUP, "lookup" }, 98 { NFSPROC_ACCESS, "access" }, 99 { NFSPROC_READLINK, "readlink" }, 100 { NFSPROC_READ, "read" }, 101 { NFSPROC_WRITE, "write" }, 102 { NFSPROC_CREATE, "create" }, 103 { NFSPROC_MKDIR, "mkdir" }, 104 { NFSPROC_SYMLINK, "symlink" }, 105 { NFSPROC_MKNOD, "mknod" }, 106 { NFSPROC_REMOVE, "remove" }, 107 { NFSPROC_RMDIR, "rmdir" }, 108 { NFSPROC_RENAME, "rename" }, 109 { NFSPROC_LINK, "link" }, 110 { NFSPROC_READDIR, "readdir" }, 111 { NFSPROC_READDIRPLUS, "readdirplus" }, 112 { NFSPROC_FSSTAT, "fsstat" }, 113 { NFSPROC_FSINFO, "fsinfo" }, 114 { NFSPROC_PATHCONF, "pathconf" }, 115 { NFSPROC_COMMIT, "commit" }, 116 { 0, NULL } 117 }; 118 119 /* 120 * NFS V2 and V3 status values. 121 * 122 * Some of these come from the RFCs for NFS V2 and V3, with the message 123 * strings taken from the FreeBSD C library "errlst.c". 124 * 125 * Others are errors that are not in the RFC but that I suspect some 126 * NFS servers could return; the values are FreeBSD errno values, as 127 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS 128 * was primarily BSD-derived. 129 */ 130 static const struct tok status2str[] = { 131 { 1, "Operation not permitted" }, /* EPERM */ 132 { 2, "No such file or directory" }, /* ENOENT */ 133 { 5, "Input/output error" }, /* EIO */ 134 { 6, "Device not configured" }, /* ENXIO */ 135 { 11, "Resource deadlock avoided" }, /* EDEADLK */ 136 { 12, "Cannot allocate memory" }, /* ENOMEM */ 137 { 13, "Permission denied" }, /* EACCES */ 138 { 17, "File exists" }, /* EEXIST */ 139 { 18, "Cross-device link" }, /* EXDEV */ 140 { 19, "Operation not supported by device" }, /* ENODEV */ 141 { 20, "Not a directory" }, /* ENOTDIR */ 142 { 21, "Is a directory" }, /* EISDIR */ 143 { 22, "Invalid argument" }, /* EINVAL */ 144 { 26, "Text file busy" }, /* ETXTBSY */ 145 { 27, "File too large" }, /* EFBIG */ 146 { 28, "No space left on device" }, /* ENOSPC */ 147 { 30, "Read-only file system" }, /* EROFS */ 148 { 31, "Too many links" }, /* EMLINK */ 149 { 45, "Operation not supported" }, /* EOPNOTSUPP */ 150 { 62, "Too many levels of symbolic links" }, /* ELOOP */ 151 { 63, "File name too long" }, /* ENAMETOOLONG */ 152 { 66, "Directory not empty" }, /* ENOTEMPTY */ 153 { 69, "Disc quota exceeded" }, /* EDQUOT */ 154 { 70, "Stale NFS file handle" }, /* ESTALE */ 155 { 71, "Too many levels of remote in path" }, /* EREMOTE */ 156 { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */ 157 { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */ 158 { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */ 159 { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */ 160 { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */ 161 { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */ 162 { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */ 163 { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */ 164 { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */ 165 { 0, NULL } 166 }; 167 168 static const struct tok nfsv3_writemodes[] = { 169 { 0, "unstable" }, 170 { 1, "datasync" }, 171 { 2, "filesync" }, 172 { 0, NULL } 173 }; 174 175 static const struct tok type2str[] = { 176 { NFNON, "NON" }, 177 { NFREG, "REG" }, 178 { NFDIR, "DIR" }, 179 { NFBLK, "BLK" }, 180 { NFCHR, "CHR" }, 181 { NFLNK, "LNK" }, 182 { NFFIFO, "FIFO" }, 183 { 0, NULL } 184 }; 185 186 static const struct tok sunrpc_auth_str[] = { 187 { SUNRPC_AUTH_OK, "OK" }, 188 { SUNRPC_AUTH_BADCRED, "Bogus Credentials (seal broken)" }, 189 { SUNRPC_AUTH_REJECTEDCRED, "Rejected Credentials (client should begin new session)" }, 190 { SUNRPC_AUTH_BADVERF, "Bogus Verifier (seal broken)" }, 191 { SUNRPC_AUTH_REJECTEDVERF, "Verifier expired or was replayed" }, 192 { SUNRPC_AUTH_TOOWEAK, "Credentials are too weak" }, 193 { SUNRPC_AUTH_INVALIDRESP, "Bogus response verifier" }, 194 { SUNRPC_AUTH_FAILED, "Unknown failure" }, 195 { 0, NULL } 196 }; 197 198 static const struct tok sunrpc_str[] = { 199 { SUNRPC_PROG_UNAVAIL, "PROG_UNAVAIL" }, 200 { SUNRPC_PROG_MISMATCH, "PROG_MISMATCH" }, 201 { SUNRPC_PROC_UNAVAIL, "PROC_UNAVAIL" }, 202 { SUNRPC_GARBAGE_ARGS, "GARBAGE_ARGS" }, 203 { SUNRPC_SYSTEM_ERR, "SYSTEM_ERR" }, 204 { 0, NULL } 205 }; 206 207 static void 208 print_nfsaddr(netdissect_options *ndo, 209 const u_char *bp, const char *s, const char *d) 210 { 211 struct ip *ip; 212 #ifdef INET6 213 struct ip6_hdr *ip6; 214 char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN]; 215 #else 216 #ifndef INET_ADDRSTRLEN 217 #define INET_ADDRSTRLEN 16 218 #endif 219 char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN]; 220 #endif 221 222 srcaddr[0] = dstaddr[0] = '\0'; 223 switch (IP_V((struct ip *)bp)) { 224 case 4: 225 ip = (struct ip *)bp; 226 strlcpy(srcaddr, ipaddr_string(ndo, &ip->ip_src), sizeof(srcaddr)); 227 strlcpy(dstaddr, ipaddr_string(ndo, &ip->ip_dst), sizeof(dstaddr)); 228 break; 229 #ifdef INET6 230 case 6: 231 ip6 = (struct ip6_hdr *)bp; 232 strlcpy(srcaddr, ip6addr_string(ndo, &ip6->ip6_src), 233 sizeof(srcaddr)); 234 strlcpy(dstaddr, ip6addr_string(ndo, &ip6->ip6_dst), 235 sizeof(dstaddr)); 236 break; 237 #endif 238 default: 239 strlcpy(srcaddr, "?", sizeof(srcaddr)); 240 strlcpy(dstaddr, "?", sizeof(dstaddr)); 241 break; 242 } 243 244 ND_PRINT((ndo, "%s.%s > %s.%s: ", srcaddr, s, dstaddr, d)); 245 } 246 247 static const uint32_t * 248 parse_sattr3(netdissect_options *ndo, 249 const uint32_t *dp, struct nfsv3_sattr *sa3) 250 { 251 ND_TCHECK(dp[0]); 252 sa3->sa_modeset = EXTRACT_32BITS(dp); 253 dp++; 254 if (sa3->sa_modeset) { 255 ND_TCHECK(dp[0]); 256 sa3->sa_mode = EXTRACT_32BITS(dp); 257 dp++; 258 } 259 260 ND_TCHECK(dp[0]); 261 sa3->sa_uidset = EXTRACT_32BITS(dp); 262 dp++; 263 if (sa3->sa_uidset) { 264 ND_TCHECK(dp[0]); 265 sa3->sa_uid = EXTRACT_32BITS(dp); 266 dp++; 267 } 268 269 ND_TCHECK(dp[0]); 270 sa3->sa_gidset = EXTRACT_32BITS(dp); 271 dp++; 272 if (sa3->sa_gidset) { 273 ND_TCHECK(dp[0]); 274 sa3->sa_gid = EXTRACT_32BITS(dp); 275 dp++; 276 } 277 278 ND_TCHECK(dp[0]); 279 sa3->sa_sizeset = EXTRACT_32BITS(dp); 280 dp++; 281 if (sa3->sa_sizeset) { 282 ND_TCHECK(dp[0]); 283 sa3->sa_size = EXTRACT_32BITS(dp); 284 dp++; 285 } 286 287 ND_TCHECK(dp[0]); 288 sa3->sa_atimetype = EXTRACT_32BITS(dp); 289 dp++; 290 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) { 291 ND_TCHECK(dp[1]); 292 sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp); 293 dp++; 294 sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp); 295 dp++; 296 } 297 298 ND_TCHECK(dp[0]); 299 sa3->sa_mtimetype = EXTRACT_32BITS(dp); 300 dp++; 301 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) { 302 ND_TCHECK(dp[1]); 303 sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp); 304 dp++; 305 sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp); 306 dp++; 307 } 308 309 return dp; 310 trunc: 311 return NULL; 312 } 313 314 static int nfserr; /* true if we error rather than trunc */ 315 316 static void 317 print_sattr3(netdissect_options *ndo, 318 const struct nfsv3_sattr *sa3, int verbose) 319 { 320 if (sa3->sa_modeset) 321 ND_PRINT((ndo, " mode %o", sa3->sa_mode)); 322 if (sa3->sa_uidset) 323 ND_PRINT((ndo, " uid %u", sa3->sa_uid)); 324 if (sa3->sa_gidset) 325 ND_PRINT((ndo, " gid %u", sa3->sa_gid)); 326 if (verbose > 1) { 327 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) 328 ND_PRINT((ndo, " atime %u.%06u", sa3->sa_atime.nfsv3_sec, 329 sa3->sa_atime.nfsv3_nsec)); 330 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) 331 ND_PRINT((ndo, " mtime %u.%06u", sa3->sa_mtime.nfsv3_sec, 332 sa3->sa_mtime.nfsv3_nsec)); 333 } 334 } 335 336 void 337 nfsreply_print(netdissect_options *ndo, 338 register const u_char *bp, u_int length, 339 register const u_char *bp2) 340 { 341 register const struct sunrpc_msg *rp; 342 char srcid[20], dstid[20]; /*fits 32bit*/ 343 344 nfserr = 0; /* assume no error */ 345 rp = (const struct sunrpc_msg *)bp; 346 347 ND_TCHECK(rp->rm_xid); 348 if (!ndo->ndo_nflag) { 349 strlcpy(srcid, "nfs", sizeof(srcid)); 350 snprintf(dstid, sizeof(dstid), "%u", 351 EXTRACT_32BITS(&rp->rm_xid)); 352 } else { 353 snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); 354 snprintf(dstid, sizeof(dstid), "%u", 355 EXTRACT_32BITS(&rp->rm_xid)); 356 } 357 print_nfsaddr(ndo, bp2, srcid, dstid); 358 359 nfsreply_print_noaddr(ndo, bp, length, bp2); 360 return; 361 362 trunc: 363 if (!nfserr) 364 ND_PRINT((ndo, "%s", tstr)); 365 } 366 367 void 368 nfsreply_print_noaddr(netdissect_options *ndo, 369 register const u_char *bp, u_int length, 370 register const u_char *bp2) 371 { 372 register const struct sunrpc_msg *rp; 373 uint32_t proc, vers, reply_stat; 374 enum sunrpc_reject_stat rstat; 375 uint32_t rlow; 376 uint32_t rhigh; 377 enum sunrpc_auth_stat rwhy; 378 379 nfserr = 0; /* assume no error */ 380 rp = (const struct sunrpc_msg *)bp; 381 382 ND_TCHECK(rp->rm_reply.rp_stat); 383 reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat); 384 switch (reply_stat) { 385 386 case SUNRPC_MSG_ACCEPTED: 387 ND_PRINT((ndo, "reply ok %u", length)); 388 if (xid_map_find(rp, bp2, &proc, &vers) >= 0) 389 interp_reply(ndo, rp, proc, vers, length); 390 break; 391 392 case SUNRPC_MSG_DENIED: 393 ND_PRINT((ndo, "reply ERR %u: ", length)); 394 ND_TCHECK(rp->rm_reply.rp_reject.rj_stat); 395 rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat); 396 switch (rstat) { 397 398 case SUNRPC_RPC_MISMATCH: 399 ND_TCHECK(rp->rm_reply.rp_reject.rj_vers.high); 400 rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low); 401 rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high); 402 ND_PRINT((ndo, "RPC Version mismatch (%u-%u)", rlow, rhigh)); 403 break; 404 405 case SUNRPC_AUTH_ERROR: 406 ND_TCHECK(rp->rm_reply.rp_reject.rj_why); 407 rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why); 408 ND_PRINT((ndo, "Auth %s", tok2str(sunrpc_auth_str, "Invalid failure code %u", rwhy))); 409 break; 410 411 default: 412 ND_PRINT((ndo, "Unknown reason for rejecting rpc message %u", (unsigned int)rstat)); 413 break; 414 } 415 break; 416 417 default: 418 ND_PRINT((ndo, "reply Unknown rpc response code=%u %u", reply_stat, length)); 419 break; 420 } 421 return; 422 423 trunc: 424 if (!nfserr) 425 ND_PRINT((ndo, "%s", tstr)); 426 } 427 428 /* 429 * Return a pointer to the first file handle in the packet. 430 * If the packet was truncated, return 0. 431 */ 432 static const uint32_t * 433 parsereq(netdissect_options *ndo, 434 register const struct sunrpc_msg *rp, register u_int length) 435 { 436 register const uint32_t *dp; 437 register u_int len; 438 439 /* 440 * find the start of the req data (if we captured it) 441 */ 442 dp = (uint32_t *)&rp->rm_call.cb_cred; 443 ND_TCHECK(dp[1]); 444 len = EXTRACT_32BITS(&dp[1]); 445 if (len < length) { 446 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 447 ND_TCHECK(dp[1]); 448 len = EXTRACT_32BITS(&dp[1]); 449 if (len < length) { 450 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 451 ND_TCHECK2(dp[0], 0); 452 return (dp); 453 } 454 } 455 trunc: 456 return (NULL); 457 } 458 459 /* 460 * Print out an NFS file handle and return a pointer to following word. 461 * If packet was truncated, return 0. 462 */ 463 static const uint32_t * 464 parsefh(netdissect_options *ndo, 465 register const uint32_t *dp, int v3) 466 { 467 u_int len; 468 469 if (v3) { 470 ND_TCHECK(dp[0]); 471 len = EXTRACT_32BITS(dp) / 4; 472 dp++; 473 } else 474 len = NFSX_V2FH / 4; 475 476 if (ND_TTEST2(*dp, len * sizeof(*dp))) { 477 nfs_printfh(ndo, dp, len); 478 return (dp + len); 479 } 480 trunc: 481 return (NULL); 482 } 483 484 /* 485 * Print out a file name and return pointer to 32-bit word past it. 486 * If packet was truncated, return 0. 487 */ 488 static const uint32_t * 489 parsefn(netdissect_options *ndo, 490 register const uint32_t *dp) 491 { 492 register uint32_t len; 493 register const u_char *cp; 494 495 /* Bail if we don't have the string length */ 496 ND_TCHECK(*dp); 497 498 /* Fetch string length; convert to host order */ 499 len = *dp++; 500 NTOHL(len); 501 502 ND_TCHECK2(*dp, ((len + 3) & ~3)); 503 504 cp = (u_char *)dp; 505 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 506 dp += ((len + 3) & ~3) / sizeof(*dp); 507 ND_PRINT((ndo, "\"")); 508 if (fn_printn(ndo, cp, len, ndo->ndo_snapend)) { 509 ND_PRINT((ndo, "\"")); 510 goto trunc; 511 } 512 ND_PRINT((ndo, "\"")); 513 514 return (dp); 515 trunc: 516 return NULL; 517 } 518 519 /* 520 * Print out file handle and file name. 521 * Return pointer to 32-bit word past file name. 522 * If packet was truncated (or there was some other error), return 0. 523 */ 524 static const uint32_t * 525 parsefhn(netdissect_options *ndo, 526 register const uint32_t *dp, int v3) 527 { 528 dp = parsefh(ndo, dp, v3); 529 if (dp == NULL) 530 return (NULL); 531 ND_PRINT((ndo, " ")); 532 return (parsefn(ndo, dp)); 533 } 534 535 void 536 nfsreq_print_noaddr(netdissect_options *ndo, 537 register const u_char *bp, u_int length, 538 register const u_char *bp2) 539 { 540 register const struct sunrpc_msg *rp; 541 register const uint32_t *dp; 542 nfs_type type; 543 int v3; 544 uint32_t proc; 545 uint32_t access_flags; 546 struct nfsv3_sattr sa3; 547 548 ND_PRINT((ndo, "%d", length)); 549 nfserr = 0; /* assume no error */ 550 rp = (const struct sunrpc_msg *)bp; 551 552 if (!xid_map_enter(ndo, rp, bp2)) /* record proc number for later on */ 553 goto trunc; 554 555 v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3); 556 proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 557 558 if (!v3 && proc < NFS_NPROCS) 559 proc = nfsv3_procid[proc]; 560 561 ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc))); 562 switch (proc) { 563 564 case NFSPROC_GETATTR: 565 case NFSPROC_SETATTR: 566 case NFSPROC_READLINK: 567 case NFSPROC_FSSTAT: 568 case NFSPROC_FSINFO: 569 case NFSPROC_PATHCONF: 570 if ((dp = parsereq(ndo, rp, length)) != NULL && 571 parsefh(ndo, dp, v3) != NULL) 572 return; 573 break; 574 575 case NFSPROC_LOOKUP: 576 case NFSPROC_CREATE: 577 case NFSPROC_MKDIR: 578 case NFSPROC_REMOVE: 579 case NFSPROC_RMDIR: 580 if ((dp = parsereq(ndo, rp, length)) != NULL && 581 parsefhn(ndo, dp, v3) != NULL) 582 return; 583 break; 584 585 case NFSPROC_ACCESS: 586 if ((dp = parsereq(ndo, rp, length)) != NULL && 587 (dp = parsefh(ndo, dp, v3)) != NULL) { 588 ND_TCHECK(dp[0]); 589 access_flags = EXTRACT_32BITS(&dp[0]); 590 if (access_flags & ~NFSV3ACCESS_FULL) { 591 /* NFSV3ACCESS definitions aren't up to date */ 592 ND_PRINT((ndo, " %04x", access_flags)); 593 } else if ((access_flags & NFSV3ACCESS_FULL) == NFSV3ACCESS_FULL) { 594 ND_PRINT((ndo, " NFS_ACCESS_FULL")); 595 } else { 596 char separator = ' '; 597 if (access_flags & NFSV3ACCESS_READ) { 598 ND_PRINT((ndo, " NFS_ACCESS_READ")); 599 separator = '|'; 600 } 601 if (access_flags & NFSV3ACCESS_LOOKUP) { 602 ND_PRINT((ndo, "%cNFS_ACCESS_LOOKUP", separator)); 603 separator = '|'; 604 } 605 if (access_flags & NFSV3ACCESS_MODIFY) { 606 ND_PRINT((ndo, "%cNFS_ACCESS_MODIFY", separator)); 607 separator = '|'; 608 } 609 if (access_flags & NFSV3ACCESS_EXTEND) { 610 ND_PRINT((ndo, "%cNFS_ACCESS_EXTEND", separator)); 611 separator = '|'; 612 } 613 if (access_flags & NFSV3ACCESS_DELETE) { 614 ND_PRINT((ndo, "%cNFS_ACCESS_DELETE", separator)); 615 separator = '|'; 616 } 617 if (access_flags & NFSV3ACCESS_EXECUTE) 618 ND_PRINT((ndo, "%cNFS_ACCESS_EXECUTE", separator)); 619 } 620 return; 621 } 622 break; 623 624 case NFSPROC_READ: 625 if ((dp = parsereq(ndo, rp, length)) != NULL && 626 (dp = parsefh(ndo, dp, v3)) != NULL) { 627 if (v3) { 628 ND_TCHECK(dp[2]); 629 ND_PRINT((ndo, " %u bytes @ %" PRIu64, 630 EXTRACT_32BITS(&dp[2]), 631 EXTRACT_64BITS(&dp[0]))); 632 } else { 633 ND_TCHECK(dp[1]); 634 ND_PRINT((ndo, " %u bytes @ %u", 635 EXTRACT_32BITS(&dp[1]), 636 EXTRACT_32BITS(&dp[0]))); 637 } 638 return; 639 } 640 break; 641 642 case NFSPROC_WRITE: 643 if ((dp = parsereq(ndo, rp, length)) != NULL && 644 (dp = parsefh(ndo, dp, v3)) != NULL) { 645 if (v3) { 646 ND_TCHECK(dp[2]); 647 ND_PRINT((ndo, " %u (%u) bytes @ %" PRIu64, 648 EXTRACT_32BITS(&dp[4]), 649 EXTRACT_32BITS(&dp[2]), 650 EXTRACT_64BITS(&dp[0]))); 651 if (ndo->ndo_vflag) { 652 dp += 3; 653 ND_TCHECK(dp[0]); 654 ND_PRINT((ndo, " <%s>", 655 tok2str(nfsv3_writemodes, 656 NULL, EXTRACT_32BITS(dp)))); 657 } 658 } else { 659 ND_TCHECK(dp[3]); 660 ND_PRINT((ndo, " %u (%u) bytes @ %u (%u)", 661 EXTRACT_32BITS(&dp[3]), 662 EXTRACT_32BITS(&dp[2]), 663 EXTRACT_32BITS(&dp[1]), 664 EXTRACT_32BITS(&dp[0]))); 665 } 666 return; 667 } 668 break; 669 670 case NFSPROC_SYMLINK: 671 if ((dp = parsereq(ndo, rp, length)) != 0 && 672 (dp = parsefhn(ndo, dp, v3)) != 0) { 673 ND_PRINT((ndo, " ->")); 674 if (v3 && (dp = parse_sattr3(ndo, dp, &sa3)) == 0) 675 break; 676 if (parsefn(ndo, dp) == 0) 677 break; 678 if (v3 && ndo->ndo_vflag) 679 print_sattr3(ndo, &sa3, ndo->ndo_vflag); 680 return; 681 } 682 break; 683 684 case NFSPROC_MKNOD: 685 if ((dp = parsereq(ndo, rp, length)) != 0 && 686 (dp = parsefhn(ndo, dp, v3)) != 0) { 687 ND_TCHECK(*dp); 688 type = (nfs_type)EXTRACT_32BITS(dp); 689 dp++; 690 if ((dp = parse_sattr3(ndo, dp, &sa3)) == 0) 691 break; 692 ND_PRINT((ndo, " %s", tok2str(type2str, "unk-ft %d", type))); 693 if (ndo->ndo_vflag && (type == NFCHR || type == NFBLK)) { 694 ND_TCHECK(dp[1]); 695 ND_PRINT((ndo, " %u/%u", 696 EXTRACT_32BITS(&dp[0]), 697 EXTRACT_32BITS(&dp[1]))); 698 dp += 2; 699 } 700 if (ndo->ndo_vflag) 701 print_sattr3(ndo, &sa3, ndo->ndo_vflag); 702 return; 703 } 704 break; 705 706 case NFSPROC_RENAME: 707 if ((dp = parsereq(ndo, rp, length)) != NULL && 708 (dp = parsefhn(ndo, dp, v3)) != NULL) { 709 ND_PRINT((ndo, " ->")); 710 if (parsefhn(ndo, dp, v3) != NULL) 711 return; 712 } 713 break; 714 715 case NFSPROC_LINK: 716 if ((dp = parsereq(ndo, rp, length)) != NULL && 717 (dp = parsefh(ndo, dp, v3)) != NULL) { 718 ND_PRINT((ndo, " ->")); 719 if (parsefhn(ndo, dp, v3) != NULL) 720 return; 721 } 722 break; 723 724 case NFSPROC_READDIR: 725 if ((dp = parsereq(ndo, rp, length)) != NULL && 726 (dp = parsefh(ndo, dp, v3)) != NULL) { 727 if (v3) { 728 ND_TCHECK(dp[4]); 729 /* 730 * We shouldn't really try to interpret the 731 * offset cookie here. 732 */ 733 ND_PRINT((ndo, " %u bytes @ %" PRId64, 734 EXTRACT_32BITS(&dp[4]), 735 EXTRACT_64BITS(&dp[0]))); 736 if (ndo->ndo_vflag) 737 ND_PRINT((ndo, " verf %08x%08x", dp[2], dp[3])); 738 } else { 739 ND_TCHECK(dp[1]); 740 /* 741 * Print the offset as signed, since -1 is 742 * common, but offsets > 2^31 aren't. 743 */ 744 ND_PRINT((ndo, " %u bytes @ %d", 745 EXTRACT_32BITS(&dp[1]), 746 EXTRACT_32BITS(&dp[0]))); 747 } 748 return; 749 } 750 break; 751 752 case NFSPROC_READDIRPLUS: 753 if ((dp = parsereq(ndo, rp, length)) != NULL && 754 (dp = parsefh(ndo, dp, v3)) != NULL) { 755 ND_TCHECK(dp[4]); 756 /* 757 * We don't try to interpret the offset 758 * cookie here. 759 */ 760 ND_PRINT((ndo, " %u bytes @ %" PRId64, 761 EXTRACT_32BITS(&dp[4]), 762 EXTRACT_64BITS(&dp[0]))); 763 if (ndo->ndo_vflag) { 764 ND_TCHECK(dp[5]); 765 ND_PRINT((ndo, " max %u verf %08x%08x", 766 EXTRACT_32BITS(&dp[5]), dp[2], dp[3])); 767 } 768 return; 769 } 770 break; 771 772 case NFSPROC_COMMIT: 773 if ((dp = parsereq(ndo, rp, length)) != NULL && 774 (dp = parsefh(ndo, dp, v3)) != NULL) { 775 ND_TCHECK(dp[2]); 776 ND_PRINT((ndo, " %u bytes @ %" PRIu64, 777 EXTRACT_32BITS(&dp[2]), 778 EXTRACT_64BITS(&dp[0]))); 779 return; 780 } 781 break; 782 783 default: 784 return; 785 } 786 787 trunc: 788 if (!nfserr) 789 ND_PRINT((ndo, "%s", tstr)); 790 } 791 792 /* 793 * Print out an NFS file handle. 794 * We assume packet was not truncated before the end of the 795 * file handle pointed to by dp. 796 * 797 * Note: new version (using portable file-handle parser) doesn't produce 798 * generation number. It probably could be made to do that, with some 799 * additional hacking on the parser code. 800 */ 801 static void 802 nfs_printfh(netdissect_options *ndo, 803 register const uint32_t *dp, const u_int len) 804 { 805 my_fsid fsid; 806 uint32_t ino; 807 const char *sfsname = NULL; 808 char *spacep; 809 810 if (ndo->ndo_uflag) { 811 u_int i; 812 char const *sep = ""; 813 814 ND_PRINT((ndo, " fh[")); 815 for (i=0; i<len; i++) { 816 ND_PRINT((ndo, "%s%x", sep, dp[i])); 817 sep = ":"; 818 } 819 ND_PRINT((ndo, "]")); 820 return; 821 } 822 823 Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0); 824 825 if (sfsname) { 826 /* file system ID is ASCII, not numeric, for this server OS */ 827 static char temp[NFSX_V3FHMAX+1]; 828 829 /* Make sure string is null-terminated */ 830 strncpy(temp, sfsname, NFSX_V3FHMAX); 831 temp[sizeof(temp) - 1] = '\0'; 832 /* Remove trailing spaces */ 833 spacep = strchr(temp, ' '); 834 if (spacep) 835 *spacep = '\0'; 836 837 ND_PRINT((ndo, " fh %s/", temp)); 838 } else { 839 ND_PRINT((ndo, " fh %d,%d/", 840 fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor)); 841 } 842 843 if(fsid.Fsid_dev.Minor == 257) 844 /* Print the undecoded handle */ 845 ND_PRINT((ndo, "%s", fsid.Opaque_Handle)); 846 else 847 ND_PRINT((ndo, "%ld", (long) ino)); 848 } 849 850 /* 851 * Maintain a small cache of recent client.XID.server/proc pairs, to allow 852 * us to match up replies with requests and thus to know how to parse 853 * the reply. 854 */ 855 856 struct xid_map_entry { 857 uint32_t xid; /* transaction ID (net order) */ 858 int ipver; /* IP version (4 or 6) */ 859 #ifdef INET6 860 struct in6_addr client; /* client IP address (net order) */ 861 struct in6_addr server; /* server IP address (net order) */ 862 #else 863 struct in_addr client; /* client IP address (net order) */ 864 struct in_addr server; /* server IP address (net order) */ 865 #endif 866 uint32_t proc; /* call proc number (host order) */ 867 uint32_t vers; /* program version (host order) */ 868 }; 869 870 /* 871 * Map entries are kept in an array that we manage as a ring; 872 * new entries are always added at the tail of the ring. Initially, 873 * all the entries are zero and hence don't match anything. 874 */ 875 876 #define XIDMAPSIZE 64 877 878 struct xid_map_entry xid_map[XIDMAPSIZE]; 879 880 int xid_map_next = 0; 881 int xid_map_hint = 0; 882 883 static int 884 xid_map_enter(netdissect_options *ndo, 885 const struct sunrpc_msg *rp, const u_char *bp) 886 { 887 struct ip *ip = NULL; 888 #ifdef INET6 889 struct ip6_hdr *ip6 = NULL; 890 #endif 891 struct xid_map_entry *xmep; 892 893 if (!ND_TTEST(rp->rm_call.cb_vers)) 894 return (0); 895 switch (IP_V((struct ip *)bp)) { 896 case 4: 897 ip = (struct ip *)bp; 898 break; 899 #ifdef INET6 900 case 6: 901 ip6 = (struct ip6_hdr *)bp; 902 break; 903 #endif 904 default: 905 return (1); 906 } 907 908 xmep = &xid_map[xid_map_next]; 909 910 if (++xid_map_next >= XIDMAPSIZE) 911 xid_map_next = 0; 912 913 UNALIGNED_MEMCPY(&xmep->xid, &rp->rm_xid, sizeof(xmep->xid)); 914 if (ip) { 915 xmep->ipver = 4; 916 UNALIGNED_MEMCPY(&xmep->client, &ip->ip_src, sizeof(ip->ip_src)); 917 UNALIGNED_MEMCPY(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst)); 918 } 919 #ifdef INET6 920 else if (ip6) { 921 xmep->ipver = 6; 922 UNALIGNED_MEMCPY(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src)); 923 UNALIGNED_MEMCPY(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); 924 } 925 #endif 926 xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 927 xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers); 928 return (1); 929 } 930 931 /* 932 * Returns 0 and puts NFSPROC_xxx in proc return and 933 * version in vers return, or returns -1 on failure 934 */ 935 static int 936 xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, uint32_t *proc, 937 uint32_t *vers) 938 { 939 int i; 940 struct xid_map_entry *xmep; 941 uint32_t xid = rp->rm_xid; 942 struct ip *ip = (struct ip *)bp; 943 #ifdef INET6 944 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 945 #endif 946 int cmp; 947 948 /* Start searching from where we last left off */ 949 i = xid_map_hint; 950 do { 951 xmep = &xid_map[i]; 952 cmp = 1; 953 if (xmep->ipver != IP_V(ip) || xmep->xid != xid) 954 goto nextitem; 955 switch (xmep->ipver) { 956 case 4: 957 if (UNALIGNED_MEMCMP(&ip->ip_src, &xmep->server, 958 sizeof(ip->ip_src)) != 0 || 959 UNALIGNED_MEMCMP(&ip->ip_dst, &xmep->client, 960 sizeof(ip->ip_dst)) != 0) { 961 cmp = 0; 962 } 963 break; 964 #ifdef INET6 965 case 6: 966 if (UNALIGNED_MEMCMP(&ip6->ip6_src, &xmep->server, 967 sizeof(ip6->ip6_src)) != 0 || 968 UNALIGNED_MEMCMP(&ip6->ip6_dst, &xmep->client, 969 sizeof(ip6->ip6_dst)) != 0) { 970 cmp = 0; 971 } 972 break; 973 #endif 974 default: 975 cmp = 0; 976 break; 977 } 978 if (cmp) { 979 /* match */ 980 xid_map_hint = i; 981 *proc = xmep->proc; 982 *vers = xmep->vers; 983 return 0; 984 } 985 nextitem: 986 if (++i >= XIDMAPSIZE) 987 i = 0; 988 } while (i != xid_map_hint); 989 990 /* search failed */ 991 return (-1); 992 } 993 994 /* 995 * Routines for parsing reply packets 996 */ 997 998 /* 999 * Return a pointer to the beginning of the actual results. 1000 * If the packet was truncated, return 0. 1001 */ 1002 static const uint32_t * 1003 parserep(netdissect_options *ndo, 1004 register const struct sunrpc_msg *rp, register u_int length) 1005 { 1006 register const uint32_t *dp; 1007 u_int len; 1008 enum sunrpc_accept_stat astat; 1009 1010 /* 1011 * Portability note: 1012 * Here we find the address of the ar_verf credentials. 1013 * Originally, this calculation was 1014 * dp = (uint32_t *)&rp->rm_reply.rp_acpt.ar_verf 1015 * On the wire, the rp_acpt field starts immediately after 1016 * the (32 bit) rp_stat field. However, rp_acpt (which is a 1017 * "struct accepted_reply") contains a "struct opaque_auth", 1018 * whose internal representation contains a pointer, so on a 1019 * 64-bit machine the compiler inserts 32 bits of padding 1020 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 1021 * the internal representation to parse the on-the-wire 1022 * representation. Instead, we skip past the rp_stat field, 1023 * which is an "enum" and so occupies one 32-bit word. 1024 */ 1025 dp = ((const uint32_t *)&rp->rm_reply) + 1; 1026 ND_TCHECK(dp[1]); 1027 len = EXTRACT_32BITS(&dp[1]); 1028 if (len >= length) 1029 return (NULL); 1030 /* 1031 * skip past the ar_verf credentials. 1032 */ 1033 dp += (len + (2*sizeof(uint32_t) + 3)) / sizeof(uint32_t); 1034 ND_TCHECK2(dp[0], 0); 1035 1036 /* 1037 * now we can check the ar_stat field 1038 */ 1039 astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp); 1040 if (astat != SUNRPC_SUCCESS) { 1041 ND_PRINT((ndo, " %s", tok2str(sunrpc_str, "ar_stat %d", astat))); 1042 nfserr = 1; /* suppress trunc string */ 1043 return (NULL); 1044 } 1045 /* successful return */ 1046 ND_TCHECK2(*dp, sizeof(astat)); 1047 return ((uint32_t *) (sizeof(astat) + ((char *)dp))); 1048 trunc: 1049 return (0); 1050 } 1051 1052 static const uint32_t * 1053 parsestatus(netdissect_options *ndo, 1054 const uint32_t *dp, int *er) 1055 { 1056 int errnum; 1057 1058 ND_TCHECK(dp[0]); 1059 1060 errnum = EXTRACT_32BITS(&dp[0]); 1061 if (er) 1062 *er = errnum; 1063 if (errnum != 0) { 1064 if (!ndo->ndo_qflag) 1065 ND_PRINT((ndo, " ERROR: %s", 1066 tok2str(status2str, "unk %d", errnum))); 1067 nfserr = 1; 1068 } 1069 return (dp + 1); 1070 trunc: 1071 return NULL; 1072 } 1073 1074 static const uint32_t * 1075 parsefattr(netdissect_options *ndo, 1076 const uint32_t *dp, int verbose, int v3) 1077 { 1078 const struct nfs_fattr *fap; 1079 1080 fap = (const struct nfs_fattr *)dp; 1081 ND_TCHECK(fap->fa_gid); 1082 if (verbose) { 1083 ND_PRINT((ndo, " %s %o ids %d/%d", 1084 tok2str(type2str, "unk-ft %d ", 1085 EXTRACT_32BITS(&fap->fa_type)), 1086 EXTRACT_32BITS(&fap->fa_mode), 1087 EXTRACT_32BITS(&fap->fa_uid), 1088 EXTRACT_32BITS(&fap->fa_gid))); 1089 if (v3) { 1090 ND_TCHECK(fap->fa3_size); 1091 ND_PRINT((ndo, " sz %" PRIu64, 1092 EXTRACT_64BITS((uint32_t *)&fap->fa3_size))); 1093 } else { 1094 ND_TCHECK(fap->fa2_size); 1095 ND_PRINT((ndo, " sz %d", EXTRACT_32BITS(&fap->fa2_size))); 1096 } 1097 } 1098 /* print lots more stuff */ 1099 if (verbose > 1) { 1100 if (v3) { 1101 ND_TCHECK(fap->fa3_ctime); 1102 ND_PRINT((ndo, " nlink %d rdev %d/%d", 1103 EXTRACT_32BITS(&fap->fa_nlink), 1104 EXTRACT_32BITS(&fap->fa3_rdev.specdata1), 1105 EXTRACT_32BITS(&fap->fa3_rdev.specdata2))); 1106 ND_PRINT((ndo, " fsid %" PRIx64, 1107 EXTRACT_64BITS((uint32_t *)&fap->fa3_fsid))); 1108 ND_PRINT((ndo, " fileid %" PRIx64, 1109 EXTRACT_64BITS((uint32_t *)&fap->fa3_fileid))); 1110 ND_PRINT((ndo, " a/m/ctime %u.%06u", 1111 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec), 1112 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec))); 1113 ND_PRINT((ndo, " %u.%06u", 1114 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec), 1115 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec))); 1116 ND_PRINT((ndo, " %u.%06u", 1117 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec), 1118 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec))); 1119 } else { 1120 ND_TCHECK(fap->fa2_ctime); 1121 ND_PRINT((ndo, " nlink %d rdev 0x%x fsid 0x%x nodeid 0x%x a/m/ctime", 1122 EXTRACT_32BITS(&fap->fa_nlink), 1123 EXTRACT_32BITS(&fap->fa2_rdev), 1124 EXTRACT_32BITS(&fap->fa2_fsid), 1125 EXTRACT_32BITS(&fap->fa2_fileid))); 1126 ND_PRINT((ndo, " %u.%06u", 1127 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec), 1128 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec))); 1129 ND_PRINT((ndo, " %u.%06u", 1130 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec), 1131 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec))); 1132 ND_PRINT((ndo, " %u.%06u", 1133 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec), 1134 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec))); 1135 } 1136 } 1137 return ((const uint32_t *)((unsigned char *)dp + 1138 (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 1139 trunc: 1140 return (NULL); 1141 } 1142 1143 static int 1144 parseattrstat(netdissect_options *ndo, 1145 const uint32_t *dp, int verbose, int v3) 1146 { 1147 int er; 1148 1149 dp = parsestatus(ndo, dp, &er); 1150 if (dp == NULL) 1151 return (0); 1152 if (er) 1153 return (1); 1154 1155 return (parsefattr(ndo, dp, verbose, v3) != NULL); 1156 } 1157 1158 static int 1159 parsediropres(netdissect_options *ndo, 1160 const uint32_t *dp) 1161 { 1162 int er; 1163 1164 if (!(dp = parsestatus(ndo, dp, &er))) 1165 return (0); 1166 if (er) 1167 return (1); 1168 1169 dp = parsefh(ndo, dp, 0); 1170 if (dp == NULL) 1171 return (0); 1172 1173 return (parsefattr(ndo, dp, ndo->ndo_vflag, 0) != NULL); 1174 } 1175 1176 static int 1177 parselinkres(netdissect_options *ndo, 1178 const uint32_t *dp, int v3) 1179 { 1180 int er; 1181 1182 dp = parsestatus(ndo, dp, &er); 1183 if (dp == NULL) 1184 return(0); 1185 if (er) 1186 return(1); 1187 if (v3 && !(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1188 return (0); 1189 ND_PRINT((ndo, " ")); 1190 return (parsefn(ndo, dp) != NULL); 1191 } 1192 1193 static int 1194 parsestatfs(netdissect_options *ndo, 1195 const uint32_t *dp, int v3) 1196 { 1197 const struct nfs_statfs *sfsp; 1198 int er; 1199 1200 dp = parsestatus(ndo, dp, &er); 1201 if (dp == NULL) 1202 return (0); 1203 if (!v3 && er) 1204 return (1); 1205 1206 if (ndo->ndo_qflag) 1207 return(1); 1208 1209 if (v3) { 1210 if (ndo->ndo_vflag) 1211 ND_PRINT((ndo, " POST:")); 1212 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1213 return (0); 1214 } 1215 1216 ND_TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 1217 1218 sfsp = (const struct nfs_statfs *)dp; 1219 1220 if (v3) { 1221 ND_PRINT((ndo, " tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64, 1222 EXTRACT_64BITS((uint32_t *)&sfsp->sf_tbytes), 1223 EXTRACT_64BITS((uint32_t *)&sfsp->sf_fbytes), 1224 EXTRACT_64BITS((uint32_t *)&sfsp->sf_abytes))); 1225 if (ndo->ndo_vflag) { 1226 ND_PRINT((ndo, " tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u", 1227 EXTRACT_64BITS((uint32_t *)&sfsp->sf_tfiles), 1228 EXTRACT_64BITS((uint32_t *)&sfsp->sf_ffiles), 1229 EXTRACT_64BITS((uint32_t *)&sfsp->sf_afiles), 1230 EXTRACT_32BITS(&sfsp->sf_invarsec))); 1231 } 1232 } else { 1233 ND_PRINT((ndo, " tsize %d bsize %d blocks %d bfree %d bavail %d", 1234 EXTRACT_32BITS(&sfsp->sf_tsize), 1235 EXTRACT_32BITS(&sfsp->sf_bsize), 1236 EXTRACT_32BITS(&sfsp->sf_blocks), 1237 EXTRACT_32BITS(&sfsp->sf_bfree), 1238 EXTRACT_32BITS(&sfsp->sf_bavail))); 1239 } 1240 1241 return (1); 1242 trunc: 1243 return (0); 1244 } 1245 1246 static int 1247 parserddires(netdissect_options *ndo, 1248 const uint32_t *dp) 1249 { 1250 int er; 1251 1252 dp = parsestatus(ndo, dp, &er); 1253 if (dp == NULL) 1254 return (0); 1255 if (er) 1256 return (1); 1257 if (ndo->ndo_qflag) 1258 return (1); 1259 1260 ND_TCHECK(dp[2]); 1261 ND_PRINT((ndo, " offset 0x%x size %d ", 1262 EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]))); 1263 if (dp[2] != 0) 1264 ND_PRINT((ndo, " eof")); 1265 1266 return (1); 1267 trunc: 1268 return (0); 1269 } 1270 1271 static const uint32_t * 1272 parse_wcc_attr(netdissect_options *ndo, 1273 const uint32_t *dp) 1274 { 1275 ND_PRINT((ndo, " sz %" PRIu64, EXTRACT_64BITS(&dp[0]))); 1276 ND_PRINT((ndo, " mtime %u.%06u ctime %u.%06u", 1277 EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]), 1278 EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]))); 1279 return (dp + 6); 1280 } 1281 1282 /* 1283 * Pre operation attributes. Print only if vflag > 1. 1284 */ 1285 static const uint32_t * 1286 parse_pre_op_attr(netdissect_options *ndo, 1287 const uint32_t *dp, int verbose) 1288 { 1289 ND_TCHECK(dp[0]); 1290 if (!EXTRACT_32BITS(&dp[0])) 1291 return (dp + 1); 1292 dp++; 1293 ND_TCHECK2(*dp, 24); 1294 if (verbose > 1) { 1295 return parse_wcc_attr(ndo, dp); 1296 } else { 1297 /* If not verbose enough, just skip over wcc_attr */ 1298 return (dp + 6); 1299 } 1300 trunc: 1301 return (NULL); 1302 } 1303 1304 /* 1305 * Post operation attributes are printed if vflag >= 1 1306 */ 1307 static const uint32_t * 1308 parse_post_op_attr(netdissect_options *ndo, 1309 const uint32_t *dp, int verbose) 1310 { 1311 ND_TCHECK(dp[0]); 1312 if (!EXTRACT_32BITS(&dp[0])) 1313 return (dp + 1); 1314 dp++; 1315 if (verbose) { 1316 return parsefattr(ndo, dp, verbose, 1); 1317 } else 1318 return (dp + (NFSX_V3FATTR / sizeof (uint32_t))); 1319 trunc: 1320 return (NULL); 1321 } 1322 1323 static const uint32_t * 1324 parse_wcc_data(netdissect_options *ndo, 1325 const uint32_t *dp, int verbose) 1326 { 1327 if (verbose > 1) 1328 ND_PRINT((ndo, " PRE:")); 1329 if (!(dp = parse_pre_op_attr(ndo, dp, verbose))) 1330 return (0); 1331 1332 if (verbose) 1333 ND_PRINT((ndo, " POST:")); 1334 return parse_post_op_attr(ndo, dp, verbose); 1335 } 1336 1337 static const uint32_t * 1338 parsecreateopres(netdissect_options *ndo, 1339 const uint32_t *dp, int verbose) 1340 { 1341 int er; 1342 1343 if (!(dp = parsestatus(ndo, dp, &er))) 1344 return (0); 1345 if (er) 1346 dp = parse_wcc_data(ndo, dp, verbose); 1347 else { 1348 ND_TCHECK(dp[0]); 1349 if (!EXTRACT_32BITS(&dp[0])) 1350 return (dp + 1); 1351 dp++; 1352 if (!(dp = parsefh(ndo, dp, 1))) 1353 return (0); 1354 if (verbose) { 1355 if (!(dp = parse_post_op_attr(ndo, dp, verbose))) 1356 return (0); 1357 if (ndo->ndo_vflag > 1) { 1358 ND_PRINT((ndo, " dir attr:")); 1359 dp = parse_wcc_data(ndo, dp, verbose); 1360 } 1361 } 1362 } 1363 return (dp); 1364 trunc: 1365 return (NULL); 1366 } 1367 1368 static int 1369 parsewccres(netdissect_options *ndo, 1370 const uint32_t *dp, int verbose) 1371 { 1372 int er; 1373 1374 if (!(dp = parsestatus(ndo, dp, &er))) 1375 return (0); 1376 return parse_wcc_data(ndo, dp, verbose) != 0; 1377 } 1378 1379 static const uint32_t * 1380 parsev3rddirres(netdissect_options *ndo, 1381 const uint32_t *dp, int verbose) 1382 { 1383 int er; 1384 1385 if (!(dp = parsestatus(ndo, dp, &er))) 1386 return (0); 1387 if (ndo->ndo_vflag) 1388 ND_PRINT((ndo, " POST:")); 1389 if (!(dp = parse_post_op_attr(ndo, dp, verbose))) 1390 return (0); 1391 if (er) 1392 return dp; 1393 if (ndo->ndo_vflag) { 1394 ND_TCHECK(dp[1]); 1395 ND_PRINT((ndo, " verf %08x%08x", dp[0], dp[1])); 1396 dp += 2; 1397 } 1398 return dp; 1399 trunc: 1400 return (NULL); 1401 } 1402 1403 static int 1404 parsefsinfo(netdissect_options *ndo, 1405 const uint32_t *dp) 1406 { 1407 struct nfsv3_fsinfo *sfp; 1408 int er; 1409 1410 if (!(dp = parsestatus(ndo, dp, &er))) 1411 return (0); 1412 if (ndo->ndo_vflag) 1413 ND_PRINT((ndo, " POST:")); 1414 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1415 return (0); 1416 if (er) 1417 return (1); 1418 1419 sfp = (struct nfsv3_fsinfo *)dp; 1420 ND_TCHECK(*sfp); 1421 ND_PRINT((ndo, " rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u", 1422 EXTRACT_32BITS(&sfp->fs_rtmax), 1423 EXTRACT_32BITS(&sfp->fs_rtpref), 1424 EXTRACT_32BITS(&sfp->fs_wtmax), 1425 EXTRACT_32BITS(&sfp->fs_wtpref), 1426 EXTRACT_32BITS(&sfp->fs_dtpref))); 1427 if (ndo->ndo_vflag) { 1428 ND_PRINT((ndo, " rtmult %u wtmult %u maxfsz %" PRIu64, 1429 EXTRACT_32BITS(&sfp->fs_rtmult), 1430 EXTRACT_32BITS(&sfp->fs_wtmult), 1431 EXTRACT_64BITS((uint32_t *)&sfp->fs_maxfilesize))); 1432 ND_PRINT((ndo, " delta %u.%06u ", 1433 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec), 1434 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec))); 1435 } 1436 return (1); 1437 trunc: 1438 return (0); 1439 } 1440 1441 static int 1442 parsepathconf(netdissect_options *ndo, 1443 const uint32_t *dp) 1444 { 1445 int er; 1446 struct nfsv3_pathconf *spp; 1447 1448 if (!(dp = parsestatus(ndo, dp, &er))) 1449 return (0); 1450 if (ndo->ndo_vflag) 1451 ND_PRINT((ndo, " POST:")); 1452 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1453 return (0); 1454 if (er) 1455 return (1); 1456 1457 spp = (struct nfsv3_pathconf *)dp; 1458 ND_TCHECK(*spp); 1459 1460 ND_PRINT((ndo, " linkmax %u namemax %u %s %s %s %s", 1461 EXTRACT_32BITS(&spp->pc_linkmax), 1462 EXTRACT_32BITS(&spp->pc_namemax), 1463 EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "", 1464 EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "", 1465 EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "", 1466 EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "")); 1467 return (1); 1468 trunc: 1469 return (0); 1470 } 1471 1472 static void 1473 interp_reply(netdissect_options *ndo, 1474 const struct sunrpc_msg *rp, uint32_t proc, uint32_t vers, int length) 1475 { 1476 register const uint32_t *dp; 1477 register int v3; 1478 int er; 1479 1480 v3 = (vers == NFS_VER3); 1481 1482 if (!v3 && proc < NFS_NPROCS) 1483 proc = nfsv3_procid[proc]; 1484 1485 ND_PRINT((ndo, " %s", tok2str(nfsproc_str, "proc-%u", proc))); 1486 switch (proc) { 1487 1488 case NFSPROC_GETATTR: 1489 dp = parserep(ndo, rp, length); 1490 if (dp != NULL && parseattrstat(ndo, dp, !ndo->ndo_qflag, v3) != 0) 1491 return; 1492 break; 1493 1494 case NFSPROC_SETATTR: 1495 if (!(dp = parserep(ndo, rp, length))) 1496 return; 1497 if (v3) { 1498 if (parsewccres(ndo, dp, ndo->ndo_vflag)) 1499 return; 1500 } else { 1501 if (parseattrstat(ndo, dp, !ndo->ndo_qflag, 0) != 0) 1502 return; 1503 } 1504 break; 1505 1506 case NFSPROC_LOOKUP: 1507 if (!(dp = parserep(ndo, rp, length))) 1508 break; 1509 if (v3) { 1510 if (!(dp = parsestatus(ndo, dp, &er))) 1511 break; 1512 if (er) { 1513 if (ndo->ndo_vflag > 1) { 1514 ND_PRINT((ndo, " post dattr:")); 1515 dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag); 1516 } 1517 } else { 1518 if (!(dp = parsefh(ndo, dp, v3))) 1519 break; 1520 if ((dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag)) && 1521 ndo->ndo_vflag > 1) { 1522 ND_PRINT((ndo, " post dattr:")); 1523 dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag); 1524 } 1525 } 1526 if (dp) 1527 return; 1528 } else { 1529 if (parsediropres(ndo, dp) != 0) 1530 return; 1531 } 1532 break; 1533 1534 case NFSPROC_ACCESS: 1535 if (!(dp = parserep(ndo, rp, length))) 1536 break; 1537 if (!(dp = parsestatus(ndo, dp, &er))) 1538 break; 1539 if (ndo->ndo_vflag) 1540 ND_PRINT((ndo, " attr:")); 1541 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1542 break; 1543 if (!er) 1544 ND_PRINT((ndo, " c %04x", EXTRACT_32BITS(&dp[0]))); 1545 return; 1546 1547 case NFSPROC_READLINK: 1548 dp = parserep(ndo, rp, length); 1549 if (dp != NULL && parselinkres(ndo, dp, v3) != 0) 1550 return; 1551 break; 1552 1553 case NFSPROC_READ: 1554 if (!(dp = parserep(ndo, rp, length))) 1555 break; 1556 if (v3) { 1557 if (!(dp = parsestatus(ndo, dp, &er))) 1558 break; 1559 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1560 break; 1561 if (er) 1562 return; 1563 if (ndo->ndo_vflag) { 1564 ND_TCHECK(dp[1]); 1565 ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0]))); 1566 if (EXTRACT_32BITS(&dp[1])) 1567 ND_PRINT((ndo, " EOF")); 1568 } 1569 return; 1570 } else { 1571 if (parseattrstat(ndo, dp, ndo->ndo_vflag, 0) != 0) 1572 return; 1573 } 1574 break; 1575 1576 case NFSPROC_WRITE: 1577 if (!(dp = parserep(ndo, rp, length))) 1578 break; 1579 if (v3) { 1580 if (!(dp = parsestatus(ndo, dp, &er))) 1581 break; 1582 if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 1583 break; 1584 if (er) 1585 return; 1586 if (ndo->ndo_vflag) { 1587 ND_TCHECK(dp[0]); 1588 ND_PRINT((ndo, " %u bytes", EXTRACT_32BITS(&dp[0]))); 1589 if (ndo->ndo_vflag > 1) { 1590 ND_TCHECK(dp[1]); 1591 ND_PRINT((ndo, " <%s>", 1592 tok2str(nfsv3_writemodes, 1593 NULL, EXTRACT_32BITS(&dp[1])))); 1594 } 1595 return; 1596 } 1597 } else { 1598 if (parseattrstat(ndo, dp, ndo->ndo_vflag, v3) != 0) 1599 return; 1600 } 1601 break; 1602 1603 case NFSPROC_CREATE: 1604 case NFSPROC_MKDIR: 1605 if (!(dp = parserep(ndo, rp, length))) 1606 break; 1607 if (v3) { 1608 if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0) 1609 return; 1610 } else { 1611 if (parsediropres(ndo, dp) != 0) 1612 return; 1613 } 1614 break; 1615 1616 case NFSPROC_SYMLINK: 1617 if (!(dp = parserep(ndo, rp, length))) 1618 break; 1619 if (v3) { 1620 if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0) 1621 return; 1622 } else { 1623 if (parsestatus(ndo, dp, &er) != 0) 1624 return; 1625 } 1626 break; 1627 1628 case NFSPROC_MKNOD: 1629 if (!(dp = parserep(ndo, rp, length))) 1630 break; 1631 if (parsecreateopres(ndo, dp, ndo->ndo_vflag) != 0) 1632 return; 1633 break; 1634 1635 case NFSPROC_REMOVE: 1636 case NFSPROC_RMDIR: 1637 if (!(dp = parserep(ndo, rp, length))) 1638 break; 1639 if (v3) { 1640 if (parsewccres(ndo, dp, ndo->ndo_vflag)) 1641 return; 1642 } else { 1643 if (parsestatus(ndo, dp, &er) != 0) 1644 return; 1645 } 1646 break; 1647 1648 case NFSPROC_RENAME: 1649 if (!(dp = parserep(ndo, rp, length))) 1650 break; 1651 if (v3) { 1652 if (!(dp = parsestatus(ndo, dp, &er))) 1653 break; 1654 if (ndo->ndo_vflag) { 1655 ND_PRINT((ndo, " from:")); 1656 if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 1657 break; 1658 ND_PRINT((ndo, " to:")); 1659 if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 1660 break; 1661 } 1662 return; 1663 } else { 1664 if (parsestatus(ndo, dp, &er) != 0) 1665 return; 1666 } 1667 break; 1668 1669 case NFSPROC_LINK: 1670 if (!(dp = parserep(ndo, rp, length))) 1671 break; 1672 if (v3) { 1673 if (!(dp = parsestatus(ndo, dp, &er))) 1674 break; 1675 if (ndo->ndo_vflag) { 1676 ND_PRINT((ndo, " file POST:")); 1677 if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) 1678 break; 1679 ND_PRINT((ndo, " dir:")); 1680 if (!(dp = parse_wcc_data(ndo, dp, ndo->ndo_vflag))) 1681 break; 1682 return; 1683 } 1684 } else { 1685 if (parsestatus(ndo, dp, &er) != 0) 1686 return; 1687 } 1688 break; 1689 1690 case NFSPROC_READDIR: 1691 if (!(dp = parserep(ndo, rp, length))) 1692 break; 1693 if (v3) { 1694 if (parsev3rddirres(ndo, dp, ndo->ndo_vflag)) 1695 return; 1696 } else { 1697 if (parserddires(ndo, dp) != 0) 1698 return; 1699 } 1700 break; 1701 1702 case NFSPROC_READDIRPLUS: 1703 if (!(dp = parserep(ndo, rp, length))) 1704 break; 1705 if (parsev3rddirres(ndo, dp, ndo->ndo_vflag)) 1706 return; 1707 break; 1708 1709 case NFSPROC_FSSTAT: 1710 dp = parserep(ndo, rp, length); 1711 if (dp != NULL && parsestatfs(ndo, dp, v3) != 0) 1712 return; 1713 break; 1714 1715 case NFSPROC_FSINFO: 1716 dp = parserep(ndo, rp, length); 1717 if (dp != NULL && parsefsinfo(ndo, dp) != 0) 1718 return; 1719 break; 1720 1721 case NFSPROC_PATHCONF: 1722 dp = parserep(ndo, rp, length); 1723 if (dp != NULL && parsepathconf(ndo, dp) != 0) 1724 return; 1725 break; 1726 1727 case NFSPROC_COMMIT: 1728 dp = parserep(ndo, rp, length); 1729 if (dp != NULL && parsewccres(ndo, dp, ndo->ndo_vflag) != 0) 1730 return; 1731 break; 1732 1733 default: 1734 return; 1735 } 1736 trunc: 1737 if (!nfserr) 1738 ND_PRINT((ndo, "%s", tstr)); 1739 } 1740