198524Sfenner/*
298524Sfenner * Decode and print Zephyr packets.
398524Sfenner *
4147899Ssam *	http://web.mit.edu/zephyr/doc/protocol
5147899Ssam *
698524Sfenner * Copyright (c) 2001 Nickolai Zeldovich <kolya@MIT.EDU>
798524Sfenner * All rights reserved.
898524Sfenner *
998524Sfenner * Redistribution and use in source and binary forms, with or without
1098524Sfenner * modification, are permitted provided that: (1) source code
1198524Sfenner * distributions retain the above copyright notice and this paragraph
1298524Sfenner * in its entirety, and (2) distributions including binary code include
1398524Sfenner * the above copyright notice and this paragraph in its entirety in
1498524Sfenner * the documentation or other materials provided with the distribution.
1598524Sfenner * The name of the author(s) may not be used to endorse or promote
1698524Sfenner * products derived from this software without specific prior written
1798524Sfenner * permission.  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
1898524Sfenner * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
1998524Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2098524Sfenner * PURPOSE.
2198524Sfenner */
2298524Sfenner
2398524Sfenner#ifndef lint
24127668Sbmsstatic const char rcsid[] _U_ =
25190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-zephyr.c,v 1.10 2007-08-09 18:47:27 hannes Exp $";
2698524Sfenner#endif
2798524Sfenner
2898524Sfenner#ifdef HAVE_CONFIG_H
2998524Sfenner#include "config.h"
3098524Sfenner#endif
3198524Sfenner
32127668Sbms#include <tcpdump-stdinc.h>
33127668Sbms
3498524Sfenner#include <stdio.h>
3598524Sfenner#include <string.h>
3698524Sfenner#include <stdlib.h>
3798524Sfenner
3898524Sfenner#include "interface.h"
3998524Sfenner
4098524Sfennerstruct z_packet {
4198524Sfenner    char *version;
4298524Sfenner    int numfields;
4398524Sfenner    int kind;
4498524Sfenner    char *uid;
4598524Sfenner    int port;
4698524Sfenner    int auth;
4798524Sfenner    int authlen;
4898524Sfenner    char *authdata;
4998524Sfenner    char *class;
5098524Sfenner    char *inst;
5198524Sfenner    char *opcode;
5298524Sfenner    char *sender;
53127668Sbms    const char *recipient;
5498524Sfenner    char *format;
5598524Sfenner    int cksum;
5698524Sfenner    int multi;
5798524Sfenner    char *multi_uid;
5898524Sfenner    /* Other fields follow here.. */
5998524Sfenner};
6098524Sfenner
61111726Sfennerenum z_packet_type {
6298524Sfenner    Z_PACKET_UNSAFE = 0,
6398524Sfenner    Z_PACKET_UNACKED,
6498524Sfenner    Z_PACKET_ACKED,
6598524Sfenner    Z_PACKET_HMACK,
6698524Sfenner    Z_PACKET_HMCTL,
6798524Sfenner    Z_PACKET_SERVACK,
6898524Sfenner    Z_PACKET_SERVNAK,
6998524Sfenner    Z_PACKET_CLIENTACK,
7098524Sfenner    Z_PACKET_STAT
71111726Sfenner};
7298524Sfenner
7398524Sfennerstatic struct tok z_types[] = {
7498524Sfenner    { Z_PACKET_UNSAFE,		"unsafe" },
7598524Sfenner    { Z_PACKET_UNACKED,		"unacked" },
7698524Sfenner    { Z_PACKET_ACKED,		"acked" },
7798524Sfenner    { Z_PACKET_HMACK,		"hm-ack" },
7898524Sfenner    { Z_PACKET_HMCTL,		"hm-ctl" },
7998524Sfenner    { Z_PACKET_SERVACK,		"serv-ack" },
8098524Sfenner    { Z_PACKET_SERVNAK,		"serv-nak" },
8198524Sfenner    { Z_PACKET_CLIENTACK,	"client-ack" },
8298524Sfenner    { Z_PACKET_STAT,		"stat" }
8398524Sfenner};
8498524Sfenner
8598524Sfennerchar z_buf[256];
8698524Sfenner
8798524Sfennerstatic char *
8898524Sfennerparse_field(char **pptr, int *len)
8998524Sfenner{
9098524Sfenner    char *s;
9198524Sfenner
9298524Sfenner    if (*len <= 0 || !pptr || !*pptr)
9398524Sfenner	return NULL;
9498524Sfenner    if (*pptr > (char *) snapend)
9598524Sfenner	return NULL;
9698524Sfenner
9798524Sfenner    s = *pptr;
9898524Sfenner    while (*pptr <= (char *) snapend && *len >= 0 && **pptr) {
9998524Sfenner	(*pptr)++;
10098524Sfenner	(*len)--;
10198524Sfenner    }
10298524Sfenner    (*pptr)++;
10398524Sfenner    (*len)--;
10498524Sfenner    if (*len < 0 || *pptr > (char *) snapend)
10598524Sfenner	return NULL;
10698524Sfenner    return s;
10798524Sfenner}
10898524Sfenner
10998524Sfennerstatic const char *
110127668Sbmsz_triple(char *class, char *inst, const char *recipient)
11198524Sfenner{
11298524Sfenner    if (!*recipient)
11398524Sfenner	recipient = "*";
11498524Sfenner    snprintf(z_buf, sizeof(z_buf), "<%s,%s,%s>", class, inst, recipient);
11598524Sfenner    z_buf[sizeof(z_buf)-1] = '\0';
11698524Sfenner    return z_buf;
11798524Sfenner}
11898524Sfenner
11998524Sfennerstatic const char *
12098524Sfennerstr_to_lower(char *string)
12198524Sfenner{
12298524Sfenner    strncpy(z_buf, string, sizeof(z_buf));
12398524Sfenner    z_buf[sizeof(z_buf)-1] = '\0';
12498524Sfenner
12598524Sfenner    string = z_buf;
12698524Sfenner    while (*string) {
127111726Sfenner	*string = tolower((unsigned char)(*string));
12898524Sfenner	string++;
12998524Sfenner    }
13098524Sfenner
13198524Sfenner    return z_buf;
13298524Sfenner}
13398524Sfenner
13498524Sfennervoid
13598524Sfennerzephyr_print(const u_char *cp, int length)
13698524Sfenner{
13798524Sfenner    struct z_packet z;
13898524Sfenner    char *parse = (char *) cp;
13998524Sfenner    int parselen = length;
14098524Sfenner    char *s;
14198524Sfenner    int lose = 0;
14298524Sfenner
143190207Srpaulo    /* squelch compiler warnings */
144190207Srpaulo
145190207Srpaulo    z.kind = 0;
146190207Srpaulo    z.class = 0;
147190207Srpaulo    z.inst = 0;
148190207Srpaulo    z.opcode = 0;
149190207Srpaulo    z.sender = 0;
150190207Srpaulo    z.recipient = 0;
151190207Srpaulo
15298524Sfenner#define PARSE_STRING				\
15398524Sfenner	s = parse_field(&parse, &parselen);	\
15498524Sfenner	if (!s) lose = 1;
15598524Sfenner
15698524Sfenner#define PARSE_FIELD_INT(field)			\
15798524Sfenner	PARSE_STRING				\
15898524Sfenner	if (!lose) field = strtol(s, 0, 16);
15998524Sfenner
16098524Sfenner#define PARSE_FIELD_STR(field)			\
16198524Sfenner	PARSE_STRING				\
16298524Sfenner	if (!lose) field = s;
16398524Sfenner
16498524Sfenner    PARSE_FIELD_STR(z.version);
16598524Sfenner    if (lose) return;
16698524Sfenner    if (strncmp(z.version, "ZEPH", 4))
16798524Sfenner	return;
16898524Sfenner
16998524Sfenner    PARSE_FIELD_INT(z.numfields);
17098524Sfenner    PARSE_FIELD_INT(z.kind);
17198524Sfenner    PARSE_FIELD_STR(z.uid);
17298524Sfenner    PARSE_FIELD_INT(z.port);
17398524Sfenner    PARSE_FIELD_INT(z.auth);
17498524Sfenner    PARSE_FIELD_INT(z.authlen);
17598524Sfenner    PARSE_FIELD_STR(z.authdata);
17698524Sfenner    PARSE_FIELD_STR(z.class);
17798524Sfenner    PARSE_FIELD_STR(z.inst);
17898524Sfenner    PARSE_FIELD_STR(z.opcode);
17998524Sfenner    PARSE_FIELD_STR(z.sender);
18098524Sfenner    PARSE_FIELD_STR(z.recipient);
18198524Sfenner    PARSE_FIELD_STR(z.format);
18298524Sfenner    PARSE_FIELD_INT(z.cksum);
18398524Sfenner    PARSE_FIELD_INT(z.multi);
18498524Sfenner    PARSE_FIELD_STR(z.multi_uid);
18598524Sfenner
18698524Sfenner    if (lose) {
18798524Sfenner	printf(" [|zephyr] (%d)", length);
18898524Sfenner	return;
18998524Sfenner    }
19098524Sfenner
19198524Sfenner    printf(" zephyr");
19298524Sfenner    if (strncmp(z.version+4, "0.2", 3)) {
19398524Sfenner	printf(" v%s", z.version+4);
19498524Sfenner	return;
19598524Sfenner    }
19698524Sfenner
19798524Sfenner    printf(" %s", tok2str(z_types, "type %d", z.kind));
19898524Sfenner    if (z.kind == Z_PACKET_SERVACK) {
19998524Sfenner	/* Initialization to silence warnings */
20098524Sfenner	char *ackdata = NULL;
20198524Sfenner	PARSE_FIELD_STR(ackdata);
20298524Sfenner	if (!lose && strcmp(ackdata, "SENT"))
20398524Sfenner	    printf("/%s", str_to_lower(ackdata));
20498524Sfenner    }
20598524Sfenner    if (*z.sender) printf(" %s", z.sender);
20698524Sfenner
20798524Sfenner    if (!strcmp(z.class, "USER_LOCATE")) {
20898524Sfenner	if (!strcmp(z.opcode, "USER_HIDE"))
20998524Sfenner	    printf(" hide");
21098524Sfenner	else if (!strcmp(z.opcode, "USER_UNHIDE"))
21198524Sfenner	    printf(" unhide");
21298524Sfenner	else
21398524Sfenner	    printf(" locate %s", z.inst);
21498524Sfenner	return;
21598524Sfenner    }
21698524Sfenner
21798524Sfenner    if (!strcmp(z.class, "ZEPHYR_ADMIN")) {
21898524Sfenner	printf(" zephyr-admin %s", str_to_lower(z.opcode));
21998524Sfenner	return;
22098524Sfenner    }
22198524Sfenner
22298524Sfenner    if (!strcmp(z.class, "ZEPHYR_CTL")) {
22398524Sfenner	if (!strcmp(z.inst, "CLIENT")) {
22498524Sfenner	    if (!strcmp(z.opcode, "SUBSCRIBE") ||
22598524Sfenner		!strcmp(z.opcode, "SUBSCRIBE_NODEFS") ||
22698524Sfenner		!strcmp(z.opcode, "UNSUBSCRIBE")) {
22798524Sfenner
22898524Sfenner		printf(" %ssub%s", strcmp(z.opcode, "SUBSCRIBE") ? "un" : "",
22998524Sfenner				   strcmp(z.opcode, "SUBSCRIBE_NODEFS") ? "" :
23098524Sfenner								   "-nodefs");
23198524Sfenner		if (z.kind != Z_PACKET_SERVACK) {
23298524Sfenner		    /* Initialization to silence warnings */
23398524Sfenner		    char *c = NULL, *i = NULL, *r = NULL;
23498524Sfenner		    PARSE_FIELD_STR(c);
23598524Sfenner		    PARSE_FIELD_STR(i);
23698524Sfenner		    PARSE_FIELD_STR(r);
23798524Sfenner		    if (!lose) printf(" %s", z_triple(c, i, r));
23898524Sfenner		}
23998524Sfenner		return;
24098524Sfenner	    }
24198524Sfenner
24298524Sfenner	    if (!strcmp(z.opcode, "GIMME")) {
24398524Sfenner		printf(" ret");
24498524Sfenner		return;
24598524Sfenner	    }
24698524Sfenner
24798524Sfenner	    if (!strcmp(z.opcode, "GIMMEDEFS")) {
24898524Sfenner		printf(" gimme-defs");
24998524Sfenner		return;
25098524Sfenner	    }
25198524Sfenner
25298524Sfenner	    if (!strcmp(z.opcode, "CLEARSUB")) {
25398524Sfenner		printf(" clear-subs");
25498524Sfenner		return;
25598524Sfenner	    }
25698524Sfenner
25798524Sfenner	    printf(" %s", str_to_lower(z.opcode));
25898524Sfenner	    return;
25998524Sfenner	}
26098524Sfenner
26198524Sfenner	if (!strcmp(z.inst, "HM")) {
26298524Sfenner	    printf(" %s", str_to_lower(z.opcode));
26398524Sfenner	    return;
26498524Sfenner	}
26598524Sfenner
26698524Sfenner	if (!strcmp(z.inst, "REALM")) {
26798524Sfenner	    if (!strcmp(z.opcode, "ADD_SUBSCRIBE"))
26898524Sfenner		printf(" realm add-subs");
26998524Sfenner	    if (!strcmp(z.opcode, "REQ_SUBSCRIBE"))
27098524Sfenner		printf(" realm req-subs");
27198524Sfenner	    if (!strcmp(z.opcode, "RLM_SUBSCRIBE"))
27298524Sfenner		printf(" realm rlm-sub");
27398524Sfenner	    if (!strcmp(z.opcode, "RLM_UNSUBSCRIBE"))
27498524Sfenner		printf(" realm rlm-unsub");
27598524Sfenner	    return;
27698524Sfenner	}
27798524Sfenner    }
27898524Sfenner
27998524Sfenner    if (!strcmp(z.class, "HM_CTL")) {
28098524Sfenner	printf(" hm_ctl %s", str_to_lower(z.inst));
28198524Sfenner	printf(" %s", str_to_lower(z.opcode));
28298524Sfenner	return;
28398524Sfenner    }
28498524Sfenner
28598524Sfenner    if (!strcmp(z.class, "HM_STAT")) {
28698524Sfenner	if (!strcmp(z.inst, "HMST_CLIENT") && !strcmp(z.opcode, "GIMMESTATS")) {
28798524Sfenner	    printf(" get-client-stats");
28898524Sfenner	    return;
28998524Sfenner	}
29098524Sfenner    }
29198524Sfenner
29298524Sfenner    if (!strcmp(z.class, "WG_CTL")) {
29398524Sfenner	printf(" wg_ctl %s", str_to_lower(z.inst));
29498524Sfenner	printf(" %s", str_to_lower(z.opcode));
29598524Sfenner	return;
29698524Sfenner    }
29798524Sfenner
29898524Sfenner    if (!strcmp(z.class, "LOGIN")) {
29998524Sfenner	if (!strcmp(z.opcode, "USER_FLUSH")) {
30098524Sfenner	    printf(" flush_locs");
30198524Sfenner	    return;
30298524Sfenner	}
30398524Sfenner
30498524Sfenner	if (!strcmp(z.opcode, "NONE") ||
30598524Sfenner	    !strcmp(z.opcode, "OPSTAFF") ||
30698524Sfenner	    !strcmp(z.opcode, "REALM-VISIBLE") ||
30798524Sfenner	    !strcmp(z.opcode, "REALM-ANNOUNCED") ||
30898524Sfenner	    !strcmp(z.opcode, "NET-VISIBLE") ||
30998524Sfenner	    !strcmp(z.opcode, "NET-ANNOUNCED")) {
31098524Sfenner	    printf(" set-exposure %s", str_to_lower(z.opcode));
31198524Sfenner	    return;
31298524Sfenner	}
31398524Sfenner    }
31498524Sfenner
31598524Sfenner    if (!*z.recipient)
31698524Sfenner	z.recipient = "*";
31798524Sfenner
31898524Sfenner    printf(" to %s", z_triple(z.class, z.inst, z.recipient));
31998524Sfenner    if (*z.opcode)
32098524Sfenner	printf(" op %s", z.opcode);
32198524Sfenner    return;
32298524Sfenner}
323