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