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