1 /* 2 * Decode and print Zephyr packets. 3 * 4 * http://web.mit.edu/zephyr/doc/protocol 5 * 6 * Copyright (c) 2001 Nickolai Zeldovich <kolya (at) MIT.EDU> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that: (1) source code 11 * distributions retain the above copyright notice and this paragraph 12 * in its entirety, and (2) distributions including binary code include 13 * the above copyright notice and this paragraph in its entirety in 14 * the documentation or other materials provided with the distribution. 15 * The name of the author(s) may not be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE. 21 */ 22 23 #define NETDISSECT_REWORKED 24 #ifdef HAVE_CONFIG_H 25 #include "config.h" 26 #endif 27 28 #include <tcpdump-stdinc.h> 29 30 #include <stdio.h> 31 #include <string.h> 32 #include <stdlib.h> 33 34 #include "interface.h" 35 36 struct z_packet { 37 char *version; 38 int numfields; 39 int kind; 40 char *uid; 41 int port; 42 int auth; 43 int authlen; 44 char *authdata; 45 char *class; 46 char *inst; 47 char *opcode; 48 char *sender; 49 const char *recipient; 50 char *format; 51 int cksum; 52 int multi; 53 char *multi_uid; 54 /* Other fields follow here.. */ 55 }; 56 57 enum z_packet_type { 58 Z_PACKET_UNSAFE = 0, 59 Z_PACKET_UNACKED, 60 Z_PACKET_ACKED, 61 Z_PACKET_HMACK, 62 Z_PACKET_HMCTL, 63 Z_PACKET_SERVACK, 64 Z_PACKET_SERVNAK, 65 Z_PACKET_CLIENTACK, 66 Z_PACKET_STAT 67 }; 68 69 static const struct tok z_types[] = { 70 { Z_PACKET_UNSAFE, "unsafe" }, 71 { Z_PACKET_UNACKED, "unacked" }, 72 { Z_PACKET_ACKED, "acked" }, 73 { Z_PACKET_HMACK, "hm-ack" }, 74 { Z_PACKET_HMCTL, "hm-ctl" }, 75 { Z_PACKET_SERVACK, "serv-ack" }, 76 { Z_PACKET_SERVNAK, "serv-nak" }, 77 { Z_PACKET_CLIENTACK, "client-ack" }, 78 { Z_PACKET_STAT, "stat" } 79 }; 80 81 static char z_buf[256]; 82 83 static char * 84 parse_field(netdissect_options *ndo, char **pptr, int *len) 85 { 86 char *s; 87 88 if (*len <= 0 || !pptr || !*pptr) 89 return NULL; 90 if (*pptr > (char *) ndo->ndo_snapend) 91 return NULL; 92 93 s = *pptr; 94 while (*pptr <= (char *) ndo->ndo_snapend && *len >= 0 && **pptr) { 95 (*pptr)++; 96 (*len)--; 97 } 98 (*pptr)++; 99 (*len)--; 100 if (*len < 0 || *pptr > (char *) ndo->ndo_snapend) 101 return NULL; 102 return s; 103 } 104 105 static const char * 106 z_triple(char *class, char *inst, const char *recipient) 107 { 108 if (!*recipient) 109 recipient = "*"; 110 snprintf(z_buf, sizeof(z_buf), "<%s,%s,%s>", class, inst, recipient); 111 z_buf[sizeof(z_buf)-1] = '\0'; 112 return z_buf; 113 } 114 115 static const char * 116 str_to_lower(char *string) 117 { 118 strncpy(z_buf, string, sizeof(z_buf)); 119 z_buf[sizeof(z_buf)-1] = '\0'; 120 121 string = z_buf; 122 while (*string) { 123 *string = tolower((unsigned char)(*string)); 124 string++; 125 } 126 127 return z_buf; 128 } 129 130 void 131 zephyr_print(netdissect_options *ndo, const u_char *cp, int length) 132 { 133 struct z_packet z; 134 char *parse = (char *) cp; 135 int parselen = length; 136 char *s; 137 int lose = 0; 138 139 /* squelch compiler warnings */ 140 141 z.kind = 0; 142 z.class = 0; 143 z.inst = 0; 144 z.opcode = 0; 145 z.sender = 0; 146 z.recipient = 0; 147 148 #define PARSE_STRING \ 149 s = parse_field(ndo, &parse, &parselen); \ 150 if (!s) lose = 1; 151 152 #define PARSE_FIELD_INT(field) \ 153 PARSE_STRING \ 154 if (!lose) field = strtol(s, 0, 16); 155 156 #define PARSE_FIELD_STR(field) \ 157 PARSE_STRING \ 158 if (!lose) field = s; 159 160 PARSE_FIELD_STR(z.version); 161 if (lose) return; 162 if (strncmp(z.version, "ZEPH", 4)) 163 return; 164 165 PARSE_FIELD_INT(z.numfields); 166 PARSE_FIELD_INT(z.kind); 167 PARSE_FIELD_STR(z.uid); 168 PARSE_FIELD_INT(z.port); 169 PARSE_FIELD_INT(z.auth); 170 PARSE_FIELD_INT(z.authlen); 171 PARSE_FIELD_STR(z.authdata); 172 PARSE_FIELD_STR(z.class); 173 PARSE_FIELD_STR(z.inst); 174 PARSE_FIELD_STR(z.opcode); 175 PARSE_FIELD_STR(z.sender); 176 PARSE_FIELD_STR(z.recipient); 177 PARSE_FIELD_STR(z.format); 178 PARSE_FIELD_INT(z.cksum); 179 PARSE_FIELD_INT(z.multi); 180 PARSE_FIELD_STR(z.multi_uid); 181 182 if (lose) { 183 ND_PRINT((ndo, " [|zephyr] (%d)", length)); 184 return; 185 } 186 187 ND_PRINT((ndo, " zephyr")); 188 if (strncmp(z.version+4, "0.2", 3)) { 189 ND_PRINT((ndo, " v%s", z.version+4)); 190 return; 191 } 192 193 ND_PRINT((ndo, " %s", tok2str(z_types, "type %d", z.kind))); 194 if (z.kind == Z_PACKET_SERVACK) { 195 /* Initialization to silence warnings */ 196 char *ackdata = NULL; 197 PARSE_FIELD_STR(ackdata); 198 if (!lose && strcmp(ackdata, "SENT")) 199 ND_PRINT((ndo, "/%s", str_to_lower(ackdata))); 200 } 201 if (*z.sender) ND_PRINT((ndo, " %s", z.sender)); 202 203 if (!strcmp(z.class, "USER_LOCATE")) { 204 if (!strcmp(z.opcode, "USER_HIDE")) 205 ND_PRINT((ndo, " hide")); 206 else if (!strcmp(z.opcode, "USER_UNHIDE")) 207 ND_PRINT((ndo, " unhide")); 208 else 209 ND_PRINT((ndo, " locate %s", z.inst)); 210 return; 211 } 212 213 if (!strcmp(z.class, "ZEPHYR_ADMIN")) { 214 ND_PRINT((ndo, " zephyr-admin %s", str_to_lower(z.opcode))); 215 return; 216 } 217 218 if (!strcmp(z.class, "ZEPHYR_CTL")) { 219 if (!strcmp(z.inst, "CLIENT")) { 220 if (!strcmp(z.opcode, "SUBSCRIBE") || 221 !strcmp(z.opcode, "SUBSCRIBE_NODEFS") || 222 !strcmp(z.opcode, "UNSUBSCRIBE")) { 223 224 ND_PRINT((ndo, " %ssub%s", strcmp(z.opcode, "SUBSCRIBE") ? "un" : "", 225 strcmp(z.opcode, "SUBSCRIBE_NODEFS") ? "" : 226 "-nodefs")); 227 if (z.kind != Z_PACKET_SERVACK) { 228 /* Initialization to silence warnings */ 229 char *c = NULL, *i = NULL, *r = NULL; 230 PARSE_FIELD_STR(c); 231 PARSE_FIELD_STR(i); 232 PARSE_FIELD_STR(r); 233 if (!lose) ND_PRINT((ndo, " %s", z_triple(c, i, r))); 234 } 235 return; 236 } 237 238 if (!strcmp(z.opcode, "GIMME")) { 239 ND_PRINT((ndo, " ret")); 240 return; 241 } 242 243 if (!strcmp(z.opcode, "GIMMEDEFS")) { 244 ND_PRINT((ndo, " gimme-defs")); 245 return; 246 } 247 248 if (!strcmp(z.opcode, "CLEARSUB")) { 249 ND_PRINT((ndo, " clear-subs")); 250 return; 251 } 252 253 ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); 254 return; 255 } 256 257 if (!strcmp(z.inst, "HM")) { 258 ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); 259 return; 260 } 261 262 if (!strcmp(z.inst, "REALM")) { 263 if (!strcmp(z.opcode, "ADD_SUBSCRIBE")) 264 ND_PRINT((ndo, " realm add-subs")); 265 if (!strcmp(z.opcode, "REQ_SUBSCRIBE")) 266 ND_PRINT((ndo, " realm req-subs")); 267 if (!strcmp(z.opcode, "RLM_SUBSCRIBE")) 268 ND_PRINT((ndo, " realm rlm-sub")); 269 if (!strcmp(z.opcode, "RLM_UNSUBSCRIBE")) 270 ND_PRINT((ndo, " realm rlm-unsub")); 271 return; 272 } 273 } 274 275 if (!strcmp(z.class, "HM_CTL")) { 276 ND_PRINT((ndo, " hm_ctl %s", str_to_lower(z.inst))); 277 ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); 278 return; 279 } 280 281 if (!strcmp(z.class, "HM_STAT")) { 282 if (!strcmp(z.inst, "HMST_CLIENT") && !strcmp(z.opcode, "GIMMESTATS")) { 283 ND_PRINT((ndo, " get-client-stats")); 284 return; 285 } 286 } 287 288 if (!strcmp(z.class, "WG_CTL")) { 289 ND_PRINT((ndo, " wg_ctl %s", str_to_lower(z.inst))); 290 ND_PRINT((ndo, " %s", str_to_lower(z.opcode))); 291 return; 292 } 293 294 if (!strcmp(z.class, "LOGIN")) { 295 if (!strcmp(z.opcode, "USER_FLUSH")) { 296 ND_PRINT((ndo, " flush_locs")); 297 return; 298 } 299 300 if (!strcmp(z.opcode, "NONE") || 301 !strcmp(z.opcode, "OPSTAFF") || 302 !strcmp(z.opcode, "REALM-VISIBLE") || 303 !strcmp(z.opcode, "REALM-ANNOUNCED") || 304 !strcmp(z.opcode, "NET-VISIBLE") || 305 !strcmp(z.opcode, "NET-ANNOUNCED")) { 306 ND_PRINT((ndo, " set-exposure %s", str_to_lower(z.opcode))); 307 return; 308 } 309 } 310 311 if (!*z.recipient) 312 z.recipient = "*"; 313 314 ND_PRINT((ndo, " to %s", z_triple(z.class, z.inst, z.recipient))); 315 if (*z.opcode) 316 ND_PRINT((ndo, " op %s", z.opcode)); 317 } 318