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