diff options
Diffstat (limited to 'print-zephyr.c')
-rw-r--r-- | print-zephyr.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/print-zephyr.c b/print-zephyr.c new file mode 100644 index 000000000000..38b0cd0c7bf5 --- /dev/null +++ b/print-zephyr.c @@ -0,0 +1,320 @@ +/* + * Decode and print Zephyr packets. + * + * http://web.mit.edu/zephyr/doc/protocol + * + * Copyright (c) 2001 Nickolai Zeldovich <kolya@MIT.EDU> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code + * distributions retain the above copyright notice and this paragraph + * in its entirety, and (2) distributions including binary code include + * the above copyright notice and this paragraph in its entirety in + * the documentation or other materials provided with the distribution. + * The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/* \summary: Zephyr printer */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <netdissect-stdinc.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "netdissect.h" + +struct z_packet { + const char *version; + int numfields; + int kind; + const char *uid; + int port; + int auth; + int authlen; + const char *authdata; + const char *class; + const char *inst; + const char *opcode; + const char *sender; + const char *recipient; + const char *format; + int cksum; + int multi; + const char *multi_uid; + /* Other fields follow here.. */ +}; + +enum z_packet_type { + Z_PACKET_UNSAFE = 0, + Z_PACKET_UNACKED, + Z_PACKET_ACKED, + Z_PACKET_HMACK, + Z_PACKET_HMCTL, + Z_PACKET_SERVACK, + Z_PACKET_SERVNAK, + Z_PACKET_CLIENTACK, + Z_PACKET_STAT +}; + +static const struct tok z_types[] = { + { Z_PACKET_UNSAFE, "unsafe" }, + { Z_PACKET_UNACKED, "unacked" }, + { Z_PACKET_ACKED, "acked" }, + { Z_PACKET_HMACK, "hm-ack" }, + { Z_PACKET_HMCTL, "hm-ctl" }, + { Z_PACKET_SERVACK, "serv-ack" }, + { Z_PACKET_SERVNAK, "serv-nak" }, + { Z_PACKET_CLIENTACK, "client-ack" }, + { Z_PACKET_STAT, "stat" } +}; + +static char z_buf[256]; + +static const char * +parse_field(netdissect_options *ndo, const char **pptr, int *len) +{ + const char *s; + + if (*len <= 0 || !pptr || !*pptr) + return NULL; + if (*pptr > (const char *) ndo->ndo_snapend) + return NULL; + + s = *pptr; + while (*pptr <= (const char *) ndo->ndo_snapend && *len >= 0 && **pptr) { + (*pptr)++; + (*len)--; + } + (*pptr)++; + (*len)--; + if (*len < 0 || *pptr > (const char *) ndo->ndo_snapend) + return NULL; + return s; +} + +static const char * +z_triple(const char *class, const char *inst, const char *recipient) +{ + if (!*recipient) + recipient = "*"; + snprintf(z_buf, sizeof(z_buf), "<%s,%s,%s>", class, inst, recipient); + z_buf[sizeof(z_buf)-1] = '\0'; + return z_buf; +} + +static const char * +str_to_lower(const char *string) +{ + char *zb_string; + + strncpy(z_buf, string, sizeof(z_buf)); + z_buf[sizeof(z_buf)-1] = '\0'; + + zb_string = z_buf; + while (*zb_string) { + *zb_string = tolower((unsigned char)(*zb_string)); + zb_string++; + } + + return z_buf; +} + +void +zephyr_print(netdissect_options *ndo, const u_char *cp, int length) +{ + struct z_packet z; + const char *parse = (const char *) cp; + int parselen = length; + const char *s; + int lose = 0; + + /* squelch compiler warnings */ + + z.kind = 0; + z.class = 0; + z.inst = 0; + z.opcode = 0; + z.sender = 0; + z.recipient = 0; + +#define PARSE_STRING \ + s = parse_field(ndo, &parse, &parselen); \ + if (!s) lose = 1; + +#define PARSE_FIELD_INT(field) \ + PARSE_STRING \ + if (!lose) field = strtol(s, 0, 16); + +#define PARSE_FIELD_STR(field) \ + PARSE_STRING \ + if (!lose) field = s; + + PARSE_FIELD_STR(z.version); + if (lose) return; + if (strncmp(z.version, "ZEPH", 4)) + return; + + PARSE_FIELD_INT(z.numfields); + PARSE_FIELD_INT(z.kind); + PARSE_FIELD_STR(z.uid); + PARSE_FIELD_INT(z.port); + PARSE_FIELD_INT(z.auth); + PARSE_FIELD_INT(z.authlen); + PARSE_FIELD_STR(z.authdata); + PARSE_FIELD_STR(z.class); + PARSE_FIELD_STR(z.inst); + PARSE_FIELD_STR(z.opcode); + PARSE_FIELD_STR(z.sender); + PARSE_FIELD_STR(z.recipient); + PARSE_FIELD_STR(z.format); + PARSE_FIELD_INT(z.cksum); + PARSE_FIELD_INT(z.multi); + PARSE_FIELD_STR(z.multi_uid); + + if (lose) { + ND_PRINT((ndo, " [|zephyr] (%d)", length)); + return; + } + + ND_PRINT((ndo, " zephyr")); + if (strncmp(z.version+4, "0.2", 3)) { + ND_PRINT((ndo, " v%s", z.version+4)); + return; + } + + ND_PRINT((ndo, " %s", tok2str(z_types, "type %d", z.kind))); + if (z.kind == Z_PACKET_SERVACK) { + /* Initialization to silence warnings */ + const char *ackdata = NULL; + PARSE_FIELD_STR(ackdata); + if (!lose && strcmp(ackdata, "SENT")) + ND_PRINT((ndo, "/%s", str_to_lower(ackdata))); + } + if (*z.sender) ND_PRINT((ndo, " %s", z.sender)); + + if (!strcmp(z.class, "USER_LOCATE")) { + if (!strcmp(z.opcode, "USER_HIDE")) + ND_PRINT((ndo, " hide")); + else if (!strcmp(z.opcode, "USER_UNHIDE")) + ND_PRINT((ndo, " unhide")); + else + ND_PRINT((ndo, " locate %s", z.inst)); + return; + } + + if (!strcmp(z.class, "ZEPHYR_ADMIN")) { + ND_PRINT((ndo, " zephyr-admin %s", str_to_lower(z.opcode))); + return; + } + + if (!strcmp(z.class, "ZEPHYR_CTL")) { + if (!strcmp(z.inst, "CLIENT")) { + if (!strcmp(z.opcode, "SUBSCRIBE") || + !strcmp(z.opcode, "SUBSCRIBE_NODEFS") || + !strcmp(z.opcode, "UNSUBSCRIBE")) { + + ND_PRINT((ndo, " %ssub%s", strcmp(z.opcode, "SUBSCRIBE") ? "un" : "", + strcmp(z.opcode, "SUBSCRIBE_NODEFS") ? "" : + "-nodefs")); + if (z.kind != Z_PACKET_SERVACK) { + /* Initialization to silence warnings */ + const char *c = NULL, *i = NULL, *r = NULL; + PARSE_FIELD_STR(c); + PARSE_FIELD_STR(i); + PARSE_FIELD_STR(r); + if (!lose) ND_PRINT((ndo, " %s", z_triple(c, i, r))); + } + return; + } + + if (!strcmp(z.opcode, "GIMME")) { + ND_PRINT((ndo, " ret")); + return; + } + + if (!strcmp(z.opcode, "GIMMEDEFS")) { + ND_PRINT((ndo, " gimme-defs")); + return; + } + + if (!strcmp(z.opcode, "CLEARSUB")) { + ND_PRINT((ndo, " clear-subs")); + return; + } + + ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); + return; + } + + if (!strcmp(z.inst, "HM")) { + ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); + return; + } + + if (!strcmp(z.inst, "REALM")) { + if (!strcmp(z.opcode, "ADD_SUBSCRIBE")) + ND_PRINT((ndo, " realm add-subs")); + if (!strcmp(z.opcode, "REQ_SUBSCRIBE")) + ND_PRINT((ndo, " realm req-subs")); + if (!strcmp(z.opcode, "RLM_SUBSCRIBE")) + ND_PRINT((ndo, " realm rlm-sub")); + if (!strcmp(z.opcode, "RLM_UNSUBSCRIBE")) + ND_PRINT((ndo, " realm rlm-unsub")); + return; + } + } + + if (!strcmp(z.class, "HM_CTL")) { + ND_PRINT((ndo, " hm_ctl %s", str_to_lower(z.inst))); + ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); + return; + } + + if (!strcmp(z.class, "HM_STAT")) { + if (!strcmp(z.inst, "HMST_CLIENT") && !strcmp(z.opcode, "GIMMESTATS")) { + ND_PRINT((ndo, " get-client-stats")); + return; + } + } + + if (!strcmp(z.class, "WG_CTL")) { + ND_PRINT((ndo, " wg_ctl %s", str_to_lower(z.inst))); + ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); + return; + } + + if (!strcmp(z.class, "LOGIN")) { + if (!strcmp(z.opcode, "USER_FLUSH")) { + ND_PRINT((ndo, " flush_locs")); + return; + } + + if (!strcmp(z.opcode, "NONE") || + !strcmp(z.opcode, "OPSTAFF") || + !strcmp(z.opcode, "REALM-VISIBLE") || + !strcmp(z.opcode, "REALM-ANNOUNCED") || + !strcmp(z.opcode, "NET-VISIBLE") || + !strcmp(z.opcode, "NET-ANNOUNCED")) { + ND_PRINT((ndo, " set-exposure %s", str_to_lower(z.opcode))); + return; + } + } + + if (!*z.recipient) + z.recipient = "*"; + + ND_PRINT((ndo, " to %s", z_triple(z.class, z.inst, z.recipient))); + if (*z.opcode) + ND_PRINT((ndo, " op %s", z.opcode)); +} |