
For now, printing of Sun RPC requests is disabled because we do not yet have the RPC header files. This should affect basically noone, as we do not have any RPC-based programs yet, for the same reason. Change-Id: Ie7818faaaacdc104d8b2c37a68866b4ce18247d6
427 lines
11 KiB
C
427 lines
11 KiB
C
/*
|
|
* This module implements decoding of AHCP (Ad Hoc Configuration Protocol) based
|
|
* on draft-chroboczek-ahcp-00 and source code of ahcpd-0.53.
|
|
*
|
|
*
|
|
* Copyright (c) 2013 The TCPDUMP project
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: print-ahcp.c,v 1.3 2015/03/31 21:59:35 christos Exp $");
|
|
#endif
|
|
|
|
#define NETDISSECT_REWORKED
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <tcpdump-stdinc.h>
|
|
|
|
#include "interface.h"
|
|
#include "extract.h"
|
|
#include "addrtoname.h"
|
|
|
|
static const char tstr[] = " [|ahcp]";
|
|
static const char cstr[] = "(corrupt)";
|
|
|
|
#define AHCP_MAGIC_NUMBER 43
|
|
#define AHCP_VERSION_1 1
|
|
#define AHCP1_HEADER_FIX_LEN 24
|
|
#define AHCP1_BODY_MIN_LEN 4
|
|
|
|
#define AHCP1_MSG_DISCOVER 0
|
|
#define AHCP1_MSG_OFFER 1
|
|
#define AHCP1_MSG_REQUEST 2
|
|
#define AHCP1_MSG_ACK 3
|
|
#define AHCP1_MSG_NACK 4
|
|
#define AHCP1_MSG_RELEASE 5
|
|
|
|
static const struct tok ahcp1_msg_str[] = {
|
|
{ AHCP1_MSG_DISCOVER, "Discover" },
|
|
{ AHCP1_MSG_OFFER, "Offer" },
|
|
{ AHCP1_MSG_REQUEST, "Request" },
|
|
{ AHCP1_MSG_ACK, "Ack" },
|
|
{ AHCP1_MSG_NACK, "Nack" },
|
|
{ AHCP1_MSG_RELEASE, "Release" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
#define AHCP1_OPT_PAD 0
|
|
#define AHCP1_OPT_MANDATORY 1
|
|
#define AHCP1_OPT_ORIGIN_TIME 2
|
|
#define AHCP1_OPT_EXPIRES 3
|
|
#define AHCP1_OPT_MY_IPV6_ADDRESS 4
|
|
#define AHCP1_OPT_MY_IPV4_ADDRESS 5
|
|
#define AHCP1_OPT_IPV6_PREFIX 6
|
|
#define AHCP1_OPT_IPV4_PREFIX 7
|
|
#define AHCP1_OPT_IPV6_ADDRESS 8
|
|
#define AHCP1_OPT_IPV4_ADDRESS 9
|
|
#define AHCP1_OPT_IPV6_PREFIX_DELEGATION 10
|
|
#define AHCP1_OPT_IPV4_PREFIX_DELEGATION 11
|
|
#define AHCP1_OPT_NAME_SERVER 12
|
|
#define AHCP1_OPT_NTP_SERVER 13
|
|
#define AHCP1_OPT_MAX 13
|
|
|
|
static const struct tok ahcp1_opt_str[] = {
|
|
{ AHCP1_OPT_PAD, "Pad" },
|
|
{ AHCP1_OPT_MANDATORY, "Mandatory" },
|
|
{ AHCP1_OPT_ORIGIN_TIME, "Origin Time" },
|
|
{ AHCP1_OPT_EXPIRES, "Expires" },
|
|
{ AHCP1_OPT_MY_IPV6_ADDRESS, "My-IPv6-Address" },
|
|
{ AHCP1_OPT_MY_IPV4_ADDRESS, "My-IPv4-Address" },
|
|
{ AHCP1_OPT_IPV6_PREFIX, "IPv6 Prefix" },
|
|
{ AHCP1_OPT_IPV4_PREFIX, "IPv4 Prefix" },
|
|
{ AHCP1_OPT_IPV6_ADDRESS, "IPv6 Address" },
|
|
{ AHCP1_OPT_IPV4_ADDRESS, "IPv4 Address" },
|
|
{ AHCP1_OPT_IPV6_PREFIX_DELEGATION, "IPv6 Prefix Delegation" },
|
|
{ AHCP1_OPT_IPV4_PREFIX_DELEGATION, "IPv4 Prefix Delegation" },
|
|
{ AHCP1_OPT_NAME_SERVER, "Name Server" },
|
|
{ AHCP1_OPT_NTP_SERVER, "NTP Server" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static int
|
|
ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
time_t t;
|
|
struct tm *tm;
|
|
char buf[BUFSIZE];
|
|
|
|
if (cp + 4 != ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 4);
|
|
t = EXTRACT_32BITS(cp);
|
|
if (NULL == (tm = gmtime(&t)))
|
|
ND_PRINT((ndo, ": gmtime() error"));
|
|
else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
|
|
ND_PRINT((ndo, ": strftime() error"));
|
|
else
|
|
ND_PRINT((ndo, ": %s UTC", buf));
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
if (cp + 4 != ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 4);
|
|
ND_PRINT((ndo, ": %us", EXTRACT_32BITS(cp)));
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
const char *sep = ": ";
|
|
|
|
while (cp < ep) {
|
|
if (cp + 16 > ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 16);
|
|
#ifdef INET6
|
|
ND_PRINT((ndo, "%s%s", sep, ip6addr_string(ndo, cp)));
|
|
#else
|
|
ND_PRINT((ndo, "%s(compiled w/o IPv6)", sep));
|
|
#endif /* INET6 */
|
|
cp += 16;
|
|
sep = ", ";
|
|
}
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ahcp_ipv4_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
const char *sep = ": ";
|
|
|
|
while (cp < ep) {
|
|
if (cp + 4 > ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 4);
|
|
ND_PRINT((ndo, "%s%s", sep, ipaddr_string(ndo, cp)));
|
|
cp += 4;
|
|
sep = ", ";
|
|
}
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ahcp_ipv6_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
const char *sep = ": ";
|
|
|
|
while (cp < ep) {
|
|
if (cp + 17 > ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 17);
|
|
#ifdef INET6
|
|
ND_PRINT((ndo, "%s%s/%u", sep, ip6addr_string(ndo, cp), *(cp + 16)));
|
|
#else
|
|
ND_PRINT((ndo, "%s(compiled w/o IPv6)/%u", sep, *(cp + 16)));
|
|
#endif /* INET6 */
|
|
cp += 17;
|
|
sep = ", ";
|
|
}
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
const char *sep = ": ";
|
|
|
|
while (cp < ep) {
|
|
if (cp + 5 > ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 5);
|
|
ND_PRINT((ndo, "%s%s/%u", sep, ipaddr_string(ndo, cp), *(cp + 4)));
|
|
cp += 5;
|
|
sep = ", ";
|
|
}
|
|
return 0;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, ": %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return 0;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
return -1;
|
|
}
|
|
|
|
/* Data decoders signal truncated data with -1. */
|
|
static int
|
|
(* const data_decoders[AHCP1_OPT_MAX + 1])(netdissect_options *, const u_char *, const u_char *) = {
|
|
/* [AHCP1_OPT_PAD] = */ NULL,
|
|
/* [AHCP1_OPT_MANDATORY] = */ NULL,
|
|
/* [AHCP1_OPT_ORIGIN_TIME] = */ ahcp_time_print,
|
|
/* [AHCP1_OPT_EXPIRES] = */ ahcp_seconds_print,
|
|
/* [AHCP1_OPT_MY_IPV6_ADDRESS] = */ ahcp_ipv6_addresses_print,
|
|
/* [AHCP1_OPT_MY_IPV4_ADDRESS] = */ ahcp_ipv4_addresses_print,
|
|
/* [AHCP1_OPT_IPV6_PREFIX] = */ ahcp_ipv6_prefixes_print,
|
|
/* [AHCP1_OPT_IPV4_PREFIX] = */ NULL,
|
|
/* [AHCP1_OPT_IPV6_ADDRESS] = */ ahcp_ipv6_addresses_print,
|
|
/* [AHCP1_OPT_IPV4_ADDRESS] = */ ahcp_ipv4_addresses_print,
|
|
/* [AHCP1_OPT_IPV6_PREFIX_DELEGATION] = */ ahcp_ipv6_prefixes_print,
|
|
/* [AHCP1_OPT_IPV4_PREFIX_DELEGATION] = */ ahcp_ipv4_prefixes_print,
|
|
/* [AHCP1_OPT_NAME_SERVER] = */ ahcp_ipv6_addresses_print,
|
|
/* [AHCP1_OPT_NTP_SERVER] = */ ahcp_ipv6_addresses_print,
|
|
};
|
|
|
|
static void
|
|
ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
uint8_t option_no, option_len;
|
|
|
|
while (cp < ep) {
|
|
/* Option no */
|
|
ND_TCHECK2(*cp, 1);
|
|
option_no = *cp;
|
|
cp += 1;
|
|
ND_PRINT((ndo, "\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)));
|
|
if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
|
|
continue;
|
|
/* Length */
|
|
if (cp + 1 > ep)
|
|
goto corrupt;
|
|
ND_TCHECK2(*cp, 1);
|
|
option_len = *cp;
|
|
cp += 1;
|
|
if (cp + option_len > ep)
|
|
goto corrupt;
|
|
/* Value */
|
|
if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
|
|
if (data_decoders[option_no](ndo, cp, cp + option_len) < 0)
|
|
break; /* truncated and already marked up */
|
|
} else {
|
|
ND_PRINT((ndo, " (Length %u)", option_len));
|
|
ND_TCHECK2(*cp, option_len);
|
|
}
|
|
cp += option_len;
|
|
}
|
|
return;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, " %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
}
|
|
|
|
static void
|
|
ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
|
|
{
|
|
uint8_t type, mbz;
|
|
uint16_t body_len;
|
|
|
|
if (cp + AHCP1_BODY_MIN_LEN > ep)
|
|
goto corrupt;
|
|
/* Type */
|
|
ND_TCHECK2(*cp, 1);
|
|
type = *cp;
|
|
cp += 1;
|
|
/* MBZ */
|
|
ND_TCHECK2(*cp, 1);
|
|
mbz = *cp;
|
|
cp += 1;
|
|
/* Length */
|
|
ND_TCHECK2(*cp, 2);
|
|
body_len = EXTRACT_16BITS(cp);
|
|
cp += 2;
|
|
|
|
if (ndo->ndo_vflag) {
|
|
ND_PRINT((ndo, "\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)));
|
|
if (mbz != 0)
|
|
ND_PRINT((ndo, ", MBZ %u", mbz));
|
|
ND_PRINT((ndo, ", Length %u", body_len));
|
|
}
|
|
if (cp + body_len > ep)
|
|
goto corrupt;
|
|
|
|
/* Options */
|
|
if (ndo->ndo_vflag >= 2)
|
|
ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */
|
|
else
|
|
ND_TCHECK2(*cp, body_len);
|
|
return;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, " %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
}
|
|
|
|
void
|
|
ahcp_print(netdissect_options *ndo, const u_char *cp, const u_int len)
|
|
{
|
|
const u_char *ep = cp + len;
|
|
uint8_t version;
|
|
|
|
ND_PRINT((ndo, "AHCP"));
|
|
if (len < 2)
|
|
goto corrupt;
|
|
/* Magic */
|
|
ND_TCHECK2(*cp, 1);
|
|
if (*cp != AHCP_MAGIC_NUMBER)
|
|
goto corrupt;
|
|
cp += 1;
|
|
/* Version */
|
|
ND_TCHECK2(*cp, 1);
|
|
version = *cp;
|
|
cp += 1;
|
|
switch (version) {
|
|
case AHCP_VERSION_1: {
|
|
ND_PRINT((ndo, " Version 1"));
|
|
if (len < AHCP1_HEADER_FIX_LEN)
|
|
goto corrupt;
|
|
if (!ndo->ndo_vflag) {
|
|
ND_TCHECK2(*cp, AHCP1_HEADER_FIX_LEN - 2);
|
|
cp += AHCP1_HEADER_FIX_LEN - 2;
|
|
} else {
|
|
/* Hopcount */
|
|
ND_TCHECK2(*cp, 1);
|
|
ND_PRINT((ndo, "\n\tHopcount %u", *cp));
|
|
cp += 1;
|
|
/* Original Hopcount */
|
|
ND_TCHECK2(*cp, 1);
|
|
ND_PRINT((ndo, ", Original Hopcount %u", *cp));
|
|
cp += 1;
|
|
/* Nonce */
|
|
ND_TCHECK2(*cp, 4);
|
|
ND_PRINT((ndo, ", Nonce 0x%08x", EXTRACT_32BITS(cp)));
|
|
cp += 4;
|
|
/* Source Id */
|
|
ND_TCHECK2(*cp, 8);
|
|
ND_PRINT((ndo, ", Source Id %s", linkaddr_string(ndo, cp, 0, 8)));
|
|
cp += 8;
|
|
/* Destination Id */
|
|
ND_TCHECK2(*cp, 8);
|
|
ND_PRINT((ndo, ", Destination Id %s", linkaddr_string(ndo, cp, 0, 8)));
|
|
cp += 8;
|
|
}
|
|
/* Body */
|
|
ahcp1_body_print(ndo, cp, ep);
|
|
break;
|
|
}
|
|
default:
|
|
ND_PRINT((ndo, " Version %u (unknown)", version));
|
|
break;
|
|
}
|
|
return;
|
|
|
|
corrupt:
|
|
ND_PRINT((ndo, " %s", cstr));
|
|
ND_TCHECK2(*cp, ep - cp);
|
|
return;
|
|
trunc:
|
|
ND_PRINT((ndo, "%s", tstr));
|
|
}
|