print-zephyr.c 8.0 KB

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