1a90e161bSBill Fenner /*
2a90e161bSBill Fenner * Decode and print Zephyr packets.
3a90e161bSBill Fenner *
4*ee67461eSJoseph Mingrone * https://web.mit.edu/zephyr/doc/protocol
5f4d0c64aSSam Leffler *
6a90e161bSBill Fenner * Copyright (c) 2001 Nickolai Zeldovich <kolya@MIT.EDU>
7a90e161bSBill Fenner * All rights reserved.
8a90e161bSBill Fenner *
9a90e161bSBill Fenner * Redistribution and use in source and binary forms, with or without
10a90e161bSBill Fenner * modification, are permitted provided that: (1) source code
11a90e161bSBill Fenner * distributions retain the above copyright notice and this paragraph
12a90e161bSBill Fenner * in its entirety, and (2) distributions including binary code include
13a90e161bSBill Fenner * the above copyright notice and this paragraph in its entirety in
14a90e161bSBill Fenner * the documentation or other materials provided with the distribution.
15a90e161bSBill Fenner * The name of the author(s) may not be used to endorse or promote
16a90e161bSBill Fenner * products derived from this software without specific prior written
17a90e161bSBill Fenner * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
18a90e161bSBill Fenner * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
19a90e161bSBill Fenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20a90e161bSBill Fenner * PURPOSE.
21a90e161bSBill Fenner */
22a90e161bSBill Fenner
233340d773SGleb Smirnoff /* \summary: Zephyr printer */
243340d773SGleb Smirnoff
25*ee67461eSJoseph Mingrone #include <config.h>
26a90e161bSBill Fenner
27*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
285b0fe478SBruce M Simpson
29a90e161bSBill Fenner #include <stdio.h>
30a90e161bSBill Fenner #include <string.h>
31a90e161bSBill Fenner #include <stdlib.h>
32a90e161bSBill Fenner
33*ee67461eSJoseph Mingrone #include "netdissect-ctype.h"
34*ee67461eSJoseph Mingrone
353340d773SGleb Smirnoff #include "netdissect.h"
36*ee67461eSJoseph Mingrone #include "extract.h"
37a90e161bSBill Fenner
38a90e161bSBill Fenner struct z_packet {
393340d773SGleb Smirnoff const char *version;
40a90e161bSBill Fenner int numfields;
41a90e161bSBill Fenner int kind;
423340d773SGleb Smirnoff const char *uid;
43a90e161bSBill Fenner int port;
44a90e161bSBill Fenner int auth;
45a90e161bSBill Fenner int authlen;
463340d773SGleb Smirnoff const char *authdata;
473340d773SGleb Smirnoff const char *class;
483340d773SGleb Smirnoff const char *inst;
493340d773SGleb Smirnoff const char *opcode;
503340d773SGleb Smirnoff const char *sender;
515b0fe478SBruce M Simpson const char *recipient;
523340d773SGleb Smirnoff const char *format;
53a90e161bSBill Fenner int cksum;
54a90e161bSBill Fenner int multi;
553340d773SGleb Smirnoff const char *multi_uid;
56a90e161bSBill Fenner /* Other fields follow here.. */
57a90e161bSBill Fenner };
58a90e161bSBill Fenner
599afd0c29SBill Fenner enum z_packet_type {
60a90e161bSBill Fenner Z_PACKET_UNSAFE = 0,
61a90e161bSBill Fenner Z_PACKET_UNACKED,
62a90e161bSBill Fenner Z_PACKET_ACKED,
63a90e161bSBill Fenner Z_PACKET_HMACK,
64a90e161bSBill Fenner Z_PACKET_HMCTL,
65a90e161bSBill Fenner Z_PACKET_SERVACK,
66a90e161bSBill Fenner Z_PACKET_SERVNAK,
67a90e161bSBill Fenner Z_PACKET_CLIENTACK,
68a90e161bSBill Fenner Z_PACKET_STAT
699afd0c29SBill Fenner };
70a90e161bSBill Fenner
713c602fabSXin LI static const struct tok z_types[] = {
72a90e161bSBill Fenner { Z_PACKET_UNSAFE, "unsafe" },
73a90e161bSBill Fenner { Z_PACKET_UNACKED, "unacked" },
74a90e161bSBill Fenner { Z_PACKET_ACKED, "acked" },
75a90e161bSBill Fenner { Z_PACKET_HMACK, "hm-ack" },
76a90e161bSBill Fenner { Z_PACKET_HMCTL, "hm-ctl" },
77a90e161bSBill Fenner { Z_PACKET_SERVACK, "serv-ack" },
78a90e161bSBill Fenner { Z_PACKET_SERVNAK, "serv-nak" },
79a90e161bSBill Fenner { Z_PACKET_CLIENTACK, "client-ack" },
800bff6a5aSEd Maste { Z_PACKET_STAT, "stat" },
810bff6a5aSEd Maste { 0, NULL }
82a90e161bSBill Fenner };
83a90e161bSBill Fenner
843c602fabSXin LI static char z_buf[256];
85a90e161bSBill Fenner
863340d773SGleb Smirnoff static const char *
parse_field(netdissect_options * ndo,const char ** pptr,int * len)87*ee67461eSJoseph Mingrone parse_field(netdissect_options *ndo, const char **pptr, int *len)
88a90e161bSBill Fenner {
893340d773SGleb Smirnoff const char *s;
90a90e161bSBill Fenner
910bff6a5aSEd Maste /* Start of string */
92a90e161bSBill Fenner s = *pptr;
930bff6a5aSEd Maste /* Scan for the NUL terminator */
940bff6a5aSEd Maste for (;;) {
950bff6a5aSEd Maste if (*len == 0) {
960bff6a5aSEd Maste /* Ran out of packet data without finding it */
970bff6a5aSEd Maste return NULL;
980bff6a5aSEd Maste }
99*ee67461eSJoseph Mingrone if (GET_U_1(*pptr) == '\0') {
1000bff6a5aSEd Maste /* Found it */
1010bff6a5aSEd Maste break;
1020bff6a5aSEd Maste }
1030bff6a5aSEd Maste /* Keep scanning */
104a90e161bSBill Fenner (*pptr)++;
105a90e161bSBill Fenner (*len)--;
106a90e161bSBill Fenner }
1070bff6a5aSEd Maste /* Skip the NUL terminator */
108a90e161bSBill Fenner (*pptr)++;
109a90e161bSBill Fenner (*len)--;
110a90e161bSBill Fenner return s;
111a90e161bSBill Fenner }
112a90e161bSBill Fenner
113a90e161bSBill Fenner static const char *
z_triple(const char * class,const char * inst,const char * recipient)1143340d773SGleb Smirnoff z_triple(const char *class, const char *inst, const char *recipient)
115a90e161bSBill Fenner {
116a90e161bSBill Fenner if (!*recipient)
117a90e161bSBill Fenner recipient = "*";
118a90e161bSBill Fenner snprintf(z_buf, sizeof(z_buf), "<%s,%s,%s>", class, inst, recipient);
119a90e161bSBill Fenner z_buf[sizeof(z_buf)-1] = '\0';
120a90e161bSBill Fenner return z_buf;
121a90e161bSBill Fenner }
122a90e161bSBill Fenner
123a90e161bSBill Fenner static const char *
str_to_lower(const char * string)1243340d773SGleb Smirnoff str_to_lower(const char *string)
125a90e161bSBill Fenner {
1263340d773SGleb Smirnoff char *zb_string;
1273340d773SGleb Smirnoff
128a90e161bSBill Fenner strncpy(z_buf, string, sizeof(z_buf));
129a90e161bSBill Fenner z_buf[sizeof(z_buf)-1] = '\0';
130a90e161bSBill Fenner
1313340d773SGleb Smirnoff zb_string = z_buf;
1323340d773SGleb Smirnoff while (*zb_string) {
133*ee67461eSJoseph Mingrone *zb_string = ND_ASCII_TOLOWER(*zb_string);
1343340d773SGleb Smirnoff zb_string++;
135a90e161bSBill Fenner }
136a90e161bSBill Fenner
137a90e161bSBill Fenner return z_buf;
138a90e161bSBill Fenner }
139a90e161bSBill Fenner
140*ee67461eSJoseph Mingrone #define ZEPHYR_PRINT(str1,str2) \
141*ee67461eSJoseph Mingrone { ND_PRINT("%s", (str1)); fn_print_str(ndo, (const u_char *)(str2)); }
142*ee67461eSJoseph Mingrone
143a90e161bSBill Fenner void
zephyr_print(netdissect_options * ndo,const u_char * cp,u_int length)144*ee67461eSJoseph Mingrone zephyr_print(netdissect_options *ndo, const u_char *cp, u_int length)
145a90e161bSBill Fenner {
146*ee67461eSJoseph Mingrone struct z_packet z = {
147*ee67461eSJoseph Mingrone NULL, /* version */
148*ee67461eSJoseph Mingrone 0, /* numfields */
149*ee67461eSJoseph Mingrone 0, /* kind */
150*ee67461eSJoseph Mingrone NULL, /* uid */
151*ee67461eSJoseph Mingrone 0, /* port */
152*ee67461eSJoseph Mingrone 0, /* auth */
153*ee67461eSJoseph Mingrone 0, /* authlen */
154*ee67461eSJoseph Mingrone NULL, /* authdata */
155*ee67461eSJoseph Mingrone NULL, /* class */
156*ee67461eSJoseph Mingrone NULL, /* inst */
157*ee67461eSJoseph Mingrone NULL, /* opcode */
158*ee67461eSJoseph Mingrone NULL, /* sender */
159*ee67461eSJoseph Mingrone NULL, /* recipient */
160*ee67461eSJoseph Mingrone NULL, /* format */
161*ee67461eSJoseph Mingrone 0, /* cksum */
162*ee67461eSJoseph Mingrone 0, /* multi */
163*ee67461eSJoseph Mingrone NULL /* multi_uid */
164*ee67461eSJoseph Mingrone };
1653340d773SGleb Smirnoff const char *parse = (const char *) cp;
166a90e161bSBill Fenner int parselen = length;
1673340d773SGleb Smirnoff const char *s;
168a90e161bSBill Fenner int lose = 0;
169a90e161bSBill Fenner
170*ee67461eSJoseph Mingrone ndo->ndo_protocol = "zephyr";
171a5779b6eSRui Paulo /* squelch compiler warnings */
172a5779b6eSRui Paulo
173a90e161bSBill Fenner #define PARSE_STRING \
174*ee67461eSJoseph Mingrone s = parse_field(ndo, &parse, &parselen); \
175a90e161bSBill Fenner if (!s) lose = 1;
176a90e161bSBill Fenner
177a90e161bSBill Fenner #define PARSE_FIELD_INT(field) \
178a90e161bSBill Fenner PARSE_STRING \
179a90e161bSBill Fenner if (!lose) field = strtol(s, 0, 16);
180a90e161bSBill Fenner
181a90e161bSBill Fenner #define PARSE_FIELD_STR(field) \
182a90e161bSBill Fenner PARSE_STRING \
183a90e161bSBill Fenner if (!lose) field = s;
184a90e161bSBill Fenner
185a90e161bSBill Fenner PARSE_FIELD_STR(z.version);
186*ee67461eSJoseph Mingrone if (lose)
187*ee67461eSJoseph Mingrone goto invalid;
188*ee67461eSJoseph Mingrone
189a90e161bSBill Fenner if (strncmp(z.version, "ZEPH", 4))
190a90e161bSBill Fenner return;
191a90e161bSBill Fenner
192a90e161bSBill Fenner PARSE_FIELD_INT(z.numfields);
193a90e161bSBill Fenner PARSE_FIELD_INT(z.kind);
194a90e161bSBill Fenner PARSE_FIELD_STR(z.uid);
195a90e161bSBill Fenner PARSE_FIELD_INT(z.port);
196a90e161bSBill Fenner PARSE_FIELD_INT(z.auth);
197a90e161bSBill Fenner PARSE_FIELD_INT(z.authlen);
198a90e161bSBill Fenner PARSE_FIELD_STR(z.authdata);
199a90e161bSBill Fenner PARSE_FIELD_STR(z.class);
200a90e161bSBill Fenner PARSE_FIELD_STR(z.inst);
201a90e161bSBill Fenner PARSE_FIELD_STR(z.opcode);
202a90e161bSBill Fenner PARSE_FIELD_STR(z.sender);
203a90e161bSBill Fenner PARSE_FIELD_STR(z.recipient);
204a90e161bSBill Fenner PARSE_FIELD_STR(z.format);
205a90e161bSBill Fenner PARSE_FIELD_INT(z.cksum);
206a90e161bSBill Fenner PARSE_FIELD_INT(z.multi);
207a90e161bSBill Fenner PARSE_FIELD_STR(z.multi_uid);
208a90e161bSBill Fenner
2090bff6a5aSEd Maste if (lose)
210*ee67461eSJoseph Mingrone goto invalid;
211a90e161bSBill Fenner
212*ee67461eSJoseph Mingrone ND_PRINT(" zephyr");
213a90e161bSBill Fenner if (strncmp(z.version+4, "0.2", 3)) {
214*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" v", z.version+4)
215a90e161bSBill Fenner return;
216a90e161bSBill Fenner }
217a90e161bSBill Fenner
218*ee67461eSJoseph Mingrone ND_PRINT(" %s", tok2str(z_types, "type %d", z.kind));
219a90e161bSBill Fenner if (z.kind == Z_PACKET_SERVACK) {
220a90e161bSBill Fenner /* Initialization to silence warnings */
2213340d773SGleb Smirnoff const char *ackdata = NULL;
222a90e161bSBill Fenner PARSE_FIELD_STR(ackdata);
223a90e161bSBill Fenner if (!lose && strcmp(ackdata, "SENT"))
224*ee67461eSJoseph Mingrone ZEPHYR_PRINT("/", str_to_lower(ackdata))
225a90e161bSBill Fenner }
226*ee67461eSJoseph Mingrone if (*z.sender) ZEPHYR_PRINT(" ", z.sender);
227a90e161bSBill Fenner
228a90e161bSBill Fenner if (!strcmp(z.class, "USER_LOCATE")) {
229a90e161bSBill Fenner if (!strcmp(z.opcode, "USER_HIDE"))
230*ee67461eSJoseph Mingrone ND_PRINT(" hide");
231a90e161bSBill Fenner else if (!strcmp(z.opcode, "USER_UNHIDE"))
232*ee67461eSJoseph Mingrone ND_PRINT(" unhide");
233a90e161bSBill Fenner else
234*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" locate ", z.inst);
235a90e161bSBill Fenner return;
236a90e161bSBill Fenner }
237a90e161bSBill Fenner
238a90e161bSBill Fenner if (!strcmp(z.class, "ZEPHYR_ADMIN")) {
239*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" zephyr-admin ", str_to_lower(z.opcode));
240a90e161bSBill Fenner return;
241a90e161bSBill Fenner }
242a90e161bSBill Fenner
243a90e161bSBill Fenner if (!strcmp(z.class, "ZEPHYR_CTL")) {
244a90e161bSBill Fenner if (!strcmp(z.inst, "CLIENT")) {
245a90e161bSBill Fenner if (!strcmp(z.opcode, "SUBSCRIBE") ||
246a90e161bSBill Fenner !strcmp(z.opcode, "SUBSCRIBE_NODEFS") ||
247a90e161bSBill Fenner !strcmp(z.opcode, "UNSUBSCRIBE")) {
248a90e161bSBill Fenner
249*ee67461eSJoseph Mingrone ND_PRINT(" %ssub%s", strcmp(z.opcode, "SUBSCRIBE") ? "un" : "",
250a90e161bSBill Fenner strcmp(z.opcode, "SUBSCRIBE_NODEFS") ? "" :
251*ee67461eSJoseph Mingrone "-nodefs");
252a90e161bSBill Fenner if (z.kind != Z_PACKET_SERVACK) {
253a90e161bSBill Fenner /* Initialization to silence warnings */
2543340d773SGleb Smirnoff const char *c = NULL, *i = NULL, *r = NULL;
255a90e161bSBill Fenner PARSE_FIELD_STR(c);
256a90e161bSBill Fenner PARSE_FIELD_STR(i);
257a90e161bSBill Fenner PARSE_FIELD_STR(r);
258*ee67461eSJoseph Mingrone if (!lose) ZEPHYR_PRINT(" ", z_triple(c, i, r));
259a90e161bSBill Fenner }
260a90e161bSBill Fenner return;
261a90e161bSBill Fenner }
262a90e161bSBill Fenner
263a90e161bSBill Fenner if (!strcmp(z.opcode, "GIMME")) {
264*ee67461eSJoseph Mingrone ND_PRINT(" ret");
265a90e161bSBill Fenner return;
266a90e161bSBill Fenner }
267a90e161bSBill Fenner
268a90e161bSBill Fenner if (!strcmp(z.opcode, "GIMMEDEFS")) {
269*ee67461eSJoseph Mingrone ND_PRINT(" gimme-defs");
270a90e161bSBill Fenner return;
271a90e161bSBill Fenner }
272a90e161bSBill Fenner
273a90e161bSBill Fenner if (!strcmp(z.opcode, "CLEARSUB")) {
274*ee67461eSJoseph Mingrone ND_PRINT(" clear-subs");
275a90e161bSBill Fenner return;
276a90e161bSBill Fenner }
277a90e161bSBill Fenner
278*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" ", str_to_lower(z.opcode));
279a90e161bSBill Fenner return;
280a90e161bSBill Fenner }
281a90e161bSBill Fenner
282a90e161bSBill Fenner if (!strcmp(z.inst, "HM")) {
283*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" ", str_to_lower(z.opcode));
284a90e161bSBill Fenner return;
285a90e161bSBill Fenner }
286a90e161bSBill Fenner
287a90e161bSBill Fenner if (!strcmp(z.inst, "REALM")) {
288a90e161bSBill Fenner if (!strcmp(z.opcode, "ADD_SUBSCRIBE"))
289*ee67461eSJoseph Mingrone ND_PRINT(" realm add-subs");
290a90e161bSBill Fenner if (!strcmp(z.opcode, "REQ_SUBSCRIBE"))
291*ee67461eSJoseph Mingrone ND_PRINT(" realm req-subs");
292a90e161bSBill Fenner if (!strcmp(z.opcode, "RLM_SUBSCRIBE"))
293*ee67461eSJoseph Mingrone ND_PRINT(" realm rlm-sub");
294a90e161bSBill Fenner if (!strcmp(z.opcode, "RLM_UNSUBSCRIBE"))
295*ee67461eSJoseph Mingrone ND_PRINT(" realm rlm-unsub");
296a90e161bSBill Fenner return;
297a90e161bSBill Fenner }
298a90e161bSBill Fenner }
299a90e161bSBill Fenner
300a90e161bSBill Fenner if (!strcmp(z.class, "HM_CTL")) {
301*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" hm_ctl ", str_to_lower(z.inst));
302*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" ", str_to_lower(z.opcode));
303a90e161bSBill Fenner return;
304a90e161bSBill Fenner }
305a90e161bSBill Fenner
306a90e161bSBill Fenner if (!strcmp(z.class, "HM_STAT")) {
307a90e161bSBill Fenner if (!strcmp(z.inst, "HMST_CLIENT") && !strcmp(z.opcode, "GIMMESTATS")) {
308*ee67461eSJoseph Mingrone ND_PRINT(" get-client-stats");
309a90e161bSBill Fenner return;
310a90e161bSBill Fenner }
311a90e161bSBill Fenner }
312a90e161bSBill Fenner
313a90e161bSBill Fenner if (!strcmp(z.class, "WG_CTL")) {
314*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" wg_ctl ", str_to_lower(z.inst));
315*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" ", str_to_lower(z.opcode));
316a90e161bSBill Fenner return;
317a90e161bSBill Fenner }
318a90e161bSBill Fenner
319a90e161bSBill Fenner if (!strcmp(z.class, "LOGIN")) {
320a90e161bSBill Fenner if (!strcmp(z.opcode, "USER_FLUSH")) {
321*ee67461eSJoseph Mingrone ND_PRINT(" flush_locs");
322a90e161bSBill Fenner return;
323a90e161bSBill Fenner }
324a90e161bSBill Fenner
325a90e161bSBill Fenner if (!strcmp(z.opcode, "NONE") ||
326a90e161bSBill Fenner !strcmp(z.opcode, "OPSTAFF") ||
327a90e161bSBill Fenner !strcmp(z.opcode, "REALM-VISIBLE") ||
328a90e161bSBill Fenner !strcmp(z.opcode, "REALM-ANNOUNCED") ||
329a90e161bSBill Fenner !strcmp(z.opcode, "NET-VISIBLE") ||
330a90e161bSBill Fenner !strcmp(z.opcode, "NET-ANNOUNCED")) {
331*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" set-exposure ", str_to_lower(z.opcode));
332a90e161bSBill Fenner return;
333a90e161bSBill Fenner }
334a90e161bSBill Fenner }
335a90e161bSBill Fenner
336a90e161bSBill Fenner if (!*z.recipient)
337a90e161bSBill Fenner z.recipient = "*";
338a90e161bSBill Fenner
339*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" to ", z_triple(z.class, z.inst, z.recipient));
340a90e161bSBill Fenner if (*z.opcode)
341*ee67461eSJoseph Mingrone ZEPHYR_PRINT(" op ", z.opcode);
3420bff6a5aSEd Maste return;
3430bff6a5aSEd Maste
344*ee67461eSJoseph Mingrone invalid:
345*ee67461eSJoseph Mingrone nd_print_invalid(ndo);
346a90e161bSBill Fenner }
347