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