Home | History | Annotate | Line # | Download | only in dist
print-ahcp.c revision 1.1
      1 /*
      2  * This module implements decoding of AHCP (Ad Hoc Configuration Protocol) based
      3  * on draft-chroboczek-ahcp-00 and source code of ahcpd-0.53.
      4  *
      5  *
      6  * Copyright (c) 2013 The TCPDUMP project
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #define NETDISSECT_REWORKED
     33 #ifdef HAVE_CONFIG_H
     34 #include "config.h"
     35 #endif
     36 
     37 #include <tcpdump-stdinc.h>
     38 
     39 #include "interface.h"
     40 #include "extract.h"
     41 #include "addrtoname.h"
     42 
     43 static const char tstr[] = " [|ahcp]";
     44 static const char cstr[] = "(corrupt)";
     45 
     46 #define AHCP_MAGIC_NUMBER 43
     47 #define AHCP_VERSION_1 1
     48 #define AHCP1_HEADER_FIX_LEN 24
     49 #define AHCP1_BODY_MIN_LEN 4
     50 
     51 #define AHCP1_MSG_DISCOVER 0
     52 #define AHCP1_MSG_OFFER    1
     53 #define AHCP1_MSG_REQUEST  2
     54 #define AHCP1_MSG_ACK      3
     55 #define AHCP1_MSG_NACK     4
     56 #define AHCP1_MSG_RELEASE  5
     57 
     58 static const struct tok ahcp1_msg_str[] = {
     59 	{ AHCP1_MSG_DISCOVER, "Discover" },
     60 	{ AHCP1_MSG_OFFER,    "Offer"    },
     61 	{ AHCP1_MSG_REQUEST,  "Request"  },
     62 	{ AHCP1_MSG_ACK,      "Ack"      },
     63 	{ AHCP1_MSG_NACK,     "Nack"     },
     64 	{ AHCP1_MSG_RELEASE,  "Release"  },
     65 	{ 0, NULL }
     66 };
     67 
     68 #define AHCP1_OPT_PAD                     0
     69 #define AHCP1_OPT_MANDATORY               1
     70 #define AHCP1_OPT_ORIGIN_TIME             2
     71 #define AHCP1_OPT_EXPIRES                 3
     72 #define AHCP1_OPT_MY_IPV6_ADDRESS         4
     73 #define AHCP1_OPT_MY_IPV4_ADDRESS         5
     74 #define AHCP1_OPT_IPV6_PREFIX             6
     75 #define AHCP1_OPT_IPV4_PREFIX             7
     76 #define AHCP1_OPT_IPV6_ADDRESS            8
     77 #define AHCP1_OPT_IPV4_ADDRESS            9
     78 #define AHCP1_OPT_IPV6_PREFIX_DELEGATION 10
     79 #define AHCP1_OPT_IPV4_PREFIX_DELEGATION 11
     80 #define AHCP1_OPT_NAME_SERVER            12
     81 #define AHCP1_OPT_NTP_SERVER             13
     82 #define AHCP1_OPT_MAX                    13
     83 
     84 static const struct tok ahcp1_opt_str[] = {
     85 	{ AHCP1_OPT_PAD,                    "Pad"                    },
     86 	{ AHCP1_OPT_MANDATORY,              "Mandatory"              },
     87 	{ AHCP1_OPT_ORIGIN_TIME,            "Origin Time"            },
     88 	{ AHCP1_OPT_EXPIRES,                "Expires"                },
     89 	{ AHCP1_OPT_MY_IPV6_ADDRESS,        "My-IPv6-Address"        },
     90 	{ AHCP1_OPT_MY_IPV4_ADDRESS,        "My-IPv4-Address"        },
     91 	{ AHCP1_OPT_IPV6_PREFIX,            "IPv6 Prefix"            },
     92 	{ AHCP1_OPT_IPV4_PREFIX,            "IPv4 Prefix"            },
     93 	{ AHCP1_OPT_IPV6_ADDRESS,           "IPv6 Address"           },
     94 	{ AHCP1_OPT_IPV4_ADDRESS,           "IPv4 Address"           },
     95 	{ AHCP1_OPT_IPV6_PREFIX_DELEGATION, "IPv6 Prefix Delegation" },
     96 	{ AHCP1_OPT_IPV4_PREFIX_DELEGATION, "IPv4 Prefix Delegation" },
     97 	{ AHCP1_OPT_NAME_SERVER,            "Name Server"            },
     98 	{ AHCP1_OPT_NTP_SERVER,             "NTP Server"             },
     99 	{ 0, NULL }
    100 };
    101 
    102 static int
    103 ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    104 	time_t t;
    105 	struct tm *tm;
    106 	char buf[BUFSIZE];
    107 
    108 	if (cp + 4 != ep)
    109 		goto corrupt;
    110 	ND_TCHECK2(*cp, 4);
    111 	t = EXTRACT_32BITS(cp);
    112 	if (NULL == (tm = gmtime(&t)))
    113 		ND_PRINT((ndo, ": gmtime() error"));
    114 	else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
    115 		ND_PRINT((ndo, ": strftime() error"));
    116 	else
    117 		ND_PRINT((ndo, ": %s UTC", buf));
    118 	return 0;
    119 
    120 corrupt:
    121 	ND_PRINT((ndo, ": %s", cstr));
    122 	ND_TCHECK2(*cp, ep - cp);
    123 	return 0;
    124 trunc:
    125 	ND_PRINT((ndo, "%s", tstr));
    126 	return -1;
    127 }
    128 
    129 static int
    130 ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    131 	if (cp + 4 != ep)
    132 		goto corrupt;
    133 	ND_TCHECK2(*cp, 4);
    134 	ND_PRINT((ndo, ": %us", EXTRACT_32BITS(cp)));
    135 	return 0;
    136 
    137 corrupt:
    138 	ND_PRINT((ndo, ": %s", cstr));
    139 	ND_TCHECK2(*cp, ep - cp);
    140 	return 0;
    141 trunc:
    142 	ND_PRINT((ndo, "%s", tstr));
    143 	return -1;
    144 }
    145 
    146 static int
    147 ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    148 	const char *sep = ": ";
    149 
    150 	while (cp < ep) {
    151 		if (cp + 16 > ep)
    152 			goto corrupt;
    153 		ND_TCHECK2(*cp, 16);
    154 #ifdef INET6
    155 		ND_PRINT((ndo, "%s%s", sep, ip6addr_string(ndo, cp)));
    156 #else
    157 		ND_PRINT((ndo, "%s(compiled w/o IPv6)", sep));
    158 #endif /* INET6 */
    159 		cp += 16;
    160 		sep = ", ";
    161 	}
    162 	return 0;
    163 
    164 corrupt:
    165 	ND_PRINT((ndo, ": %s", cstr));
    166 	ND_TCHECK2(*cp, ep - cp);
    167 	return 0;
    168 trunc:
    169 	ND_PRINT((ndo, "%s", tstr));
    170 	return -1;
    171 }
    172 
    173 static int
    174 ahcp_ipv4_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    175 	const char *sep = ": ";
    176 
    177 	while (cp < ep) {
    178 		if (cp + 4 > ep)
    179 			goto corrupt;
    180 		ND_TCHECK2(*cp, 4);
    181 		ND_PRINT((ndo, "%s%s", sep, ipaddr_string(ndo, cp)));
    182 		cp += 4;
    183 		sep = ", ";
    184 	}
    185 	return 0;
    186 
    187 corrupt:
    188 	ND_PRINT((ndo, ": %s", cstr));
    189 	ND_TCHECK2(*cp, ep - cp);
    190 	return 0;
    191 trunc:
    192 	ND_PRINT((ndo, "%s", tstr));
    193 	return -1;
    194 }
    195 
    196 static int
    197 ahcp_ipv6_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    198 	const char *sep = ": ";
    199 
    200 	while (cp < ep) {
    201 		if (cp + 17 > ep)
    202 			goto corrupt;
    203 		ND_TCHECK2(*cp, 17);
    204 #ifdef INET6
    205 		ND_PRINT((ndo, "%s%s/%u", sep, ip6addr_string(ndo, cp), *(cp + 16)));
    206 #else
    207 		ND_PRINT((ndo, "%s(compiled w/o IPv6)/%u", sep, *(cp + 16)));
    208 #endif /* INET6 */
    209 		cp += 17;
    210 		sep = ", ";
    211 	}
    212 	return 0;
    213 
    214 corrupt:
    215 	ND_PRINT((ndo, ": %s", cstr));
    216 	ND_TCHECK2(*cp, ep - cp);
    217 	return 0;
    218 trunc:
    219 	ND_PRINT((ndo, "%s", tstr));
    220 	return -1;
    221 }
    222 
    223 static int
    224 ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    225 	const char *sep = ": ";
    226 
    227 	while (cp < ep) {
    228 		if (cp + 5 > ep)
    229 			goto corrupt;
    230 		ND_TCHECK2(*cp, 5);
    231 		ND_PRINT((ndo, "%s%s/%u", sep, ipaddr_string(ndo, cp), *(cp + 4)));
    232 		cp += 5;
    233 		sep = ", ";
    234 	}
    235 	return 0;
    236 
    237 corrupt:
    238 	ND_PRINT((ndo, ": %s", cstr));
    239 	ND_TCHECK2(*cp, ep - cp);
    240 	return 0;
    241 trunc:
    242 	ND_PRINT((ndo, "%s", tstr));
    243 	return -1;
    244 }
    245 
    246 /* Data decoders signal truncated data with -1. */
    247 static int
    248 (* const data_decoders[AHCP1_OPT_MAX + 1])(netdissect_options *, const u_char *, const u_char *) = {
    249 	/* [AHCP1_OPT_PAD]                    = */  NULL,
    250 	/* [AHCP1_OPT_MANDATORY]              = */  NULL,
    251 	/* [AHCP1_OPT_ORIGIN_TIME]            = */  ahcp_time_print,
    252 	/* [AHCP1_OPT_EXPIRES]                = */  ahcp_seconds_print,
    253 	/* [AHCP1_OPT_MY_IPV6_ADDRESS]        = */  ahcp_ipv6_addresses_print,
    254 	/* [AHCP1_OPT_MY_IPV4_ADDRESS]        = */  ahcp_ipv4_addresses_print,
    255 	/* [AHCP1_OPT_IPV6_PREFIX]            = */  ahcp_ipv6_prefixes_print,
    256 	/* [AHCP1_OPT_IPV4_PREFIX]            = */  NULL,
    257 	/* [AHCP1_OPT_IPV6_ADDRESS]           = */  ahcp_ipv6_addresses_print,
    258 	/* [AHCP1_OPT_IPV4_ADDRESS]           = */  ahcp_ipv4_addresses_print,
    259 	/* [AHCP1_OPT_IPV6_PREFIX_DELEGATION] = */  ahcp_ipv6_prefixes_print,
    260 	/* [AHCP1_OPT_IPV4_PREFIX_DELEGATION] = */  ahcp_ipv4_prefixes_print,
    261 	/* [AHCP1_OPT_NAME_SERVER]            = */  ahcp_ipv6_addresses_print,
    262 	/* [AHCP1_OPT_NTP_SERVER]             = */  ahcp_ipv6_addresses_print,
    263 };
    264 
    265 static void
    266 ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    267 	uint8_t option_no, option_len;
    268 
    269 	while (cp < ep) {
    270 		/* Option no */
    271 		ND_TCHECK2(*cp, 1);
    272 		option_no = *cp;
    273 		cp += 1;
    274 		ND_PRINT((ndo, "\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)));
    275 		if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
    276 			continue;
    277 		/* Length */
    278 		if (cp + 1 > ep)
    279 			goto corrupt;
    280 		ND_TCHECK2(*cp, 1);
    281 		option_len = *cp;
    282 		cp += 1;
    283 		if (cp + option_len > ep)
    284 			goto corrupt;
    285 		/* Value */
    286 		if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
    287 			if (data_decoders[option_no](ndo, cp, cp + option_len) < 0)
    288 				break; /* truncated and already marked up */
    289 		} else {
    290 			ND_PRINT((ndo, " (Length %u)", option_len));
    291 			ND_TCHECK2(*cp, option_len);
    292 		}
    293 		cp += option_len;
    294 	}
    295 	return;
    296 
    297 corrupt:
    298 	ND_PRINT((ndo, " %s", cstr));
    299 	ND_TCHECK2(*cp, ep - cp);
    300 	return;
    301 trunc:
    302 	ND_PRINT((ndo, "%s", tstr));
    303 }
    304 
    305 static void
    306 ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) {
    307 	uint8_t type, mbz;
    308 	uint16_t body_len;
    309 
    310 	if (cp + AHCP1_BODY_MIN_LEN > ep)
    311 		goto corrupt;
    312 	/* Type */
    313 	ND_TCHECK2(*cp, 1);
    314 	type = *cp;
    315 	cp += 1;
    316 	/* MBZ */
    317 	ND_TCHECK2(*cp, 1);
    318 	mbz = *cp;
    319 	cp += 1;
    320 	/* Length */
    321 	ND_TCHECK2(*cp, 2);
    322 	body_len = EXTRACT_16BITS(cp);
    323 	cp += 2;
    324 
    325 	if (ndo->ndo_vflag) {
    326 		ND_PRINT((ndo, "\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)));
    327 		if (mbz != 0)
    328 			ND_PRINT((ndo, ", MBZ %u", mbz));
    329 		ND_PRINT((ndo, ", Length %u", body_len));
    330 	}
    331 	if (cp + body_len > ep)
    332 		goto corrupt;
    333 
    334 	/* Options */
    335 	if (ndo->ndo_vflag >= 2)
    336 		ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */
    337 	else
    338 		ND_TCHECK2(*cp, body_len);
    339 	return;
    340 
    341 corrupt:
    342 	ND_PRINT((ndo, " %s", cstr));
    343 	ND_TCHECK2(*cp, ep - cp);
    344 	return;
    345 trunc:
    346 	ND_PRINT((ndo, "%s", tstr));
    347 }
    348 
    349 void
    350 ahcp_print(netdissect_options *ndo, const u_char *cp, const u_int len) {
    351 	const u_char *ep = cp + len;
    352 	uint8_t version;
    353 
    354 	ND_PRINT((ndo, "AHCP"));
    355 	if (len < 2)
    356 		goto corrupt;
    357 	/* Magic */
    358 	ND_TCHECK2(*cp, 1);
    359 	if (*cp != AHCP_MAGIC_NUMBER)
    360 		goto corrupt;
    361 	cp += 1;
    362 	/* Version */
    363 	ND_TCHECK2(*cp, 1);
    364 	version = *cp;
    365 	cp += 1;
    366 	switch (version) {
    367 		case AHCP_VERSION_1: {
    368 			ND_PRINT((ndo, " Version 1"));
    369 			if (len < AHCP1_HEADER_FIX_LEN)
    370 				goto corrupt;
    371 			if (!ndo->ndo_vflag) {
    372 				ND_TCHECK2(*cp, AHCP1_HEADER_FIX_LEN - 2);
    373 				cp += AHCP1_HEADER_FIX_LEN - 2;
    374 			} else {
    375 				/* Hopcount */
    376 				ND_TCHECK2(*cp, 1);
    377 				ND_PRINT((ndo, "\n\tHopcount %u", *cp));
    378 				cp += 1;
    379 				/* Original Hopcount */
    380 				ND_TCHECK2(*cp, 1);
    381 				ND_PRINT((ndo, ", Original Hopcount %u", *cp));
    382 				cp += 1;
    383 				/* Nonce */
    384 				ND_TCHECK2(*cp, 4);
    385 				ND_PRINT((ndo, ", Nonce 0x%08x", EXTRACT_32BITS(cp)));
    386 				cp += 4;
    387 				/* Source Id */
    388 				ND_TCHECK2(*cp, 8);
    389 				ND_PRINT((ndo, ", Source Id %s", linkaddr_string(ndo, cp, 0, 8)));
    390 				cp += 8;
    391 				/* Destination Id */
    392 				ND_TCHECK2(*cp, 8);
    393 				ND_PRINT((ndo, ", Destination Id %s", linkaddr_string(ndo, cp, 0, 8)));
    394 				cp += 8;
    395 			}
    396 			/* Body */
    397 			ahcp1_body_print(ndo, cp, ep);
    398 			break;
    399 		}
    400 		default:
    401 			ND_PRINT((ndo, " Version %u (unknown)", version));
    402 			break;
    403 	}
    404 	return;
    405 
    406 corrupt:
    407 	ND_PRINT((ndo, " %s", cstr));
    408 	ND_TCHECK2(*cp, ep - cp);
    409 	return;
    410 trunc:
    411 	ND_PRINT((ndo, "%s", tstr));
    412 }
    413 
    414