Home | History | Annotate | Line # | Download | only in dist
print-ahcp.c revision 1.1.1.5
      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 /* \summary: Ad Hoc Configuration Protocol (AHCP) printer */
     29 
     30 /* Based on draft-chroboczek-ahcp-00 and source code of ahcpd-0.53 */
     31 
     32 #ifdef HAVE_CONFIG_H
     33 #include <config.h>
     34 #endif
     35 
     36 #include "netdissect-stdinc.h"
     37 
     38 #define ND_LONGJMP_FROM_TCHECK
     39 #include "netdissect.h"
     40 #include "extract.h"
     41 #include "addrtoname.h"
     42 
     43 
     44 #define AHCP_MAGIC_NUMBER 43
     45 #define AHCP_VERSION_1 1
     46 #define AHCP1_HEADER_FIX_LEN 24
     47 #define AHCP1_BODY_MIN_LEN 4
     48 
     49 #define AHCP1_MSG_DISCOVER 0
     50 #define AHCP1_MSG_OFFER    1
     51 #define AHCP1_MSG_REQUEST  2
     52 #define AHCP1_MSG_ACK      3
     53 #define AHCP1_MSG_NACK     4
     54 #define AHCP1_MSG_RELEASE  5
     55 
     56 static const struct tok ahcp1_msg_str[] = {
     57 	{ AHCP1_MSG_DISCOVER, "Discover" },
     58 	{ AHCP1_MSG_OFFER,    "Offer"    },
     59 	{ AHCP1_MSG_REQUEST,  "Request"  },
     60 	{ AHCP1_MSG_ACK,      "Ack"      },
     61 	{ AHCP1_MSG_NACK,     "Nack"     },
     62 	{ AHCP1_MSG_RELEASE,  "Release"  },
     63 	{ 0, NULL }
     64 };
     65 
     66 #define AHCP1_OPT_PAD                     0
     67 #define AHCP1_OPT_MANDATORY               1
     68 #define AHCP1_OPT_ORIGIN_TIME             2
     69 #define AHCP1_OPT_EXPIRES                 3
     70 #define AHCP1_OPT_MY_IPV6_ADDRESS         4
     71 #define AHCP1_OPT_MY_IPV4_ADDRESS         5
     72 #define AHCP1_OPT_IPV6_PREFIX             6
     73 #define AHCP1_OPT_IPV4_PREFIX             7
     74 #define AHCP1_OPT_IPV6_ADDRESS            8
     75 #define AHCP1_OPT_IPV4_ADDRESS            9
     76 #define AHCP1_OPT_IPV6_PREFIX_DELEGATION 10
     77 #define AHCP1_OPT_IPV4_PREFIX_DELEGATION 11
     78 #define AHCP1_OPT_NAME_SERVER            12
     79 #define AHCP1_OPT_NTP_SERVER             13
     80 #define AHCP1_OPT_MAX                    13
     81 
     82 static const struct tok ahcp1_opt_str[] = {
     83 	{ AHCP1_OPT_PAD,                    "Pad"                    },
     84 	{ AHCP1_OPT_MANDATORY,              "Mandatory"              },
     85 	{ AHCP1_OPT_ORIGIN_TIME,            "Origin Time"            },
     86 	{ AHCP1_OPT_EXPIRES,                "Expires"                },
     87 	{ AHCP1_OPT_MY_IPV6_ADDRESS,        "My-IPv6-Address"        },
     88 	{ AHCP1_OPT_MY_IPV4_ADDRESS,        "My-IPv4-Address"        },
     89 	{ AHCP1_OPT_IPV6_PREFIX,            "IPv6 Prefix"            },
     90 	{ AHCP1_OPT_IPV4_PREFIX,            "IPv4 Prefix"            },
     91 	{ AHCP1_OPT_IPV6_ADDRESS,           "IPv6 Address"           },
     92 	{ AHCP1_OPT_IPV4_ADDRESS,           "IPv4 Address"           },
     93 	{ AHCP1_OPT_IPV6_PREFIX_DELEGATION, "IPv6 Prefix Delegation" },
     94 	{ AHCP1_OPT_IPV4_PREFIX_DELEGATION, "IPv4 Prefix Delegation" },
     95 	{ AHCP1_OPT_NAME_SERVER,            "Name Server"            },
     96 	{ AHCP1_OPT_NTP_SERVER,             "NTP Server"             },
     97 	{ 0, NULL }
     98 };
     99 
    100 static void
    101 ahcp_time_print(netdissect_options *ndo,
    102                 const u_char *cp, uint8_t len)
    103 {
    104 	time_t t;
    105 	char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss UTC")];
    106 
    107 	if (len != 4)
    108 		goto invalid;
    109 	t = GET_BE_U_4(cp);
    110 	ND_PRINT(": %s",
    111 	    nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC",
    112 	      gmtime(&t)));
    113 	return;
    114 
    115 invalid:
    116 	nd_print_invalid(ndo);
    117 	ND_TCHECK_LEN(cp, len);
    118 }
    119 
    120 static void
    121 ahcp_seconds_print(netdissect_options *ndo,
    122                    const u_char *cp, uint8_t len)
    123 {
    124 	if (len != 4)
    125 		goto invalid;
    126 	ND_PRINT(": %us", GET_BE_U_4(cp));
    127 	return;
    128 
    129 invalid:
    130 	nd_print_invalid(ndo);
    131 	ND_TCHECK_LEN(cp, len);
    132 }
    133 
    134 static void
    135 ahcp_ipv6_addresses_print(netdissect_options *ndo,
    136                           const u_char *cp, uint8_t len)
    137 {
    138 	const char *sep = ": ";
    139 
    140 	while (len) {
    141 		if (len < 16)
    142 			goto invalid;
    143 		ND_PRINT("%s%s", sep, GET_IP6ADDR_STRING(cp));
    144 		cp += 16;
    145 		len -= 16;
    146 		sep = ", ";
    147 	}
    148 	return;
    149 
    150 invalid:
    151 	nd_print_invalid(ndo);
    152 	ND_TCHECK_LEN(cp, len);
    153 }
    154 
    155 static void
    156 ahcp_ipv4_addresses_print(netdissect_options *ndo,
    157                           const u_char *cp, uint8_t len)
    158 {
    159 	const char *sep = ": ";
    160 
    161 	while (len) {
    162 		if (len < 4)
    163 			goto invalid;
    164 		ND_PRINT("%s%s", sep, GET_IPADDR_STRING(cp));
    165 		cp += 4;
    166 		len -= 4;
    167 		sep = ", ";
    168 	}
    169 	return;
    170 
    171 invalid:
    172 	nd_print_invalid(ndo);
    173 	ND_TCHECK_LEN(cp, len);
    174 }
    175 
    176 static void
    177 ahcp_ipv6_prefixes_print(netdissect_options *ndo,
    178                          const u_char *cp, uint8_t len)
    179 {
    180 	const char *sep = ": ";
    181 
    182 	while (len) {
    183 		if (len < 17)
    184 			goto invalid;
    185 		ND_PRINT("%s%s/%u", sep, GET_IP6ADDR_STRING(cp), GET_U_1(cp + 16));
    186 		cp += 17;
    187 		len -= 17;
    188 		sep = ", ";
    189 	}
    190 	return;
    191 
    192 invalid:
    193 	nd_print_invalid(ndo);
    194 	ND_TCHECK_LEN(cp, len);
    195 }
    196 
    197 static void
    198 ahcp_ipv4_prefixes_print(netdissect_options *ndo,
    199                          const u_char *cp, uint8_t len)
    200 {
    201 	const char *sep = ": ";
    202 
    203 	while (len) {
    204 		if (len < 5)
    205 			goto invalid;
    206 		ND_PRINT("%s%s/%u", sep, GET_IPADDR_STRING(cp), GET_U_1(cp + 4));
    207 		cp += 5;
    208 		len -= 5;
    209 		sep = ", ";
    210 	}
    211 	return;
    212 
    213 invalid:
    214 	nd_print_invalid(ndo);
    215 	ND_TCHECK_LEN(cp, len);
    216 }
    217 
    218 static void
    219 (* const data_decoders[AHCP1_OPT_MAX + 1])(netdissect_options *, const u_char *, uint8_t) = {
    220 	/* [AHCP1_OPT_PAD]                    = */  NULL,
    221 	/* [AHCP1_OPT_MANDATORY]              = */  NULL,
    222 	/* [AHCP1_OPT_ORIGIN_TIME]            = */  ahcp_time_print,
    223 	/* [AHCP1_OPT_EXPIRES]                = */  ahcp_seconds_print,
    224 	/* [AHCP1_OPT_MY_IPV6_ADDRESS]        = */  ahcp_ipv6_addresses_print,
    225 	/* [AHCP1_OPT_MY_IPV4_ADDRESS]        = */  ahcp_ipv4_addresses_print,
    226 	/* [AHCP1_OPT_IPV6_PREFIX]            = */  ahcp_ipv6_prefixes_print,
    227 	/* [AHCP1_OPT_IPV4_PREFIX]            = */  NULL,
    228 	/* [AHCP1_OPT_IPV6_ADDRESS]           = */  ahcp_ipv6_addresses_print,
    229 	/* [AHCP1_OPT_IPV4_ADDRESS]           = */  ahcp_ipv4_addresses_print,
    230 	/* [AHCP1_OPT_IPV6_PREFIX_DELEGATION] = */  ahcp_ipv6_prefixes_print,
    231 	/* [AHCP1_OPT_IPV4_PREFIX_DELEGATION] = */  ahcp_ipv4_prefixes_print,
    232 	/* [AHCP1_OPT_NAME_SERVER]            = */  ahcp_ipv6_addresses_print,
    233 	/* [AHCP1_OPT_NTP_SERVER]             = */  ahcp_ipv6_addresses_print,
    234 };
    235 
    236 static void
    237 ahcp1_options_print(netdissect_options *ndo,
    238                     const u_char *cp, uint16_t len)
    239 {
    240 	while (len) {
    241 		uint8_t option_no, option_len;
    242 
    243 		/* Option no */
    244 		option_no = GET_U_1(cp);
    245 		cp += 1;
    246 		len -= 1;
    247 		ND_PRINT("\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no));
    248 		if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
    249 			continue;
    250 		/* Length */
    251 		if (!len)
    252 			goto invalid;
    253 		option_len = GET_U_1(cp);
    254 		cp += 1;
    255 		len -= 1;
    256 		if (option_len > len)
    257 			goto invalid;
    258 		/* Value */
    259 		if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
    260 			data_decoders[option_no](ndo, cp, option_len);
    261 		} else {
    262 			ND_PRINT(" (Length %u)", option_len);
    263 			ND_TCHECK_LEN(cp, option_len);
    264 		}
    265 		cp += option_len;
    266 		len -= option_len;
    267 	}
    268 	return;
    269 
    270 invalid:
    271 	nd_print_invalid(ndo);
    272 	ND_TCHECK_LEN(cp, len);
    273 }
    274 
    275 static void
    276 ahcp1_body_print(netdissect_options *ndo,
    277                  const u_char *cp, u_int len)
    278 {
    279 	uint8_t type, mbz;
    280 	uint16_t body_len;
    281 
    282 	if (len < AHCP1_BODY_MIN_LEN)
    283 		goto invalid;
    284 	/* Type */
    285 	type = GET_U_1(cp);
    286 	cp += 1;
    287 	len -= 1;
    288 	/* MBZ */
    289 	mbz = GET_U_1(cp);
    290 	cp += 1;
    291 	len -= 1;
    292 	/* Length */
    293 	body_len = GET_BE_U_2(cp);
    294 	cp += 2;
    295 	len -= 2;
    296 
    297 	if (ndo->ndo_vflag) {
    298 		ND_PRINT("\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type));
    299 		if (mbz != 0)
    300 			ND_PRINT(", MBZ %u", mbz);
    301 		ND_PRINT(", Length %u", body_len);
    302 	}
    303 	if (body_len > len)
    304 		goto invalid;
    305 
    306 	/* Options */
    307 	/* Here use "body_len", not "len" (ignore any extra data). */
    308 	if (ndo->ndo_vflag >= 2)
    309 		ahcp1_options_print(ndo, cp, body_len);
    310 	else
    311 		ND_TCHECK_LEN(cp, body_len);
    312 	return;
    313 
    314 invalid:
    315 	nd_print_invalid(ndo);
    316 	ND_TCHECK_LEN(cp, len);
    317 
    318 }
    319 
    320 void
    321 ahcp_print(netdissect_options *ndo,
    322            const u_char *cp, u_int len)
    323 {
    324 	uint8_t version;
    325 
    326 	ndo->ndo_protocol = "ahcp";
    327 	nd_print_protocol_caps(ndo);
    328 	if (len < 2)
    329 		goto invalid;
    330 	/* Magic */
    331 	if (GET_U_1(cp) != AHCP_MAGIC_NUMBER)
    332 		goto invalid;
    333 	cp += 1;
    334 	len -= 1;
    335 	/* Version */
    336 	version = GET_U_1(cp);
    337 	cp += 1;
    338 	len -= 1;
    339 	switch (version) {
    340 		case AHCP_VERSION_1: {
    341 			ND_PRINT(" Version 1");
    342 			if (len < AHCP1_HEADER_FIX_LEN - 2)
    343 				goto invalid;
    344 			if (!ndo->ndo_vflag) {
    345 				ND_TCHECK_LEN(cp, AHCP1_HEADER_FIX_LEN - 2);
    346 				cp += AHCP1_HEADER_FIX_LEN - 2;
    347 				len -= AHCP1_HEADER_FIX_LEN - 2;
    348 			} else {
    349 				/* Hopcount */
    350 				ND_PRINT("\n\tHopcount %u", GET_U_1(cp));
    351 				cp += 1;
    352 				len -= 1;
    353 				/* Original Hopcount */
    354 				ND_PRINT(", Original Hopcount %u", GET_U_1(cp));
    355 				cp += 1;
    356 				len -= 1;
    357 				/* Nonce */
    358 				ND_PRINT(", Nonce 0x%08x", GET_BE_U_4(cp));
    359 				cp += 4;
    360 				len -= 4;
    361 				/* Source Id */
    362 				ND_PRINT(", Source Id %s", GET_LINKADDR_STRING(cp, LINKADDR_OTHER, 8));
    363 				cp += 8;
    364 				len -= 8;
    365 				/* Destination Id */
    366 				ND_PRINT(", Destination Id %s", GET_LINKADDR_STRING(cp, LINKADDR_OTHER, 8));
    367 				cp += 8;
    368 				len -= 8;
    369 			}
    370 			/* Body */
    371 			ahcp1_body_print(ndo, cp, len);
    372 			break;
    373 		}
    374 		default:
    375 			ND_PRINT(" Version %u (unknown)", version);
    376 			ND_TCHECK_LEN(cp, len);
    377 			break;
    378 	}
    379 	return;
    380 
    381 invalid:
    382 	nd_print_invalid(ndo);
    383 	ND_TCHECK_LEN(cp, len);
    384 }
    385