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