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