diff options
author | delphij <delphij@FreeBSD.org> | 2015-01-07 19:55:18 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2015-01-07 19:55:18 +0000 |
commit | f49c5d523af9076a4a59e8dd664f9a897108432e (patch) | |
tree | e268839e08c106e178b33bd461d8d0a9c6fb5ad9 /contrib/tcpdump/print-ahcp.c | |
parent | c371846049d370ab78d943e60e789cdffe0aad3d (diff) | |
parent | 08263d19579d35a7a65e0c8bcb768504ce76d04e (diff) | |
download | FreeBSD-src-f49c5d523af9076a4a59e8dd664f9a897108432e.zip FreeBSD-src-f49c5d523af9076a4a59e8dd664f9a897108432e.tar.gz |
MFV r276761: tcpdump 4.6.2.
MFC after: 1 month
Diffstat (limited to 'contrib/tcpdump/print-ahcp.c')
-rw-r--r-- | contrib/tcpdump/print-ahcp.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/contrib/tcpdump/print-ahcp.c b/contrib/tcpdump/print-ahcp.c new file mode 100644 index 0000000..280372d --- /dev/null +++ b/contrib/tcpdump/print-ahcp.c @@ -0,0 +1,413 @@ +/* + * 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. + */ + +#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)); +} + |