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