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