1 /*
2 * Copyright: (c) 2000 United States Government as represented by the
3 * Secretary of the Navy. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior
17 * written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 */
23
24 /* \summary: AFS RX printer */
25
26 /*
27 * This code unmangles RX packets. RX is the mutant form of RPC that AFS
28 * uses to communicate between clients and servers.
29 *
30 * In this code, I mainly concern myself with decoding the AFS calls, not
31 * with the guts of RX, per se.
32 *
33 * Bah. If I never look at rx_packet.h again, it will be too soon.
34 *
35 * Ken Hornstein <kenh@cmf.nrl.navy.mil>
36 */
37
38 #include <sys/cdefs.h>
39 #ifndef lint
40 __RCSID("$NetBSD: print-rx.c,v 1.11 2024/09/02 16:15:33 christos Exp $");
41 #endif
42
43 #include <config.h>
44
45 #include <stdio.h>
46 #include <string.h>
47 #include "netdissect-stdinc.h"
48
49 #include "netdissect.h"
50 #include "addrtoname.h"
51 #include "extract.h"
52
53 #include "ip.h"
54
55 #define FS_RX_PORT 7000
56 #define CB_RX_PORT 7001
57 #define PROT_RX_PORT 7002
58 #define VLDB_RX_PORT 7003
59 #define KAUTH_RX_PORT 7004
60 #define VOL_RX_PORT 7005
61 #define ERROR_RX_PORT 7006 /* Doesn't seem to be used */
62 #define BOS_RX_PORT 7007
63
64 #define AFSOPAQUEMAX 1024
65 #define AFSNAMEMAX 256 /* Must be >= PRNAMEMAX + 1, VLNAMEMAX + 1, and 32 + 1 */
66 #define PRNAMEMAX 64
67 #define VLNAMEMAX 65
68 #define KANAMEMAX 64
69 #define BOSNAMEMAX 256
70 #define USERNAMEMAX 1024 /* AFSOPAQUEMAX was used for this; does it need to be this big? */
71
72 #define PRSFS_READ 1 /* Read files */
73 #define PRSFS_WRITE 2 /* Write files */
74 #define PRSFS_INSERT 4 /* Insert files into a directory */
75 #define PRSFS_LOOKUP 8 /* Lookup files into a directory */
76 #define PRSFS_DELETE 16 /* Delete files */
77 #define PRSFS_LOCK 32 /* Lock files */
78 #define PRSFS_ADMINISTER 64 /* Change ACL's */
79
80 struct rx_header {
81 nd_uint32_t epoch;
82 nd_uint32_t cid;
83 nd_uint32_t callNumber;
84 nd_uint32_t seq;
85 nd_uint32_t serial;
86 nd_uint8_t type;
87 #define RX_PACKET_TYPE_DATA 1
88 #define RX_PACKET_TYPE_ACK 2
89 #define RX_PACKET_TYPE_BUSY 3
90 #define RX_PACKET_TYPE_ABORT 4
91 #define RX_PACKET_TYPE_ACKALL 5
92 #define RX_PACKET_TYPE_CHALLENGE 6
93 #define RX_PACKET_TYPE_RESPONSE 7
94 #define RX_PACKET_TYPE_DEBUG 8
95 #define RX_PACKET_TYPE_PARAMS 9
96 #define RX_PACKET_TYPE_VERSION 13
97 nd_uint8_t flags;
98 #define RX_CLIENT_INITIATED 1
99 #define RX_REQUEST_ACK 2
100 #define RX_LAST_PACKET 4
101 #define RX_MORE_PACKETS 8
102 #define RX_FREE_PACKET 16
103 #define RX_SLOW_START_OK 32
104 #define RX_JUMBO_PACKET 32
105 nd_uint8_t userStatus;
106 nd_uint8_t securityIndex;
107 nd_uint16_t spare; /* How clever: even though the AFS */
108 nd_uint16_t serviceId; /* header files indicate that the */
109 }; /* serviceId is first, it's really */
110 /* encoded _after_ the spare field */
111 /* I wasted a day figuring that out! */
112
113 #define NUM_RX_FLAGS 7
114
115 #define RX_MAXACKS 255
116
117 struct rx_ackPacket {
118 nd_uint16_t bufferSpace; /* Number of packet buffers available */
119 nd_uint16_t maxSkew; /* Max diff between ack'd packet and */
120 /* highest packet received */
121 nd_uint32_t firstPacket; /* The first packet in ack list */
122 nd_uint32_t previousPacket; /* Previous packet recv'd (obsolete) */
123 nd_uint32_t serial; /* # of packet that prompted the ack */
124 nd_uint8_t reason; /* Reason for acknowledgement */
125 nd_uint8_t nAcks; /* Number of acknowledgements */
126 /* Followed by nAcks acknowledgments */
127 #if 0
128 uint8_t acks[RX_MAXACKS]; /* Up to RX_MAXACKS acknowledgements */
129 #endif
130 };
131
132 /*
133 * Values for the acks array
134 */
135
136 #define RX_ACK_TYPE_NACK 0 /* Don't have this packet */
137 #define RX_ACK_TYPE_ACK 1 /* I have this packet */
138
139 static const struct tok rx_types[] = {
140 { RX_PACKET_TYPE_DATA, "data" },
141 { RX_PACKET_TYPE_ACK, "ack" },
142 { RX_PACKET_TYPE_BUSY, "busy" },
143 { RX_PACKET_TYPE_ABORT, "abort" },
144 { RX_PACKET_TYPE_ACKALL, "ackall" },
145 { RX_PACKET_TYPE_CHALLENGE, "challenge" },
146 { RX_PACKET_TYPE_RESPONSE, "response" },
147 { RX_PACKET_TYPE_DEBUG, "debug" },
148 { RX_PACKET_TYPE_PARAMS, "params" },
149 { RX_PACKET_TYPE_VERSION, "version" },
150 { 0, NULL },
151 };
152
153 static const struct double_tok {
154 uint32_t flag; /* Rx flag */
155 uint32_t packetType; /* Packet type */
156 const char *s; /* Flag string */
157 } rx_flags[] = {
158 { RX_CLIENT_INITIATED, 0, "client-init" },
159 { RX_REQUEST_ACK, 0, "req-ack" },
160 { RX_LAST_PACKET, 0, "last-pckt" },
161 { RX_MORE_PACKETS, 0, "more-pckts" },
162 { RX_FREE_PACKET, 0, "free-pckt" },
163 { RX_SLOW_START_OK, RX_PACKET_TYPE_ACK, "slow-start" },
164 { RX_JUMBO_PACKET, RX_PACKET_TYPE_DATA, "jumbogram" }
165 };
166
167 static const struct tok fs_req[] = {
168 { 130, "fetch-data" },
169 { 131, "fetch-acl" },
170 { 132, "fetch-status" },
171 { 133, "store-data" },
172 { 134, "store-acl" },
173 { 135, "store-status" },
174 { 136, "remove-file" },
175 { 137, "create-file" },
176 { 138, "rename" },
177 { 139, "symlink" },
178 { 140, "link" },
179 { 141, "makedir" },
180 { 142, "rmdir" },
181 { 143, "oldsetlock" },
182 { 144, "oldextlock" },
183 { 145, "oldrellock" },
184 { 146, "get-stats" },
185 { 147, "give-cbs" },
186 { 148, "get-vlinfo" },
187 { 149, "get-vlstats" },
188 { 150, "set-vlstats" },
189 { 151, "get-rootvl" },
190 { 152, "check-token" },
191 { 153, "get-time" },
192 { 154, "nget-vlinfo" },
193 { 155, "bulk-stat" },
194 { 156, "setlock" },
195 { 157, "extlock" },
196 { 158, "rellock" },
197 { 159, "xstat-ver" },
198 { 160, "get-xstat" },
199 { 161, "dfs-lookup" },
200 { 162, "dfs-flushcps" },
201 { 163, "dfs-symlink" },
202 { 220, "residency" },
203 { 65536, "inline-bulk-status" },
204 { 65537, "fetch-data-64" },
205 { 65538, "store-data-64" },
206 { 65539, "give-up-all-cbs" },
207 { 65540, "get-caps" },
208 { 65541, "cb-rx-conn-addr" },
209 { 0, NULL },
210 };
211
212 static const struct tok cb_req[] = {
213 { 204, "callback" },
214 { 205, "initcb" },
215 { 206, "probe" },
216 { 207, "getlock" },
217 { 208, "getce" },
218 { 209, "xstatver" },
219 { 210, "getxstat" },
220 { 211, "initcb2" },
221 { 212, "whoareyou" },
222 { 213, "initcb3" },
223 { 214, "probeuuid" },
224 { 215, "getsrvprefs" },
225 { 216, "getcellservdb" },
226 { 217, "getlocalcell" },
227 { 218, "getcacheconf" },
228 { 65536, "getce64" },
229 { 65537, "getcellbynum" },
230 { 65538, "tellmeaboutyourself" },
231 { 0, NULL },
232 };
233
234 static const struct tok pt_req[] = {
235 { 500, "new-user" },
236 { 501, "where-is-it" },
237 { 502, "dump-entry" },
238 { 503, "add-to-group" },
239 { 504, "name-to-id" },
240 { 505, "id-to-name" },
241 { 506, "delete" },
242 { 507, "remove-from-group" },
243 { 508, "get-cps" },
244 { 509, "new-entry" },
245 { 510, "list-max" },
246 { 511, "set-max" },
247 { 512, "list-entry" },
248 { 513, "change-entry" },
249 { 514, "list-elements" },
250 { 515, "same-mbr-of" },
251 { 516, "set-fld-sentry" },
252 { 517, "list-owned" },
253 { 518, "get-cps2" },
254 { 519, "get-host-cps" },
255 { 520, "update-entry" },
256 { 521, "list-entries" },
257 { 530, "list-super-groups" },
258 { 0, NULL },
259 };
260
261 static const struct tok vldb_req[] = {
262 { 501, "create-entry" },
263 { 502, "delete-entry" },
264 { 503, "get-entry-by-id" },
265 { 504, "get-entry-by-name" },
266 { 505, "get-new-volume-id" },
267 { 506, "replace-entry" },
268 { 507, "update-entry" },
269 { 508, "setlock" },
270 { 509, "releaselock" },
271 { 510, "list-entry" },
272 { 511, "list-attrib" },
273 { 512, "linked-list" },
274 { 513, "get-stats" },
275 { 514, "probe" },
276 { 515, "get-addrs" },
277 { 516, "change-addr" },
278 { 517, "create-entry-n" },
279 { 518, "get-entry-by-id-n" },
280 { 519, "get-entry-by-name-n" },
281 { 520, "replace-entry-n" },
282 { 521, "list-entry-n" },
283 { 522, "list-attrib-n" },
284 { 523, "linked-list-n" },
285 { 524, "update-entry-by-name" },
286 { 525, "create-entry-u" },
287 { 526, "get-entry-by-id-u" },
288 { 527, "get-entry-by-name-u" },
289 { 528, "replace-entry-u" },
290 { 529, "list-entry-u" },
291 { 530, "list-attrib-u" },
292 { 531, "linked-list-u" },
293 { 532, "regaddr" },
294 { 533, "get-addrs-u" },
295 { 534, "list-attrib-n2" },
296 { 0, NULL },
297 };
298
299 static const struct tok kauth_req[] = {
300 { 1, "auth-old" },
301 { 21, "authenticate" },
302 { 22, "authenticate-v2" },
303 { 2, "change-pw" },
304 { 3, "get-ticket-old" },
305 { 23, "get-ticket" },
306 { 4, "set-pw" },
307 { 5, "set-fields" },
308 { 6, "create-user" },
309 { 7, "delete-user" },
310 { 8, "get-entry" },
311 { 9, "list-entry" },
312 { 10, "get-stats" },
313 { 11, "debug" },
314 { 12, "get-pw" },
315 { 13, "get-random-key" },
316 { 14, "unlock" },
317 { 15, "lock-status" },
318 { 0, NULL },
319 };
320
321 static const struct tok vol_req[] = {
322 { 100, "create-volume" },
323 { 101, "delete-volume" },
324 { 102, "restore" },
325 { 103, "forward" },
326 { 104, "end-trans" },
327 { 105, "clone" },
328 { 106, "set-flags" },
329 { 107, "get-flags" },
330 { 108, "trans-create" },
331 { 109, "dump" },
332 { 110, "get-nth-volume" },
333 { 111, "set-forwarding" },
334 { 112, "get-name" },
335 { 113, "get-status" },
336 { 114, "sig-restore" },
337 { 115, "list-partitions" },
338 { 116, "list-volumes" },
339 { 117, "set-id-types" },
340 { 118, "monitor" },
341 { 119, "partition-info" },
342 { 120, "reclone" },
343 { 121, "list-one-volume" },
344 { 122, "nuke" },
345 { 123, "set-date" },
346 { 124, "x-list-volumes" },
347 { 125, "x-list-one-volume" },
348 { 126, "set-info" },
349 { 127, "x-list-partitions" },
350 { 128, "forward-multiple" },
351 { 65536, "convert-ro" },
352 { 65537, "get-size" },
353 { 65538, "dump-v2" },
354 { 0, NULL },
355 };
356
357 static const struct tok bos_req[] = {
358 { 80, "create-bnode" },
359 { 81, "delete-bnode" },
360 { 82, "set-status" },
361 { 83, "get-status" },
362 { 84, "enumerate-instance" },
363 { 85, "get-instance-info" },
364 { 86, "get-instance-parm" },
365 { 87, "add-superuser" },
366 { 88, "delete-superuser" },
367 { 89, "list-superusers" },
368 { 90, "list-keys" },
369 { 91, "add-key" },
370 { 92, "delete-key" },
371 { 93, "set-cell-name" },
372 { 94, "get-cell-name" },
373 { 95, "get-cell-host" },
374 { 96, "add-cell-host" },
375 { 97, "delete-cell-host" },
376 { 98, "set-t-status" },
377 { 99, "shutdown-all" },
378 { 100, "restart-all" },
379 { 101, "startup-all" },
380 { 102, "set-noauth-flag" },
381 { 103, "re-bozo" },
382 { 104, "restart" },
383 { 105, "start-bozo-install" },
384 { 106, "uninstall" },
385 { 107, "get-dates" },
386 { 108, "exec" },
387 { 109, "prune" },
388 { 110, "set-restart-time" },
389 { 111, "get-restart-time" },
390 { 112, "start-bozo-log" },
391 { 113, "wait-all" },
392 { 114, "get-instance-strings" },
393 { 115, "get-restricted" },
394 { 116, "set-restricted" },
395 { 0, NULL },
396 };
397
398 static const struct tok ubik_req[] = {
399 { 10000, "vote-beacon" },
400 { 10001, "vote-debug-old" },
401 { 10002, "vote-sdebug-old" },
402 { 10003, "vote-getsyncsite" },
403 { 10004, "vote-debug" },
404 { 10005, "vote-sdebug" },
405 { 10006, "vote-xdebug" },
406 { 10007, "vote-xsdebug" },
407 { 20000, "disk-begin" },
408 { 20001, "disk-commit" },
409 { 20002, "disk-lock" },
410 { 20003, "disk-write" },
411 { 20004, "disk-getversion" },
412 { 20005, "disk-getfile" },
413 { 20006, "disk-sendfile" },
414 { 20007, "disk-abort" },
415 { 20008, "disk-releaselocks" },
416 { 20009, "disk-truncate" },
417 { 20010, "disk-probe" },
418 { 20011, "disk-writev" },
419 { 20012, "disk-interfaceaddr" },
420 { 20013, "disk-setversion" },
421 { 0, NULL },
422 };
423
424 #define VOTE_LOW 10000
425 #define VOTE_HIGH 10007
426 #define DISK_LOW 20000
427 #define DISK_HIGH 20013
428
429 static const struct tok cb_types[] = {
430 { 1, "exclusive" },
431 { 2, "shared" },
432 { 3, "dropped" },
433 { 0, NULL },
434 };
435
436 static const struct tok ubik_lock_types[] = {
437 { 1, "read" },
438 { 2, "write" },
439 { 3, "wait" },
440 { 0, NULL },
441 };
442
443 static const char *voltype[] = { "read-write", "read-only", "backup" };
444
445 static const struct tok afs_fs_errors[] = {
446 { 101, "salvage volume" },
447 { 102, "no such vnode" },
448 { 103, "no such volume" },
449 { 104, "volume exist" },
450 { 105, "no service" },
451 { 106, "volume offline" },
452 { 107, "voline online" },
453 { 108, "diskfull" },
454 { 109, "diskquota exceeded" },
455 { 110, "volume busy" },
456 { 111, "volume moved" },
457 { 112, "AFS IO error" },
458 { 0xffffff9c, "restarting fileserver" }, /* -100, sic! */
459 { 0, NULL }
460 };
461
462 /*
463 * Reasons for acknowledging a packet
464 */
465
466 static const struct tok rx_ack_reasons[] = {
467 { 1, "ack requested" },
468 { 2, "duplicate packet" },
469 { 3, "out of sequence" },
470 { 4, "exceeds window" },
471 { 5, "no buffer space" },
472 { 6, "ping" },
473 { 7, "ping response" },
474 { 8, "delay" },
475 { 9, "idle" },
476 { 0, NULL },
477 };
478
479 /*
480 * Cache entries we keep around so we can figure out the RX opcode
481 * numbers for replies. This allows us to make sense of RX reply packets.
482 */
483
484 struct rx_cache_entry {
485 uint32_t callnum; /* Call number (net order) */
486 uint32_t client; /* client IP address (net order) */
487 uint32_t server; /* server IP address (net order) */
488 uint16_t dport; /* server UDP port (host order) */
489 uint16_t serviceId; /* Service identifier (net order) */
490 uint32_t opcode; /* RX opcode (host order) */
491 };
492
493 #define RX_CACHE_SIZE 64
494
495 static struct rx_cache_entry rx_cache[RX_CACHE_SIZE];
496
497 static uint32_t rx_cache_next = 0;
498 static uint32_t rx_cache_hint = 0;
499 static void rx_cache_insert(netdissect_options *, const u_char *, const struct ip *, uint16_t);
500 static int rx_cache_find(netdissect_options *, const struct rx_header *,
501 const struct ip *, uint16_t, uint32_t *);
502
503 static void fs_print(netdissect_options *, const u_char *, u_int);
504 static void fs_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
505 static void acl_print(netdissect_options *, u_char *, const u_char *);
506 static void cb_print(netdissect_options *, const u_char *, u_int);
507 static void cb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
508 static void prot_print(netdissect_options *, const u_char *, u_int);
509 static void prot_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
510 static void vldb_print(netdissect_options *, const u_char *, u_int);
511 static void vldb_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
512 static void kauth_print(netdissect_options *, const u_char *, u_int);
513 static void kauth_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
514 static void vol_print(netdissect_options *, const u_char *, u_int);
515 static void vol_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
516 static void bos_print(netdissect_options *, const u_char *, u_int);
517 static void bos_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
518 static void ubik_print(netdissect_options *, const u_char *);
519 static void ubik_reply_print(netdissect_options *, const u_char *, u_int, uint32_t);
520
521 static void rx_ack_print(netdissect_options *, const u_char *, u_int);
522
523 static int is_ubik(uint32_t);
524
525 /*
526 * Handle the rx-level packet. See if we know what port it's going to so
527 * we can peek at the afs call inside
528 */
529
530 void
rx_print(netdissect_options * ndo,const u_char * bp,u_int length,uint16_t sport,uint16_t dport,const u_char * bp2)531 rx_print(netdissect_options *ndo,
532 const u_char *bp, u_int length, uint16_t sport, uint16_t dport,
533 const u_char *bp2)
534 {
535 const struct rx_header *rxh;
536 uint32_t i;
537 uint8_t type, flags;
538 uint32_t opcode;
539
540 ndo->ndo_protocol = "rx";
541 if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
542 ND_PRINT(" [|rx] (%u)", length);
543 return;
544 }
545
546 rxh = (const struct rx_header *) bp;
547
548 type = GET_U_1(rxh->type);
549 ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));
550
551 flags = GET_U_1(rxh->flags);
552 if (ndo->ndo_vflag) {
553 int firstflag = 0;
554
555 if (ndo->ndo_vflag > 1)
556 ND_PRINT(" cid %08x call# %u",
557 GET_BE_U_4(rxh->cid),
558 GET_BE_U_4(rxh->callNumber));
559
560 ND_PRINT(" seq %u ser %u",
561 GET_BE_U_4(rxh->seq),
562 GET_BE_U_4(rxh->serial));
563
564 if (ndo->ndo_vflag > 2)
565 ND_PRINT(" secindex %u serviceid %hu",
566 GET_U_1(rxh->securityIndex),
567 GET_BE_U_2(rxh->serviceId));
568
569 if (ndo->ndo_vflag > 1)
570 for (i = 0; i < NUM_RX_FLAGS; i++) {
571 if (flags & rx_flags[i].flag &&
572 (!rx_flags[i].packetType ||
573 type == rx_flags[i].packetType)) {
574 if (!firstflag) {
575 firstflag = 1;
576 ND_PRINT(" ");
577 } else {
578 ND_PRINT(",");
579 }
580 ND_PRINT("<%s>", rx_flags[i].s);
581 }
582 }
583 }
584
585 /*
586 * Try to handle AFS calls that we know about. Check the destination
587 * port and make sure it's a data packet. Also, make sure the
588 * seq number is 1 (because otherwise it's a continuation packet,
589 * and we can't interpret that). Also, seems that reply packets
590 * do not have the client-init flag set, so we check for that
591 * as well.
592 */
593
594 if (type == RX_PACKET_TYPE_DATA &&
595 GET_BE_U_4(rxh->seq) == 1 &&
596 flags & RX_CLIENT_INITIATED) {
597
598 /*
599 * Insert this call into the call cache table, so we
600 * have a chance to print out replies
601 */
602
603 rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);
604
605 switch (dport) {
606 case FS_RX_PORT: /* AFS file service */
607 fs_print(ndo, bp, length);
608 break;
609 case CB_RX_PORT: /* AFS callback service */
610 cb_print(ndo, bp, length);
611 break;
612 case PROT_RX_PORT: /* AFS protection service */
613 prot_print(ndo, bp, length);
614 break;
615 case VLDB_RX_PORT: /* AFS VLDB service */
616 vldb_print(ndo, bp, length);
617 break;
618 case KAUTH_RX_PORT: /* AFS Kerberos auth service */
619 kauth_print(ndo, bp, length);
620 break;
621 case VOL_RX_PORT: /* AFS Volume service */
622 vol_print(ndo, bp, length);
623 break;
624 case BOS_RX_PORT: /* AFS BOS service */
625 bos_print(ndo, bp, length);
626 break;
627 default:
628 ;
629 }
630
631 /*
632 * If it's a reply (client-init is _not_ set, but seq is one)
633 * then look it up in the cache. If we find it, call the reply
634 * printing functions Note that we handle abort packets here,
635 * because printing out the return code can be useful at times.
636 */
637
638 } else if (((type == RX_PACKET_TYPE_DATA &&
639 GET_BE_U_4(rxh->seq) == 1) ||
640 type == RX_PACKET_TYPE_ABORT) &&
641 (flags & RX_CLIENT_INITIATED) == 0 &&
642 rx_cache_find(ndo, rxh, (const struct ip *) bp2,
643 sport, &opcode)) {
644
645 switch (sport) {
646 case FS_RX_PORT: /* AFS file service */
647 fs_reply_print(ndo, bp, length, opcode);
648 break;
649 case CB_RX_PORT: /* AFS callback service */
650 cb_reply_print(ndo, bp, length, opcode);
651 break;
652 case PROT_RX_PORT: /* AFS PT service */
653 prot_reply_print(ndo, bp, length, opcode);
654 break;
655 case VLDB_RX_PORT: /* AFS VLDB service */
656 vldb_reply_print(ndo, bp, length, opcode);
657 break;
658 case KAUTH_RX_PORT: /* AFS Kerberos auth service */
659 kauth_reply_print(ndo, bp, length, opcode);
660 break;
661 case VOL_RX_PORT: /* AFS Volume service */
662 vol_reply_print(ndo, bp, length, opcode);
663 break;
664 case BOS_RX_PORT: /* AFS BOS service */
665 bos_reply_print(ndo, bp, length, opcode);
666 break;
667 default:
668 ;
669 }
670
671 /*
672 * If it's an RX ack packet, then use the appropriate ack decoding
673 * function (there isn't any service-specific information in the
674 * ack packet, so we can use one for all AFS services)
675 */
676
677 } else if (type == RX_PACKET_TYPE_ACK)
678 rx_ack_print(ndo, bp, length);
679
680
681 ND_PRINT(" (%u)", length);
682 }
683
684 /*
685 * Insert an entry into the cache. Taken from print-nfs.c
686 */
687
688 static void
rx_cache_insert(netdissect_options * ndo,const u_char * bp,const struct ip * ip,uint16_t dport)689 rx_cache_insert(netdissect_options *ndo,
690 const u_char *bp, const struct ip *ip, uint16_t dport)
691 {
692 struct rx_cache_entry *rxent;
693 const struct rx_header *rxh = (const struct rx_header *) bp;
694
695 if (!ND_TTEST_4(bp + sizeof(struct rx_header)))
696 return;
697
698 rxent = &rx_cache[rx_cache_next];
699
700 if (++rx_cache_next >= RX_CACHE_SIZE)
701 rx_cache_next = 0;
702
703 rxent->callnum = GET_BE_U_4(rxh->callNumber);
704 rxent->client = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
705 rxent->server = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
706 rxent->dport = dport;
707 rxent->serviceId = GET_BE_U_2(rxh->serviceId);
708 rxent->opcode = GET_BE_U_4(bp + sizeof(struct rx_header));
709 }
710
711 /*
712 * Lookup an entry in the cache. Also taken from print-nfs.c
713 *
714 * Note that because this is a reply, we're looking at the _source_
715 * port.
716 */
717
718 static int
rx_cache_find(netdissect_options * ndo,const struct rx_header * rxh,const struct ip * ip,uint16_t sport,uint32_t * opcode)719 rx_cache_find(netdissect_options *ndo, const struct rx_header *rxh,
720 const struct ip *ip, uint16_t sport, uint32_t *opcode)
721 {
722 uint32_t i;
723 struct rx_cache_entry *rxent;
724 uint32_t clip;
725 uint32_t sip;
726
727 clip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
728 sip = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
729
730 /* Start the search where we last left off */
731
732 i = rx_cache_hint;
733 do {
734 rxent = &rx_cache[i];
735 if (rxent->callnum == GET_BE_U_4(rxh->callNumber) &&
736 rxent->client == clip &&
737 rxent->server == sip &&
738 rxent->serviceId == GET_BE_U_2(rxh->serviceId) &&
739 rxent->dport == sport) {
740
741 /* We got a match! */
742
743 rx_cache_hint = i;
744 *opcode = rxent->opcode;
745 return(1);
746 }
747 if (++i >= RX_CACHE_SIZE)
748 i = 0;
749 } while (i != rx_cache_hint);
750
751 /* Our search failed */
752 return(0);
753 }
754
755 /*
756 * These extremely grody macros handle the printing of various AFS stuff.
757 */
758
759 #define FIDOUT() { uint32_t n1, n2, n3; \
760 ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
761 n1 = GET_BE_U_4(bp); \
762 bp += sizeof(uint32_t); \
763 n2 = GET_BE_U_4(bp); \
764 bp += sizeof(uint32_t); \
765 n3 = GET_BE_U_4(bp); \
766 bp += sizeof(uint32_t); \
767 ND_PRINT(" fid %u/%u/%u", n1, n2, n3); \
768 }
769
770 #define STROUT(MAX) { uint32_t _i; \
771 _i = GET_BE_U_4(bp); \
772 if (_i > (MAX)) \
773 goto trunc; \
774 bp += sizeof(uint32_t); \
775 ND_PRINT(" \""); \
776 if (nd_printn(ndo, bp, _i, ndo->ndo_snapend)) \
777 goto trunc; \
778 ND_PRINT("\""); \
779 bp += ((_i + sizeof(uint32_t) - 1) / sizeof(uint32_t)) * sizeof(uint32_t); \
780 }
781
782 #define INTOUT() { int32_t _i; \
783 _i = GET_BE_S_4(bp); \
784 bp += sizeof(int32_t); \
785 ND_PRINT(" %d", _i); \
786 }
787
788 #define UINTOUT() { uint32_t _i; \
789 _i = GET_BE_U_4(bp); \
790 bp += sizeof(uint32_t); \
791 ND_PRINT(" %u", _i); \
792 }
793
794 #define UINT64OUT() { uint64_t _i; \
795 _i = GET_BE_U_8(bp); \
796 bp += sizeof(uint64_t); \
797 ND_PRINT(" %" PRIu64, _i); \
798 }
799
800 #define DATEOUT() { time_t _t; char str[256]; \
801 _t = (time_t) GET_BE_S_4(bp); \
802 bp += sizeof(int32_t); \
803 ND_PRINT(" %s", \
804 nd_format_time(str, sizeof(str), \
805 "%Y-%m-%d %H:%M:%S", localtime(&_t))); \
806 }
807
808 #define STOREATTROUT() { uint32_t mask, _i; \
809 ND_TCHECK_LEN(bp, (sizeof(uint32_t) * 6)); \
810 mask = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
811 if (mask) ND_PRINT(" StoreStatus"); \
812 if (mask & 1) { ND_PRINT(" date"); DATEOUT(); } \
813 else bp += sizeof(uint32_t); \
814 _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
815 if (mask & 2) ND_PRINT(" owner %u", _i); \
816 _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
817 if (mask & 4) ND_PRINT(" group %u", _i); \
818 _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
819 if (mask & 8) ND_PRINT(" mode %o", _i & 07777); \
820 _i = GET_BE_U_4(bp); bp += sizeof(uint32_t); \
821 if (mask & 16) ND_PRINT(" segsize %u", _i); \
822 /* undocumented in 3.3 docu */ \
823 if (mask & 1024) ND_PRINT(" fsync"); \
824 }
825
826 #define UBIK_VERSIONOUT() {uint32_t epoch; uint32_t counter; \
827 ND_TCHECK_LEN(bp, sizeof(uint32_t) * 2); \
828 epoch = GET_BE_U_4(bp); \
829 bp += sizeof(uint32_t); \
830 counter = GET_BE_U_4(bp); \
831 bp += sizeof(uint32_t); \
832 ND_PRINT(" %u.%u", epoch, counter); \
833 }
834
835 #define AFSUUIDOUT() {uint32_t temp; int _i; \
836 ND_TCHECK_LEN(bp, 11 * sizeof(uint32_t)); \
837 temp = GET_BE_U_4(bp); \
838 bp += sizeof(uint32_t); \
839 ND_PRINT(" %08x", temp); \
840 temp = GET_BE_U_4(bp); \
841 bp += sizeof(uint32_t); \
842 ND_PRINT("%04x", temp); \
843 temp = GET_BE_U_4(bp); \
844 bp += sizeof(uint32_t); \
845 ND_PRINT("%04x", temp); \
846 for (_i = 0; _i < 8; _i++) { \
847 temp = GET_BE_U_4(bp); \
848 bp += sizeof(uint32_t); \
849 ND_PRINT("%02x", (unsigned char) temp); \
850 } \
851 }
852
853 /*
854 * This is the sickest one of all
855 * MAX is expected to be a constant here
856 */
857
858 #define VECOUT(MAX) { u_char *sp; \
859 u_char s[(MAX) + 1]; \
860 uint32_t k; \
861 ND_TCHECK_LEN(bp, (MAX) * sizeof(uint32_t)); \
862 sp = s; \
863 for (k = 0; k < (MAX); k++) { \
864 *sp++ = (u_char) GET_BE_U_4(bp); \
865 bp += sizeof(uint32_t); \
866 } \
867 s[(MAX)] = '\0'; \
868 ND_PRINT(" \""); \
869 fn_print_str(ndo, s); \
870 ND_PRINT("\""); \
871 }
872
873 #define DESTSERVEROUT() { uint32_t n1, n2, n3; \
874 ND_TCHECK_LEN(bp, sizeof(uint32_t) * 3); \
875 n1 = GET_BE_U_4(bp); \
876 bp += sizeof(uint32_t); \
877 n2 = GET_BE_U_4(bp); \
878 bp += sizeof(uint32_t); \
879 n3 = GET_BE_U_4(bp); \
880 bp += sizeof(uint32_t); \
881 ND_PRINT(" server %u:%u:%u", n1, n2, n3); \
882 }
883
884 /*
885 * Handle calls to the AFS file service (fs)
886 */
887
888 static void
fs_print(netdissect_options * ndo,const u_char * bp,u_int length)889 fs_print(netdissect_options *ndo,
890 const u_char *bp, u_int length)
891 {
892 uint32_t fs_op;
893 uint32_t i;
894
895 if (length <= sizeof(struct rx_header))
896 return;
897
898 /*
899 * Print out the afs call we're invoking. The table used here was
900 * gleaned from fsint/afsint.xg
901 */
902
903 fs_op = GET_BE_U_4(bp + sizeof(struct rx_header));
904
905 ND_PRINT(" fs call %s", tok2str(fs_req, "op#%u", fs_op));
906
907 /*
908 * Print out arguments to some of the AFS calls. This stuff is
909 * all from afsint.xg
910 */
911
912 bp += sizeof(struct rx_header) + 4;
913
914 /*
915 * Sigh. This is gross. Ritchie forgive me.
916 */
917
918 switch (fs_op) {
919 case 130: /* Fetch data */
920 FIDOUT();
921 ND_PRINT(" offset");
922 UINTOUT();
923 ND_PRINT(" length");
924 UINTOUT();
925 break;
926 case 131: /* Fetch ACL */
927 case 132: /* Fetch Status */
928 case 143: /* Old set lock */
929 case 144: /* Old extend lock */
930 case 145: /* Old release lock */
931 case 156: /* Set lock */
932 case 157: /* Extend lock */
933 case 158: /* Release lock */
934 FIDOUT();
935 break;
936 case 135: /* Store status */
937 FIDOUT();
938 STOREATTROUT();
939 break;
940 case 133: /* Store data */
941 FIDOUT();
942 STOREATTROUT();
943 ND_PRINT(" offset");
944 UINTOUT();
945 ND_PRINT(" length");
946 UINTOUT();
947 ND_PRINT(" flen");
948 UINTOUT();
949 break;
950 case 134: /* Store ACL */
951 {
952 char a[AFSOPAQUEMAX+1];
953 FIDOUT();
954 i = GET_BE_U_4(bp);
955 bp += sizeof(uint32_t);
956 ND_TCHECK_LEN(bp, i);
957 i = ND_MIN(AFSOPAQUEMAX, i);
958 strncpy(a, (const char *) bp, i);
959 a[i] = '\0';
960 acl_print(ndo, (u_char *) a, (u_char *) a + i);
961 break;
962 }
963 case 137: /* Create file */
964 case 141: /* MakeDir */
965 FIDOUT();
966 STROUT(AFSNAMEMAX);
967 STOREATTROUT();
968 break;
969 case 136: /* Remove file */
970 case 142: /* Remove directory */
971 FIDOUT();
972 STROUT(AFSNAMEMAX);
973 break;
974 case 138: /* Rename file */
975 ND_PRINT(" old");
976 FIDOUT();
977 STROUT(AFSNAMEMAX);
978 ND_PRINT(" new");
979 FIDOUT();
980 STROUT(AFSNAMEMAX);
981 break;
982 case 139: /* Symlink */
983 FIDOUT();
984 STROUT(AFSNAMEMAX);
985 ND_PRINT(" link to");
986 STROUT(AFSNAMEMAX);
987 break;
988 case 140: /* Link */
989 FIDOUT();
990 STROUT(AFSNAMEMAX);
991 ND_PRINT(" link to");
992 FIDOUT();
993 break;
994 case 148: /* Get volume info */
995 STROUT(AFSNAMEMAX);
996 break;
997 case 149: /* Get volume stats */
998 case 150: /* Set volume stats */
999 ND_PRINT(" volid");
1000 UINTOUT();
1001 break;
1002 case 154: /* New get volume info */
1003 ND_PRINT(" volname");
1004 STROUT(AFSNAMEMAX);
1005 break;
1006 case 155: /* Bulk stat */
1007 case 65536: /* Inline bulk stat */
1008 {
1009 uint32_t j;
1010 j = GET_BE_U_4(bp);
1011 bp += sizeof(uint32_t);
1012
1013 for (i = 0; i < j; i++) {
1014 FIDOUT();
1015 if (i != j - 1)
1016 ND_PRINT(",");
1017 }
1018 if (j == 0)
1019 ND_PRINT(" <none!>");
1020 break;
1021 }
1022 case 65537: /* Fetch data 64 */
1023 FIDOUT();
1024 ND_PRINT(" offset");
1025 UINT64OUT();
1026 ND_PRINT(" length");
1027 UINT64OUT();
1028 break;
1029 case 65538: /* Store data 64 */
1030 FIDOUT();
1031 STOREATTROUT();
1032 ND_PRINT(" offset");
1033 UINT64OUT();
1034 ND_PRINT(" length");
1035 UINT64OUT();
1036 ND_PRINT(" flen");
1037 UINT64OUT();
1038 break;
1039 case 65541: /* CallBack rx conn address */
1040 ND_PRINT(" addr");
1041 UINTOUT();
1042 default:
1043 ;
1044 }
1045
1046 return;
1047
1048 trunc:
1049 ND_PRINT(" [|fs]");
1050 }
1051
1052 /*
1053 * Handle replies to the AFS file service
1054 */
1055
1056 static void
fs_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1057 fs_reply_print(netdissect_options *ndo,
1058 const u_char *bp, u_int length, uint32_t opcode)
1059 {
1060 uint32_t i;
1061 const struct rx_header *rxh;
1062 uint8_t type;
1063
1064 if (length <= sizeof(struct rx_header))
1065 return;
1066
1067 rxh = (const struct rx_header *) bp;
1068
1069 /*
1070 * Print out the afs call we're invoking. The table used here was
1071 * gleaned from fsint/afsint.xg
1072 */
1073
1074 ND_PRINT(" fs reply %s", tok2str(fs_req, "op#%u", opcode));
1075
1076 type = GET_U_1(rxh->type);
1077 bp += sizeof(struct rx_header);
1078
1079 /*
1080 * If it was a data packet, interpret the response
1081 */
1082
1083 if (type == RX_PACKET_TYPE_DATA) {
1084 switch (opcode) {
1085 case 131: /* Fetch ACL */
1086 {
1087 char a[AFSOPAQUEMAX+1];
1088 i = GET_BE_U_4(bp);
1089 bp += sizeof(uint32_t);
1090 ND_TCHECK_LEN(bp, i);
1091 i = ND_MIN(AFSOPAQUEMAX, i);
1092 strncpy(a, (const char *) bp, i);
1093 a[i] = '\0';
1094 acl_print(ndo, (u_char *) a, (u_char *) a + i);
1095 break;
1096 }
1097 case 137: /* Create file */
1098 case 141: /* MakeDir */
1099 ND_PRINT(" new");
1100 FIDOUT();
1101 break;
1102 case 151: /* Get root volume */
1103 ND_PRINT(" root volume");
1104 STROUT(AFSNAMEMAX);
1105 break;
1106 case 153: /* Get time */
1107 DATEOUT();
1108 break;
1109 default:
1110 ;
1111 }
1112 } else if (type == RX_PACKET_TYPE_ABORT) {
1113 /*
1114 * Otherwise, just print out the return code
1115 */
1116 int32_t errcode;
1117
1118 errcode = GET_BE_S_4(bp);
1119 bp += sizeof(int32_t);
1120
1121 ND_PRINT(" error %s", tok2str(afs_fs_errors, "#%d", errcode));
1122 } else {
1123 ND_PRINT(" strange fs reply of type %u", type);
1124 }
1125
1126 return;
1127
1128 trunc:
1129 ND_PRINT(" [|fs]");
1130 }
1131
1132 /*
1133 * Print out an AFS ACL string. An AFS ACL is a string that has the
1134 * following format:
1135 *
1136 * <positive> <negative>
1137 * <uid1> <aclbits1>
1138 * ....
1139 *
1140 * "positive" and "negative" are integers which contain the number of
1141 * positive and negative ACL's in the string. The uid/aclbits pair are
1142 * ASCII strings containing the UID/PTS record and an ASCII number
1143 * representing a logical OR of all the ACL permission bits
1144 */
1145
1146 #define XSTRINGIFY(x) #x
1147 #define NUMSTRINGIFY(x) XSTRINGIFY(x)
1148
1149 static void
acl_print(netdissect_options * ndo,u_char * s,const u_char * end)1150 acl_print(netdissect_options *ndo,
1151 u_char *s, const u_char *end)
1152 {
1153 int pos, neg, acl;
1154 int n, i;
1155 char user[USERNAMEMAX+1];
1156
1157 if (sscanf((char *) s, "%d %d\n%n", &pos, &neg, &n) != 2)
1158 return;
1159
1160 s += n;
1161
1162 if (s > end)
1163 return;
1164
1165 /*
1166 * This wacky order preserves the order used by the "fs" command
1167 */
1168
1169 #define ACLOUT(acl) \
1170 ND_PRINT("%s%s%s%s%s%s%s", \
1171 acl & PRSFS_READ ? "r" : "", \
1172 acl & PRSFS_LOOKUP ? "l" : "", \
1173 acl & PRSFS_INSERT ? "i" : "", \
1174 acl & PRSFS_DELETE ? "d" : "", \
1175 acl & PRSFS_WRITE ? "w" : "", \
1176 acl & PRSFS_LOCK ? "k" : "", \
1177 acl & PRSFS_ADMINISTER ? "a" : "");
1178
1179 for (i = 0; i < pos; i++) {
1180 if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1181 return;
1182 s += n;
1183 ND_PRINT(" +{");
1184 fn_print_str(ndo, (u_char *)user);
1185 ND_PRINT(" ");
1186 ACLOUT(acl);
1187 ND_PRINT("}");
1188 if (s > end)
1189 return;
1190 }
1191
1192 for (i = 0; i < neg; i++) {
1193 if (sscanf((char *) s, "%" NUMSTRINGIFY(USERNAMEMAX) "s %d\n%n", user, &acl, &n) != 2)
1194 return;
1195 s += n;
1196 ND_PRINT(" -{");
1197 fn_print_str(ndo, (u_char *)user);
1198 ND_PRINT(" ");
1199 ACLOUT(acl);
1200 ND_PRINT("}");
1201 if (s > end)
1202 return;
1203 }
1204 }
1205
1206 #undef ACLOUT
1207
1208 /*
1209 * Handle calls to the AFS callback service
1210 */
1211
1212 static void
cb_print(netdissect_options * ndo,const u_char * bp,u_int length)1213 cb_print(netdissect_options *ndo,
1214 const u_char *bp, u_int length)
1215 {
1216 uint32_t cb_op;
1217 uint32_t i;
1218
1219 if (length <= sizeof(struct rx_header))
1220 return;
1221
1222 /*
1223 * Print out the afs call we're invoking. The table used here was
1224 * gleaned from fsint/afscbint.xg
1225 */
1226
1227 cb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1228
1229 ND_PRINT(" cb call %s", tok2str(cb_req, "op#%u", cb_op));
1230
1231 bp += sizeof(struct rx_header) + 4;
1232
1233 /*
1234 * Print out the afs call we're invoking. The table used here was
1235 * gleaned from fsint/afscbint.xg
1236 */
1237
1238 switch (cb_op) {
1239 case 204: /* Callback */
1240 {
1241 uint32_t j, t;
1242 j = GET_BE_U_4(bp);
1243 bp += sizeof(uint32_t);
1244
1245 for (i = 0; i < j; i++) {
1246 FIDOUT();
1247 if (i != j - 1)
1248 ND_PRINT(",");
1249 }
1250
1251 if (j == 0)
1252 ND_PRINT(" <none!>");
1253
1254 j = GET_BE_U_4(bp);
1255 bp += sizeof(uint32_t);
1256
1257 if (j != 0)
1258 ND_PRINT(";");
1259
1260 for (i = 0; i < j; i++) {
1261 ND_PRINT(" ver");
1262 INTOUT();
1263 ND_PRINT(" expires");
1264 DATEOUT();
1265 t = GET_BE_U_4(bp);
1266 bp += sizeof(uint32_t);
1267 tok2str(cb_types, "type %u", t);
1268 }
1269 break;
1270 }
1271 case 214: {
1272 ND_PRINT(" afsuuid");
1273 AFSUUIDOUT();
1274 break;
1275 }
1276 default:
1277 ;
1278 }
1279
1280 return;
1281
1282 trunc:
1283 ND_PRINT(" [|cb]");
1284 }
1285
1286 /*
1287 * Handle replies to the AFS Callback Service
1288 */
1289
1290 static void
cb_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1291 cb_reply_print(netdissect_options *ndo,
1292 const u_char *bp, u_int length, uint32_t opcode)
1293 {
1294 const struct rx_header *rxh;
1295 uint8_t type;
1296
1297 if (length <= sizeof(struct rx_header))
1298 return;
1299
1300 rxh = (const struct rx_header *) bp;
1301
1302 /*
1303 * Print out the afs call we're invoking. The table used here was
1304 * gleaned from fsint/afscbint.xg
1305 */
1306
1307 ND_PRINT(" cb reply %s", tok2str(cb_req, "op#%u", opcode));
1308
1309 type = GET_U_1(rxh->type);
1310 bp += sizeof(struct rx_header);
1311
1312 /*
1313 * If it was a data packet, interpret the response.
1314 */
1315
1316 if (type == RX_PACKET_TYPE_DATA)
1317 switch (opcode) {
1318 case 213: /* InitCallBackState3 */
1319 AFSUUIDOUT();
1320 break;
1321 default:
1322 ;
1323 }
1324 else {
1325 /*
1326 * Otherwise, just print out the return code
1327 */
1328 ND_PRINT(" errcode");
1329 INTOUT();
1330 }
1331
1332 return;
1333
1334 trunc:
1335 ND_PRINT(" [|cb]");
1336 }
1337
1338 /*
1339 * Handle calls to the AFS protection database server
1340 */
1341
1342 static void
prot_print(netdissect_options * ndo,const u_char * bp,u_int length)1343 prot_print(netdissect_options *ndo,
1344 const u_char *bp, u_int length)
1345 {
1346 uint32_t i;
1347 uint32_t pt_op;
1348
1349 if (length <= sizeof(struct rx_header))
1350 return;
1351
1352 /*
1353 * Print out the afs call we're invoking. The table used here was
1354 * gleaned from ptserver/ptint.xg
1355 */
1356
1357 pt_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1358
1359 ND_PRINT(" pt");
1360
1361 if (is_ubik(pt_op)) {
1362 ubik_print(ndo, bp);
1363 return;
1364 }
1365
1366 ND_PRINT(" call %s", tok2str(pt_req, "op#%u", pt_op));
1367
1368 /*
1369 * Decode some of the arguments to the PT calls
1370 */
1371
1372 bp += sizeof(struct rx_header) + 4;
1373
1374 switch (pt_op) {
1375 case 500: /* I New User */
1376 STROUT(PRNAMEMAX);
1377 ND_PRINT(" id");
1378 INTOUT();
1379 ND_PRINT(" oldid");
1380 INTOUT();
1381 break;
1382 case 501: /* Where is it */
1383 case 506: /* Delete */
1384 case 508: /* Get CPS */
1385 case 512: /* List entry */
1386 case 514: /* List elements */
1387 case 517: /* List owned */
1388 case 518: /* Get CPS2 */
1389 case 519: /* Get host CPS */
1390 case 530: /* List super groups */
1391 ND_PRINT(" id");
1392 INTOUT();
1393 break;
1394 case 502: /* Dump entry */
1395 ND_PRINT(" pos");
1396 INTOUT();
1397 break;
1398 case 503: /* Add to group */
1399 case 507: /* Remove from group */
1400 case 515: /* Is a member of? */
1401 ND_PRINT(" uid");
1402 INTOUT();
1403 ND_PRINT(" gid");
1404 INTOUT();
1405 break;
1406 case 504: /* Name to ID */
1407 {
1408 uint32_t j;
1409 j = GET_BE_U_4(bp);
1410 bp += sizeof(uint32_t);
1411
1412 /*
1413 * Who designed this chicken-shit protocol?
1414 *
1415 * Each character is stored as a 32-bit
1416 * integer!
1417 */
1418
1419 for (i = 0; i < j; i++) {
1420 VECOUT(PRNAMEMAX);
1421 }
1422 if (j == 0)
1423 ND_PRINT(" <none!>");
1424 }
1425 break;
1426 case 505: /* Id to name */
1427 {
1428 uint32_t j;
1429 ND_PRINT(" ids:");
1430 i = GET_BE_U_4(bp);
1431 bp += sizeof(uint32_t);
1432 for (j = 0; j < i; j++)
1433 INTOUT();
1434 if (j == 0)
1435 ND_PRINT(" <none!>");
1436 }
1437 break;
1438 case 509: /* New entry */
1439 STROUT(PRNAMEMAX);
1440 ND_PRINT(" flag");
1441 INTOUT();
1442 ND_PRINT(" oid");
1443 INTOUT();
1444 break;
1445 case 511: /* Set max */
1446 ND_PRINT(" id");
1447 INTOUT();
1448 ND_PRINT(" gflag");
1449 INTOUT();
1450 break;
1451 case 513: /* Change entry */
1452 ND_PRINT(" id");
1453 INTOUT();
1454 STROUT(PRNAMEMAX);
1455 ND_PRINT(" oldid");
1456 INTOUT();
1457 ND_PRINT(" newid");
1458 INTOUT();
1459 break;
1460 case 520: /* Update entry */
1461 ND_PRINT(" id");
1462 INTOUT();
1463 STROUT(PRNAMEMAX);
1464 break;
1465 default:
1466 ;
1467 }
1468
1469
1470 return;
1471
1472 trunc:
1473 ND_PRINT(" [|pt]");
1474 }
1475
1476 /*
1477 * Handle replies to the AFS protection service
1478 */
1479
1480 static void
prot_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1481 prot_reply_print(netdissect_options *ndo,
1482 const u_char *bp, u_int length, uint32_t opcode)
1483 {
1484 const struct rx_header *rxh;
1485 uint8_t type;
1486 uint32_t i;
1487
1488 if (length < sizeof(struct rx_header))
1489 return;
1490
1491 rxh = (const struct rx_header *) bp;
1492
1493 /*
1494 * Print out the afs call we're invoking. The table used here was
1495 * gleaned from ptserver/ptint.xg. Check to see if it's a
1496 * Ubik call, however.
1497 */
1498
1499 ND_PRINT(" pt");
1500
1501 if (is_ubik(opcode)) {
1502 ubik_reply_print(ndo, bp, length, opcode);
1503 return;
1504 }
1505
1506 ND_PRINT(" reply %s", tok2str(pt_req, "op#%u", opcode));
1507
1508 type = GET_U_1(rxh->type);
1509 bp += sizeof(struct rx_header);
1510
1511 /*
1512 * If it was a data packet, interpret the response
1513 */
1514
1515 if (type == RX_PACKET_TYPE_DATA)
1516 switch (opcode) {
1517 case 504: /* Name to ID */
1518 {
1519 uint32_t j;
1520 ND_PRINT(" ids:");
1521 i = GET_BE_U_4(bp);
1522 bp += sizeof(uint32_t);
1523 for (j = 0; j < i; j++)
1524 INTOUT();
1525 if (j == 0)
1526 ND_PRINT(" <none!>");
1527 }
1528 break;
1529 case 505: /* ID to name */
1530 {
1531 uint32_t j;
1532 j = GET_BE_U_4(bp);
1533 bp += sizeof(uint32_t);
1534
1535 /*
1536 * Who designed this chicken-shit protocol?
1537 *
1538 * Each character is stored as a 32-bit
1539 * integer!
1540 */
1541
1542 for (i = 0; i < j; i++) {
1543 VECOUT(PRNAMEMAX);
1544 }
1545 if (j == 0)
1546 ND_PRINT(" <none!>");
1547 }
1548 break;
1549 case 508: /* Get CPS */
1550 case 514: /* List elements */
1551 case 517: /* List owned */
1552 case 518: /* Get CPS2 */
1553 case 519: /* Get host CPS */
1554 {
1555 uint32_t j;
1556 j = GET_BE_U_4(bp);
1557 bp += sizeof(uint32_t);
1558 for (i = 0; i < j; i++) {
1559 INTOUT();
1560 }
1561 if (j == 0)
1562 ND_PRINT(" <none!>");
1563 }
1564 break;
1565 case 510: /* List max */
1566 ND_PRINT(" maxuid");
1567 INTOUT();
1568 ND_PRINT(" maxgid");
1569 INTOUT();
1570 break;
1571 default:
1572 ;
1573 }
1574 else {
1575 /*
1576 * Otherwise, just print out the return code
1577 */
1578 ND_PRINT(" errcode");
1579 INTOUT();
1580 }
1581
1582 return;
1583
1584 trunc:
1585 ND_PRINT(" [|pt]");
1586 }
1587
1588 /*
1589 * Handle calls to the AFS volume location database service
1590 */
1591
1592 static void
vldb_print(netdissect_options * ndo,const u_char * bp,u_int length)1593 vldb_print(netdissect_options *ndo,
1594 const u_char *bp, u_int length)
1595 {
1596 uint32_t vldb_op;
1597 uint32_t i;
1598
1599 if (length <= sizeof(struct rx_header))
1600 return;
1601
1602 /*
1603 * Print out the afs call we're invoking. The table used here was
1604 * gleaned from vlserver/vldbint.xg
1605 */
1606
1607 vldb_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1608
1609 ND_PRINT(" vldb");
1610
1611 if (is_ubik(vldb_op)) {
1612 ubik_print(ndo, bp);
1613 return;
1614 }
1615 ND_PRINT(" call %s", tok2str(vldb_req, "op#%u", vldb_op));
1616
1617 /*
1618 * Decode some of the arguments to the VLDB calls
1619 */
1620
1621 bp += sizeof(struct rx_header) + 4;
1622
1623 switch (vldb_op) {
1624 case 501: /* Create new volume */
1625 case 517: /* Create entry N */
1626 VECOUT(VLNAMEMAX);
1627 break;
1628 case 502: /* Delete entry */
1629 case 503: /* Get entry by ID */
1630 case 507: /* Update entry */
1631 case 508: /* Set lock */
1632 case 509: /* Release lock */
1633 case 518: /* Get entry by ID N */
1634 ND_PRINT(" volid");
1635 INTOUT();
1636 i = GET_BE_U_4(bp);
1637 bp += sizeof(uint32_t);
1638 if (i <= 2)
1639 ND_PRINT(" type %s", voltype[i]);
1640 break;
1641 case 504: /* Get entry by name */
1642 case 519: /* Get entry by name N */
1643 case 524: /* Update entry by name */
1644 case 527: /* Get entry by name U */
1645 STROUT(VLNAMEMAX);
1646 break;
1647 case 505: /* Get new vol id */
1648 ND_PRINT(" bump");
1649 INTOUT();
1650 break;
1651 case 506: /* Replace entry */
1652 case 520: /* Replace entry N */
1653 ND_PRINT(" volid");
1654 INTOUT();
1655 i = GET_BE_U_4(bp);
1656 bp += sizeof(uint32_t);
1657 if (i <= 2)
1658 ND_PRINT(" type %s", voltype[i]);
1659 VECOUT(VLNAMEMAX);
1660 break;
1661 case 510: /* List entry */
1662 case 521: /* List entry N */
1663 ND_PRINT(" index");
1664 INTOUT();
1665 break;
1666 default:
1667 ;
1668 }
1669
1670 return;
1671
1672 trunc:
1673 ND_PRINT(" [|vldb]");
1674 }
1675
1676 /*
1677 * Handle replies to the AFS volume location database service
1678 */
1679
1680 static void
vldb_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1681 vldb_reply_print(netdissect_options *ndo,
1682 const u_char *bp, u_int length, uint32_t opcode)
1683 {
1684 const struct rx_header *rxh;
1685 uint8_t type;
1686 uint32_t i;
1687
1688 if (length < sizeof(struct rx_header))
1689 return;
1690
1691 rxh = (const struct rx_header *) bp;
1692
1693 /*
1694 * Print out the afs call we're invoking. The table used here was
1695 * gleaned from vlserver/vldbint.xg. Check to see if it's a
1696 * Ubik call, however.
1697 */
1698
1699 ND_PRINT(" vldb");
1700
1701 if (is_ubik(opcode)) {
1702 ubik_reply_print(ndo, bp, length, opcode);
1703 return;
1704 }
1705
1706 ND_PRINT(" reply %s", tok2str(vldb_req, "op#%u", opcode));
1707
1708 type = GET_U_1(rxh->type);
1709 bp += sizeof(struct rx_header);
1710
1711 /*
1712 * If it was a data packet, interpret the response
1713 */
1714
1715 if (type == RX_PACKET_TYPE_DATA)
1716 switch (opcode) {
1717 case 510: /* List entry */
1718 ND_PRINT(" count");
1719 INTOUT();
1720 ND_PRINT(" nextindex");
1721 INTOUT();
1722 ND_FALL_THROUGH;
1723 case 503: /* Get entry by id */
1724 case 504: /* Get entry by name */
1725 { uint32_t nservers, j;
1726 VECOUT(VLNAMEMAX);
1727 ND_TCHECK_4(bp);
1728 bp += sizeof(uint32_t);
1729 ND_PRINT(" numservers");
1730 nservers = GET_BE_U_4(bp);
1731 bp += sizeof(uint32_t);
1732 ND_PRINT(" %u", nservers);
1733 ND_PRINT(" servers");
1734 for (i = 0; i < 8; i++) {
1735 ND_TCHECK_4(bp);
1736 if (i < nservers)
1737 ND_PRINT(" %s",
1738 intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1739 bp += sizeof(nd_ipv4);
1740 }
1741 ND_PRINT(" partitions");
1742 for (i = 0; i < 8; i++) {
1743 j = GET_BE_U_4(bp);
1744 if (i < nservers && j <= 26)
1745 ND_PRINT(" %c", 'a' + j);
1746 else if (i < nservers)
1747 ND_PRINT(" %u", j);
1748 bp += sizeof(uint32_t);
1749 }
1750 ND_TCHECK_LEN(bp, 8 * sizeof(uint32_t));
1751 bp += 8 * sizeof(uint32_t);
1752 ND_PRINT(" rwvol");
1753 UINTOUT();
1754 ND_PRINT(" rovol");
1755 UINTOUT();
1756 ND_PRINT(" backup");
1757 UINTOUT();
1758 }
1759 break;
1760 case 505: /* Get new volume ID */
1761 ND_PRINT(" newvol");
1762 UINTOUT();
1763 break;
1764 case 521: /* List entry */
1765 case 529: /* List entry U */
1766 ND_PRINT(" count");
1767 INTOUT();
1768 ND_PRINT(" nextindex");
1769 INTOUT();
1770 ND_FALL_THROUGH;
1771 case 518: /* Get entry by ID N */
1772 case 519: /* Get entry by name N */
1773 { uint32_t nservers, j;
1774 VECOUT(VLNAMEMAX);
1775 ND_PRINT(" numservers");
1776 nservers = GET_BE_U_4(bp);
1777 bp += sizeof(uint32_t);
1778 ND_PRINT(" %u", nservers);
1779 ND_PRINT(" servers");
1780 for (i = 0; i < 13; i++) {
1781 ND_TCHECK_4(bp);
1782 if (i < nservers)
1783 ND_PRINT(" %s",
1784 intoa(GET_IPV4_TO_NETWORK_ORDER(bp)));
1785 bp += sizeof(nd_ipv4);
1786 }
1787 ND_PRINT(" partitions");
1788 for (i = 0; i < 13; i++) {
1789 j = GET_BE_U_4(bp);
1790 if (i < nservers && j <= 26)
1791 ND_PRINT(" %c", 'a' + j);
1792 else if (i < nservers)
1793 ND_PRINT(" %u", j);
1794 bp += sizeof(uint32_t);
1795 }
1796 ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1797 bp += 13 * sizeof(uint32_t);
1798 ND_PRINT(" rwvol");
1799 UINTOUT();
1800 ND_PRINT(" rovol");
1801 UINTOUT();
1802 ND_PRINT(" backup");
1803 UINTOUT();
1804 }
1805 break;
1806 case 526: /* Get entry by ID U */
1807 case 527: /* Get entry by name U */
1808 { uint32_t nservers, j;
1809 VECOUT(VLNAMEMAX);
1810 ND_PRINT(" numservers");
1811 nservers = GET_BE_U_4(bp);
1812 bp += sizeof(uint32_t);
1813 ND_PRINT(" %u", nservers);
1814 ND_PRINT(" servers");
1815 for (i = 0; i < 13; i++) {
1816 if (i < nservers) {
1817 ND_PRINT(" afsuuid");
1818 AFSUUIDOUT();
1819 } else {
1820 ND_TCHECK_LEN(bp, 44);
1821 bp += 44;
1822 }
1823 }
1824 ND_TCHECK_LEN(bp, 4 * 13);
1825 bp += 4 * 13;
1826 ND_PRINT(" partitions");
1827 for (i = 0; i < 13; i++) {
1828 j = GET_BE_U_4(bp);
1829 if (i < nservers && j <= 26)
1830 ND_PRINT(" %c", 'a' + j);
1831 else if (i < nservers)
1832 ND_PRINT(" %u", j);
1833 bp += sizeof(uint32_t);
1834 }
1835 ND_TCHECK_LEN(bp, 13 * sizeof(uint32_t));
1836 bp += 13 * sizeof(uint32_t);
1837 ND_PRINT(" rwvol");
1838 UINTOUT();
1839 ND_PRINT(" rovol");
1840 UINTOUT();
1841 ND_PRINT(" backup");
1842 UINTOUT();
1843 }
1844 default:
1845 ;
1846 }
1847
1848 else {
1849 /*
1850 * Otherwise, just print out the return code
1851 */
1852 ND_PRINT(" errcode");
1853 INTOUT();
1854 }
1855
1856 return;
1857
1858 trunc:
1859 ND_PRINT(" [|vldb]");
1860 }
1861
1862 /*
1863 * Handle calls to the AFS Kerberos Authentication service
1864 */
1865
1866 static void
kauth_print(netdissect_options * ndo,const u_char * bp,u_int length)1867 kauth_print(netdissect_options *ndo,
1868 const u_char *bp, u_int length)
1869 {
1870 uint32_t kauth_op;
1871
1872 if (length <= sizeof(struct rx_header))
1873 return;
1874
1875 /*
1876 * Print out the afs call we're invoking. The table used here was
1877 * gleaned from kauth/kauth.rg
1878 */
1879
1880 kauth_op = GET_BE_U_4(bp + sizeof(struct rx_header));
1881
1882 ND_PRINT(" kauth");
1883
1884 if (is_ubik(kauth_op)) {
1885 ubik_print(ndo, bp);
1886 return;
1887 }
1888
1889
1890 ND_PRINT(" call %s", tok2str(kauth_req, "op#%u", kauth_op));
1891
1892 /*
1893 * Decode some of the arguments to the KA calls
1894 */
1895
1896 bp += sizeof(struct rx_header) + 4;
1897
1898 switch (kauth_op) {
1899 case 1: /* Authenticate old */
1900 case 21: /* Authenticate */
1901 case 22: /* Authenticate-V2 */
1902 case 2: /* Change PW */
1903 case 5: /* Set fields */
1904 case 6: /* Create user */
1905 case 7: /* Delete user */
1906 case 8: /* Get entry */
1907 case 14: /* Unlock */
1908 case 15: /* Lock status */
1909 ND_PRINT(" principal");
1910 STROUT(KANAMEMAX);
1911 STROUT(KANAMEMAX);
1912 break;
1913 case 3: /* GetTicket-old */
1914 case 23: /* GetTicket */
1915 {
1916 uint32_t i;
1917 ND_PRINT(" kvno");
1918 INTOUT();
1919 ND_PRINT(" domain");
1920 STROUT(KANAMEMAX);
1921 i = GET_BE_U_4(bp);
1922 bp += sizeof(uint32_t);
1923 ND_TCHECK_LEN(bp, i);
1924 bp += i;
1925 ND_PRINT(" principal");
1926 STROUT(KANAMEMAX);
1927 STROUT(KANAMEMAX);
1928 break;
1929 }
1930 case 4: /* Set Password */
1931 ND_PRINT(" principal");
1932 STROUT(KANAMEMAX);
1933 STROUT(KANAMEMAX);
1934 ND_PRINT(" kvno");
1935 INTOUT();
1936 break;
1937 case 12: /* Get password */
1938 ND_PRINT(" name");
1939 STROUT(KANAMEMAX);
1940 break;
1941 default:
1942 ;
1943 }
1944
1945 return;
1946
1947 trunc:
1948 ND_PRINT(" [|kauth]");
1949 }
1950
1951 /*
1952 * Handle replies to the AFS Kerberos Authentication Service
1953 */
1954
1955 static void
kauth_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)1956 kauth_reply_print(netdissect_options *ndo,
1957 const u_char *bp, u_int length, uint32_t opcode)
1958 {
1959 const struct rx_header *rxh;
1960 uint8_t type;
1961
1962 if (length <= sizeof(struct rx_header))
1963 return;
1964
1965 rxh = (const struct rx_header *) bp;
1966
1967 /*
1968 * Print out the afs call we're invoking. The table used here was
1969 * gleaned from kauth/kauth.rg
1970 */
1971
1972 ND_PRINT(" kauth");
1973
1974 if (is_ubik(opcode)) {
1975 ubik_reply_print(ndo, bp, length, opcode);
1976 return;
1977 }
1978
1979 ND_PRINT(" reply %s", tok2str(kauth_req, "op#%u", opcode));
1980
1981 type = GET_U_1(rxh->type);
1982 bp += sizeof(struct rx_header);
1983
1984 /*
1985 * If it was a data packet, interpret the response.
1986 */
1987
1988 if (type == RX_PACKET_TYPE_DATA)
1989 /* Well, no, not really. Leave this for later */
1990 ;
1991 else {
1992 /*
1993 * Otherwise, just print out the return code
1994 */
1995 ND_PRINT(" errcode");
1996 INTOUT();
1997 }
1998 }
1999
2000 /*
2001 * Handle calls to the AFS Volume location service
2002 */
2003
2004 static void
vol_print(netdissect_options * ndo,const u_char * bp,u_int length)2005 vol_print(netdissect_options *ndo,
2006 const u_char *bp, u_int length)
2007 {
2008 uint32_t vol_op;
2009
2010 if (length <= sizeof(struct rx_header))
2011 return;
2012
2013 /*
2014 * Print out the afs call we're invoking. The table used here was
2015 * gleaned from volser/volint.xg
2016 */
2017
2018 vol_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2019
2020 ND_PRINT(" vol call %s", tok2str(vol_req, "op#%u", vol_op));
2021
2022 bp += sizeof(struct rx_header) + 4;
2023
2024 switch (vol_op) {
2025 case 100: /* Create volume */
2026 ND_PRINT(" partition");
2027 UINTOUT();
2028 ND_PRINT(" name");
2029 STROUT(AFSNAMEMAX);
2030 ND_PRINT(" type");
2031 UINTOUT();
2032 ND_PRINT(" parent");
2033 UINTOUT();
2034 break;
2035 case 101: /* Delete volume */
2036 case 107: /* Get flags */
2037 ND_PRINT(" trans");
2038 UINTOUT();
2039 break;
2040 case 102: /* Restore */
2041 ND_PRINT(" totrans");
2042 UINTOUT();
2043 ND_PRINT(" flags");
2044 UINTOUT();
2045 break;
2046 case 103: /* Forward */
2047 ND_PRINT(" fromtrans");
2048 UINTOUT();
2049 ND_PRINT(" fromdate");
2050 DATEOUT();
2051 DESTSERVEROUT();
2052 ND_PRINT(" desttrans");
2053 INTOUT();
2054 break;
2055 case 104: /* End trans */
2056 ND_PRINT(" trans");
2057 UINTOUT();
2058 break;
2059 case 105: /* Clone */
2060 ND_PRINT(" trans");
2061 UINTOUT();
2062 ND_PRINT(" purgevol");
2063 UINTOUT();
2064 ND_PRINT(" newtype");
2065 UINTOUT();
2066 ND_PRINT(" newname");
2067 STROUT(AFSNAMEMAX);
2068 break;
2069 case 106: /* Set flags */
2070 ND_PRINT(" trans");
2071 UINTOUT();
2072 ND_PRINT(" flags");
2073 UINTOUT();
2074 break;
2075 case 108: /* Trans create */
2076 ND_PRINT(" vol");
2077 UINTOUT();
2078 ND_PRINT(" partition");
2079 UINTOUT();
2080 ND_PRINT(" flags");
2081 UINTOUT();
2082 break;
2083 case 109: /* Dump */
2084 case 655537: /* Get size */
2085 ND_PRINT(" fromtrans");
2086 UINTOUT();
2087 ND_PRINT(" fromdate");
2088 DATEOUT();
2089 break;
2090 case 110: /* Get n-th volume */
2091 ND_PRINT(" index");
2092 UINTOUT();
2093 break;
2094 case 111: /* Set forwarding */
2095 ND_PRINT(" tid");
2096 UINTOUT();
2097 ND_PRINT(" newsite");
2098 UINTOUT();
2099 break;
2100 case 112: /* Get name */
2101 case 113: /* Get status */
2102 ND_PRINT(" tid");
2103 break;
2104 case 114: /* Signal restore */
2105 ND_PRINT(" name");
2106 STROUT(AFSNAMEMAX);
2107 ND_PRINT(" type");
2108 UINTOUT();
2109 ND_PRINT(" pid");
2110 UINTOUT();
2111 ND_PRINT(" cloneid");
2112 UINTOUT();
2113 break;
2114 case 116: /* List volumes */
2115 ND_PRINT(" partition");
2116 UINTOUT();
2117 ND_PRINT(" flags");
2118 UINTOUT();
2119 break;
2120 case 117: /* Set id types */
2121 ND_PRINT(" tid");
2122 UINTOUT();
2123 ND_PRINT(" name");
2124 STROUT(AFSNAMEMAX);
2125 ND_PRINT(" type");
2126 UINTOUT();
2127 ND_PRINT(" pid");
2128 UINTOUT();
2129 ND_PRINT(" clone");
2130 UINTOUT();
2131 ND_PRINT(" backup");
2132 UINTOUT();
2133 break;
2134 case 119: /* Partition info */
2135 ND_PRINT(" name");
2136 STROUT(AFSNAMEMAX);
2137 break;
2138 case 120: /* Reclone */
2139 ND_PRINT(" tid");
2140 UINTOUT();
2141 break;
2142 case 121: /* List one volume */
2143 case 122: /* Nuke volume */
2144 case 124: /* Extended List volumes */
2145 case 125: /* Extended List one volume */
2146 case 65536: /* Convert RO to RW volume */
2147 ND_PRINT(" partid");
2148 UINTOUT();
2149 ND_PRINT(" volid");
2150 UINTOUT();
2151 break;
2152 case 123: /* Set date */
2153 ND_PRINT(" tid");
2154 UINTOUT();
2155 ND_PRINT(" date");
2156 DATEOUT();
2157 break;
2158 case 126: /* Set info */
2159 ND_PRINT(" tid");
2160 UINTOUT();
2161 break;
2162 case 128: /* Forward multiple */
2163 ND_PRINT(" fromtrans");
2164 UINTOUT();
2165 ND_PRINT(" fromdate");
2166 DATEOUT();
2167 {
2168 uint32_t i, j;
2169 j = GET_BE_U_4(bp);
2170 bp += sizeof(uint32_t);
2171 for (i = 0; i < j; i++) {
2172 DESTSERVEROUT();
2173 if (i != j - 1)
2174 ND_PRINT(",");
2175 }
2176 if (j == 0)
2177 ND_PRINT(" <none!>");
2178 }
2179 break;
2180 case 65538: /* Dump version 2 */
2181 ND_PRINT(" fromtrans");
2182 UINTOUT();
2183 ND_PRINT(" fromdate");
2184 DATEOUT();
2185 ND_PRINT(" flags");
2186 UINTOUT();
2187 break;
2188 default:
2189 ;
2190 }
2191 return;
2192
2193 trunc:
2194 ND_PRINT(" [|vol]");
2195 }
2196
2197 /*
2198 * Handle replies to the AFS Volume Service
2199 */
2200
2201 static void
vol_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2202 vol_reply_print(netdissect_options *ndo,
2203 const u_char *bp, u_int length, uint32_t opcode)
2204 {
2205 const struct rx_header *rxh;
2206 uint8_t type;
2207
2208 if (length <= sizeof(struct rx_header))
2209 return;
2210
2211 rxh = (const struct rx_header *) bp;
2212
2213 /*
2214 * Print out the afs call we're invoking. The table used here was
2215 * gleaned from volser/volint.xg
2216 */
2217
2218 ND_PRINT(" vol reply %s", tok2str(vol_req, "op#%u", opcode));
2219
2220 type = GET_U_1(rxh->type);
2221 bp += sizeof(struct rx_header);
2222
2223 /*
2224 * If it was a data packet, interpret the response.
2225 */
2226
2227 if (type == RX_PACKET_TYPE_DATA) {
2228 switch (opcode) {
2229 case 100: /* Create volume */
2230 ND_PRINT(" volid");
2231 UINTOUT();
2232 ND_PRINT(" trans");
2233 UINTOUT();
2234 break;
2235 case 104: /* End transaction */
2236 UINTOUT();
2237 break;
2238 case 105: /* Clone */
2239 ND_PRINT(" newvol");
2240 UINTOUT();
2241 break;
2242 case 107: /* Get flags */
2243 UINTOUT();
2244 break;
2245 case 108: /* Transaction create */
2246 ND_PRINT(" trans");
2247 UINTOUT();
2248 break;
2249 case 110: /* Get n-th volume */
2250 ND_PRINT(" volume");
2251 UINTOUT();
2252 ND_PRINT(" partition");
2253 UINTOUT();
2254 break;
2255 case 112: /* Get name */
2256 STROUT(AFSNAMEMAX);
2257 break;
2258 case 113: /* Get status */
2259 ND_PRINT(" volid");
2260 UINTOUT();
2261 ND_PRINT(" nextuniq");
2262 UINTOUT();
2263 ND_PRINT(" type");
2264 UINTOUT();
2265 ND_PRINT(" parentid");
2266 UINTOUT();
2267 ND_PRINT(" clone");
2268 UINTOUT();
2269 ND_PRINT(" backup");
2270 UINTOUT();
2271 ND_PRINT(" restore");
2272 UINTOUT();
2273 ND_PRINT(" maxquota");
2274 UINTOUT();
2275 ND_PRINT(" minquota");
2276 UINTOUT();
2277 ND_PRINT(" owner");
2278 UINTOUT();
2279 ND_PRINT(" create");
2280 DATEOUT();
2281 ND_PRINT(" access");
2282 DATEOUT();
2283 ND_PRINT(" update");
2284 DATEOUT();
2285 ND_PRINT(" expire");
2286 DATEOUT();
2287 ND_PRINT(" backup");
2288 DATEOUT();
2289 ND_PRINT(" copy");
2290 DATEOUT();
2291 break;
2292 case 115: /* Old list partitions */
2293 break;
2294 case 116: /* List volumes */
2295 case 121: /* List one volume */
2296 {
2297 uint32_t i, j;
2298 j = GET_BE_U_4(bp);
2299 bp += sizeof(uint32_t);
2300 for (i = 0; i < j; i++) {
2301 ND_PRINT(" name");
2302 VECOUT(32);
2303 ND_PRINT(" volid");
2304 UINTOUT();
2305 ND_PRINT(" type");
2306 bp += sizeof(uint32_t) * 21;
2307 if (i != j - 1)
2308 ND_PRINT(",");
2309 }
2310 if (j == 0)
2311 ND_PRINT(" <none!>");
2312 }
2313 break;
2314
2315
2316 default:
2317 ;
2318 }
2319 } else {
2320 /*
2321 * Otherwise, just print out the return code
2322 */
2323 ND_PRINT(" errcode");
2324 INTOUT();
2325 }
2326
2327 return;
2328
2329 trunc:
2330 ND_PRINT(" [|vol]");
2331 }
2332
2333 /*
2334 * Handle calls to the AFS BOS service
2335 */
2336
2337 static void
bos_print(netdissect_options * ndo,const u_char * bp,u_int length)2338 bos_print(netdissect_options *ndo,
2339 const u_char *bp, u_int length)
2340 {
2341 uint32_t bos_op;
2342
2343 if (length <= sizeof(struct rx_header))
2344 return;
2345
2346 /*
2347 * Print out the afs call we're invoking. The table used here was
2348 * gleaned from bozo/bosint.xg
2349 */
2350
2351 bos_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2352
2353 ND_PRINT(" bos call %s", tok2str(bos_req, "op#%u", bos_op));
2354
2355 /*
2356 * Decode some of the arguments to the BOS calls
2357 */
2358
2359 bp += sizeof(struct rx_header) + 4;
2360
2361 switch (bos_op) {
2362 case 80: /* Create B node */
2363 ND_PRINT(" type");
2364 STROUT(BOSNAMEMAX);
2365 ND_PRINT(" instance");
2366 STROUT(BOSNAMEMAX);
2367 break;
2368 case 81: /* Delete B node */
2369 case 83: /* Get status */
2370 case 85: /* Get instance info */
2371 case 87: /* Add super user */
2372 case 88: /* Delete super user */
2373 case 93: /* Set cell name */
2374 case 96: /* Add cell host */
2375 case 97: /* Delete cell host */
2376 case 104: /* Restart */
2377 case 106: /* Uninstall */
2378 case 108: /* Exec */
2379 case 112: /* Getlog */
2380 case 114: /* Get instance strings */
2381 STROUT(BOSNAMEMAX);
2382 break;
2383 case 82: /* Set status */
2384 case 98: /* Set T status */
2385 STROUT(BOSNAMEMAX);
2386 ND_PRINT(" status");
2387 INTOUT();
2388 break;
2389 case 86: /* Get instance parm */
2390 STROUT(BOSNAMEMAX);
2391 ND_PRINT(" num");
2392 INTOUT();
2393 break;
2394 case 84: /* Enumerate instance */
2395 case 89: /* List super users */
2396 case 90: /* List keys */
2397 case 91: /* Add key */
2398 case 92: /* Delete key */
2399 case 95: /* Get cell host */
2400 INTOUT();
2401 break;
2402 case 105: /* Install */
2403 STROUT(BOSNAMEMAX);
2404 ND_PRINT(" size");
2405 INTOUT();
2406 ND_PRINT(" flags");
2407 INTOUT();
2408 ND_PRINT(" date");
2409 INTOUT();
2410 break;
2411 default:
2412 ;
2413 }
2414
2415 return;
2416
2417 trunc:
2418 ND_PRINT(" [|bos]");
2419 }
2420
2421 /*
2422 * Handle replies to the AFS BOS Service
2423 */
2424
2425 static void
bos_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2426 bos_reply_print(netdissect_options *ndo,
2427 const u_char *bp, u_int length, uint32_t opcode)
2428 {
2429 const struct rx_header *rxh;
2430 uint8_t type;
2431
2432 if (length <= sizeof(struct rx_header))
2433 return;
2434
2435 rxh = (const struct rx_header *) bp;
2436
2437 /*
2438 * Print out the afs call we're invoking. The table used here was
2439 * gleaned from volser/volint.xg
2440 */
2441
2442 ND_PRINT(" bos reply %s", tok2str(bos_req, "op#%u", opcode));
2443
2444 type = GET_U_1(rxh->type);
2445 bp += sizeof(struct rx_header);
2446
2447 /*
2448 * If it was a data packet, interpret the response.
2449 */
2450
2451 if (type == RX_PACKET_TYPE_DATA)
2452 /* Well, no, not really. Leave this for later */
2453 ;
2454 else {
2455 /*
2456 * Otherwise, just print out the return code
2457 */
2458 ND_PRINT(" errcode");
2459 INTOUT();
2460 }
2461 }
2462
2463 /*
2464 * Check to see if this is a Ubik opcode.
2465 */
2466
2467 static int
is_ubik(uint32_t opcode)2468 is_ubik(uint32_t opcode)
2469 {
2470 if ((opcode >= VOTE_LOW && opcode <= VOTE_HIGH) ||
2471 (opcode >= DISK_LOW && opcode <= DISK_HIGH))
2472 return(1);
2473 else
2474 return(0);
2475 }
2476
2477 /*
2478 * Handle Ubik opcodes to any one of the replicated database services
2479 */
2480
2481 static void
ubik_print(netdissect_options * ndo,const u_char * bp)2482 ubik_print(netdissect_options *ndo,
2483 const u_char *bp)
2484 {
2485 uint32_t ubik_op;
2486 uint32_t temp;
2487
2488 /*
2489 * Print out the afs call we're invoking. The table used here was
2490 * gleaned from ubik/ubik_int.xg
2491 */
2492
2493 /* Every function that calls this function first makes a bounds check
2494 * for (sizeof(rx_header) + 4) bytes, so long as it remains this way
2495 * the line below will not over-read.
2496 */
2497 ubik_op = GET_BE_U_4(bp + sizeof(struct rx_header));
2498
2499 ND_PRINT(" ubik call %s", tok2str(ubik_req, "op#%u", ubik_op));
2500
2501 /*
2502 * Decode some of the arguments to the Ubik calls
2503 */
2504
2505 bp += sizeof(struct rx_header) + 4;
2506
2507 switch (ubik_op) {
2508 case 10000: /* Beacon */
2509 temp = GET_BE_U_4(bp);
2510 bp += sizeof(uint32_t);
2511 ND_PRINT(" syncsite %s", temp ? "yes" : "no");
2512 ND_PRINT(" votestart");
2513 DATEOUT();
2514 ND_PRINT(" dbversion");
2515 UBIK_VERSIONOUT();
2516 ND_PRINT(" tid");
2517 UBIK_VERSIONOUT();
2518 break;
2519 case 10003: /* Get sync site */
2520 ND_PRINT(" site");
2521 UINTOUT();
2522 break;
2523 case 20000: /* Begin */
2524 case 20001: /* Commit */
2525 case 20007: /* Abort */
2526 case 20008: /* Release locks */
2527 case 20010: /* Writev */
2528 ND_PRINT(" tid");
2529 UBIK_VERSIONOUT();
2530 break;
2531 case 20002: /* Lock */
2532 ND_PRINT(" tid");
2533 UBIK_VERSIONOUT();
2534 ND_PRINT(" file");
2535 INTOUT();
2536 ND_PRINT(" pos");
2537 INTOUT();
2538 ND_PRINT(" length");
2539 INTOUT();
2540 temp = GET_BE_U_4(bp);
2541 bp += sizeof(uint32_t);
2542 tok2str(ubik_lock_types, "type %u", temp);
2543 break;
2544 case 20003: /* Write */
2545 ND_PRINT(" tid");
2546 UBIK_VERSIONOUT();
2547 ND_PRINT(" file");
2548 INTOUT();
2549 ND_PRINT(" pos");
2550 INTOUT();
2551 break;
2552 case 20005: /* Get file */
2553 ND_PRINT(" file");
2554 INTOUT();
2555 break;
2556 case 20006: /* Send file */
2557 ND_PRINT(" file");
2558 INTOUT();
2559 ND_PRINT(" length");
2560 INTOUT();
2561 ND_PRINT(" dbversion");
2562 UBIK_VERSIONOUT();
2563 break;
2564 case 20009: /* Truncate */
2565 ND_PRINT(" tid");
2566 UBIK_VERSIONOUT();
2567 ND_PRINT(" file");
2568 INTOUT();
2569 ND_PRINT(" length");
2570 INTOUT();
2571 break;
2572 case 20012: /* Set version */
2573 ND_PRINT(" tid");
2574 UBIK_VERSIONOUT();
2575 ND_PRINT(" oldversion");
2576 UBIK_VERSIONOUT();
2577 ND_PRINT(" newversion");
2578 UBIK_VERSIONOUT();
2579 break;
2580 default:
2581 ;
2582 }
2583
2584 return;
2585
2586 trunc:
2587 ND_PRINT(" [|ubik]");
2588 }
2589
2590 /*
2591 * Handle Ubik replies to any one of the replicated database services
2592 */
2593
2594 static void
ubik_reply_print(netdissect_options * ndo,const u_char * bp,u_int length,uint32_t opcode)2595 ubik_reply_print(netdissect_options *ndo,
2596 const u_char *bp, u_int length, uint32_t opcode)
2597 {
2598 const struct rx_header *rxh;
2599 uint8_t type;
2600
2601 if (length < sizeof(struct rx_header))
2602 return;
2603
2604 rxh = (const struct rx_header *) bp;
2605
2606 /*
2607 * Print out the ubik call we're invoking. This table was gleaned
2608 * from ubik/ubik_int.xg
2609 */
2610
2611 ND_PRINT(" ubik reply %s", tok2str(ubik_req, "op#%u", opcode));
2612
2613 type = GET_U_1(rxh->type);
2614 bp += sizeof(struct rx_header);
2615
2616 /*
2617 * If it was a data packet, print out the arguments to the Ubik calls
2618 */
2619
2620 if (type == RX_PACKET_TYPE_DATA)
2621 switch (opcode) {
2622 case 10000: /* Beacon */
2623 ND_PRINT(" vote no");
2624 break;
2625 case 20004: /* Get version */
2626 ND_PRINT(" dbversion");
2627 UBIK_VERSIONOUT();
2628 break;
2629 default:
2630 ;
2631 }
2632
2633 /*
2634 * Otherwise, print out "yes" if it was a beacon packet (because
2635 * that's how yes votes are returned, go figure), otherwise
2636 * just print out the error code.
2637 */
2638
2639 else
2640 switch (opcode) {
2641 case 10000: /* Beacon */
2642 ND_PRINT(" vote yes until");
2643 DATEOUT();
2644 break;
2645 default:
2646 ND_PRINT(" errcode");
2647 INTOUT();
2648 }
2649
2650 return;
2651
2652 trunc:
2653 ND_PRINT(" [|ubik]");
2654 }
2655
2656 /*
2657 * Handle RX ACK packets.
2658 */
2659
2660 static void
rx_ack_print(netdissect_options * ndo,const u_char * bp,u_int length)2661 rx_ack_print(netdissect_options *ndo,
2662 const u_char *bp, u_int length)
2663 {
2664 const struct rx_ackPacket *rxa;
2665 uint8_t nAcks;
2666 int i, start, last;
2667 uint32_t firstPacket;
2668
2669 if (length < sizeof(struct rx_header))
2670 return;
2671
2672 bp += sizeof(struct rx_header);
2673
2674 ND_TCHECK_LEN(bp, sizeof(struct rx_ackPacket));
2675
2676 rxa = (const struct rx_ackPacket *) bp;
2677 bp += sizeof(struct rx_ackPacket);
2678
2679 /*
2680 * Print out a few useful things from the ack packet structure
2681 */
2682
2683 if (ndo->ndo_vflag > 2)
2684 ND_PRINT(" bufspace %u maxskew %u",
2685 GET_BE_U_2(rxa->bufferSpace),
2686 GET_BE_U_2(rxa->maxSkew));
2687
2688 firstPacket = GET_BE_U_4(rxa->firstPacket);
2689 ND_PRINT(" first %u serial %u reason %s",
2690 firstPacket, GET_BE_U_4(rxa->serial),
2691 tok2str(rx_ack_reasons, "#%u", GET_U_1(rxa->reason)));
2692
2693 /*
2694 * Okay, now we print out the ack array. The way _this_ works
2695 * is that we start at "first", and step through the ack array.
2696 * If we have a contiguous range of acks/nacks, try to
2697 * collapse them into a range.
2698 *
2699 * If you're really clever, you might have noticed that this
2700 * doesn't seem quite correct. Specifically, due to structure
2701 * padding, sizeof(struct rx_ackPacket) - RX_MAXACKS won't actually
2702 * yield the start of the ack array (because RX_MAXACKS is 255
2703 * and the structure will likely get padded to a 2 or 4 byte
2704 * boundary). However, this is the way it's implemented inside
2705 * of AFS - the start of the extra fields are at
2706 * sizeof(struct rx_ackPacket) - RX_MAXACKS + nAcks, which _isn't_
2707 * the exact start of the ack array. Sigh. That's why we aren't
2708 * using bp, but instead use rxa->acks[]. But nAcks gets added
2709 * to bp after this, so bp ends up at the right spot. Go figure.
2710 */
2711
2712 nAcks = GET_U_1(rxa->nAcks);
2713 if (nAcks != 0) {
2714
2715 ND_TCHECK_LEN(bp, nAcks);
2716
2717 /*
2718 * Sigh, this is gross, but it seems to work to collapse
2719 * ranges correctly.
2720 */
2721
2722 for (i = 0, start = last = -2; i < nAcks; i++)
2723 if (GET_U_1(bp + i) == RX_ACK_TYPE_ACK) {
2724
2725 /*
2726 * I figured this deserved _some_ explanation.
2727 * First, print "acked" and the packet seq
2728 * number if this is the first time we've
2729 * seen an acked packet.
2730 */
2731
2732 if (last == -2) {
2733 ND_PRINT(" acked %u", firstPacket + i);
2734 start = i;
2735 }
2736
2737 /*
2738 * Otherwise, if there is a skip in
2739 * the range (such as an nacked packet in
2740 * the middle of some acked packets),
2741 * then print the current packet number
2742 * separated from the last number by
2743 * a comma.
2744 */
2745
2746 else if (last != i - 1) {
2747 ND_PRINT(",%u", firstPacket + i);
2748 start = i;
2749 }
2750
2751 /*
2752 * We always set last to the value of
2753 * the last ack we saw. Conversely, start
2754 * is set to the value of the first ack
2755 * we saw in a range.
2756 */
2757
2758 last = i;
2759
2760 /*
2761 * Okay, this bit a code gets executed when
2762 * we hit a nack ... in _this_ case we
2763 * want to print out the range of packets
2764 * that were acked, so we need to print
2765 * the _previous_ packet number separated
2766 * from the first by a dash (-). Since we
2767 * already printed the first packet above,
2768 * just print the final packet. Don't
2769 * do this if there will be a single-length
2770 * range.
2771 */
2772 } else if (last == i - 1 && start != last)
2773 ND_PRINT("-%u", firstPacket + i - 1);
2774
2775 /*
2776 * So, what's going on here? We ran off the end of the
2777 * ack list, and if we got a range we need to finish it up.
2778 * So we need to determine if the last packet in the list
2779 * was an ack (if so, then last will be set to it) and
2780 * we need to see if the last range didn't start with the
2781 * last packet (because if it _did_, then that would mean
2782 * that the packet number has already been printed and
2783 * we don't need to print it again).
2784 */
2785
2786 if (last == i - 1 && start != last)
2787 ND_PRINT("-%u", firstPacket + i - 1);
2788
2789 /*
2790 * Same as above, just without comments
2791 */
2792
2793 for (i = 0, start = last = -2; i < nAcks; i++)
2794 if (GET_U_1(bp + i) == RX_ACK_TYPE_NACK) {
2795 if (last == -2) {
2796 ND_PRINT(" nacked %u", firstPacket + i);
2797 start = i;
2798 } else if (last != i - 1) {
2799 ND_PRINT(",%u", firstPacket + i);
2800 start = i;
2801 }
2802 last = i;
2803 } else if (last == i - 1 && start != last)
2804 ND_PRINT("-%u", firstPacket + i - 1);
2805
2806 if (last == i - 1 && start != last)
2807 ND_PRINT("-%u", firstPacket + i - 1);
2808
2809 bp += nAcks;
2810 }
2811
2812 /* Padding. */
2813 bp += 3;
2814
2815 /*
2816 * These are optional fields; depending on your version of AFS,
2817 * you may or may not see them
2818 */
2819
2820 #define TRUNCRET(n) if (ndo->ndo_snapend - bp + 1 <= n) return;
2821
2822 if (ndo->ndo_vflag > 1) {
2823 TRUNCRET(4);
2824 ND_PRINT(" ifmtu");
2825 UINTOUT();
2826
2827 TRUNCRET(4);
2828 ND_PRINT(" maxmtu");
2829 UINTOUT();
2830
2831 TRUNCRET(4);
2832 ND_PRINT(" rwind");
2833 UINTOUT();
2834
2835 TRUNCRET(4);
2836 ND_PRINT(" maxpackets");
2837 UINTOUT();
2838 }
2839
2840 return;
2841
2842 trunc:
2843 ND_PRINT(" [|ack]");
2844 }
2845 #undef TRUNCRET
2846