etc/services - sync with NetBSD-8
[minix.git] / external / bsd / tcpdump / dist / print-ahcp.c
blobcc72bd789f3255dfcf3e17e76f3eb5f55f82935c
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.
6 * Copyright (c) 2013 The TCPDUMP project
7 * All rights reserved.
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.
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.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: print-ahcp.c,v 1.3 2015/03/31 21:59:35 christos Exp $");
35 #endif
37 #define NETDISSECT_REWORKED
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
42 #include <tcpdump-stdinc.h>
44 #include "interface.h"
45 #include "extract.h"
46 #include "addrtoname.h"
48 static const char tstr[] = " [|ahcp]";
49 static const char cstr[] = "(corrupt)";
51 #define AHCP_MAGIC_NUMBER 43
52 #define AHCP_VERSION_1 1
53 #define AHCP1_HEADER_FIX_LEN 24
54 #define AHCP1_BODY_MIN_LEN 4
56 #define AHCP1_MSG_DISCOVER 0
57 #define AHCP1_MSG_OFFER 1
58 #define AHCP1_MSG_REQUEST 2
59 #define AHCP1_MSG_ACK 3
60 #define AHCP1_MSG_NACK 4
61 #define AHCP1_MSG_RELEASE 5
63 static const struct tok ahcp1_msg_str[] = {
64 { AHCP1_MSG_DISCOVER, "Discover" },
65 { AHCP1_MSG_OFFER, "Offer" },
66 { AHCP1_MSG_REQUEST, "Request" },
67 { AHCP1_MSG_ACK, "Ack" },
68 { AHCP1_MSG_NACK, "Nack" },
69 { AHCP1_MSG_RELEASE, "Release" },
70 { 0, NULL }
73 #define AHCP1_OPT_PAD 0
74 #define AHCP1_OPT_MANDATORY 1
75 #define AHCP1_OPT_ORIGIN_TIME 2
76 #define AHCP1_OPT_EXPIRES 3
77 #define AHCP1_OPT_MY_IPV6_ADDRESS 4
78 #define AHCP1_OPT_MY_IPV4_ADDRESS 5
79 #define AHCP1_OPT_IPV6_PREFIX 6
80 #define AHCP1_OPT_IPV4_PREFIX 7
81 #define AHCP1_OPT_IPV6_ADDRESS 8
82 #define AHCP1_OPT_IPV4_ADDRESS 9
83 #define AHCP1_OPT_IPV6_PREFIX_DELEGATION 10
84 #define AHCP1_OPT_IPV4_PREFIX_DELEGATION 11
85 #define AHCP1_OPT_NAME_SERVER 12
86 #define AHCP1_OPT_NTP_SERVER 13
87 #define AHCP1_OPT_MAX 13
89 static const struct tok ahcp1_opt_str[] = {
90 { AHCP1_OPT_PAD, "Pad" },
91 { AHCP1_OPT_MANDATORY, "Mandatory" },
92 { AHCP1_OPT_ORIGIN_TIME, "Origin Time" },
93 { AHCP1_OPT_EXPIRES, "Expires" },
94 { AHCP1_OPT_MY_IPV6_ADDRESS, "My-IPv6-Address" },
95 { AHCP1_OPT_MY_IPV4_ADDRESS, "My-IPv4-Address" },
96 { AHCP1_OPT_IPV6_PREFIX, "IPv6 Prefix" },
97 { AHCP1_OPT_IPV4_PREFIX, "IPv4 Prefix" },
98 { AHCP1_OPT_IPV6_ADDRESS, "IPv6 Address" },
99 { AHCP1_OPT_IPV4_ADDRESS, "IPv4 Address" },
100 { AHCP1_OPT_IPV6_PREFIX_DELEGATION, "IPv6 Prefix Delegation" },
101 { AHCP1_OPT_IPV4_PREFIX_DELEGATION, "IPv4 Prefix Delegation" },
102 { AHCP1_OPT_NAME_SERVER, "Name Server" },
103 { AHCP1_OPT_NTP_SERVER, "NTP Server" },
104 { 0, NULL }
107 static int
108 ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
110 time_t t;
111 struct tm *tm;
112 char buf[BUFSIZE];
114 if (cp + 4 != ep)
115 goto corrupt;
116 ND_TCHECK2(*cp, 4);
117 t = EXTRACT_32BITS(cp);
118 if (NULL == (tm = gmtime(&t)))
119 ND_PRINT((ndo, ": gmtime() error"));
120 else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
121 ND_PRINT((ndo, ": strftime() error"));
122 else
123 ND_PRINT((ndo, ": %s UTC", buf));
124 return 0;
126 corrupt:
127 ND_PRINT((ndo, ": %s", cstr));
128 ND_TCHECK2(*cp, ep - cp);
129 return 0;
130 trunc:
131 ND_PRINT((ndo, "%s", tstr));
132 return -1;
135 static int
136 ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
138 if (cp + 4 != ep)
139 goto corrupt;
140 ND_TCHECK2(*cp, 4);
141 ND_PRINT((ndo, ": %us", EXTRACT_32BITS(cp)));
142 return 0;
144 corrupt:
145 ND_PRINT((ndo, ": %s", cstr));
146 ND_TCHECK2(*cp, ep - cp);
147 return 0;
148 trunc:
149 ND_PRINT((ndo, "%s", tstr));
150 return -1;
153 static int
154 ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
156 const char *sep = ": ";
158 while (cp < ep) {
159 if (cp + 16 > ep)
160 goto corrupt;
161 ND_TCHECK2(*cp, 16);
162 #ifdef INET6
163 ND_PRINT((ndo, "%s%s", sep, ip6addr_string(ndo, cp)));
164 #else
165 ND_PRINT((ndo, "%s(compiled w/o IPv6)", sep));
166 #endif /* INET6 */
167 cp += 16;
168 sep = ", ";
170 return 0;
172 corrupt:
173 ND_PRINT((ndo, ": %s", cstr));
174 ND_TCHECK2(*cp, ep - cp);
175 return 0;
176 trunc:
177 ND_PRINT((ndo, "%s", tstr));
178 return -1;
181 static int
182 ahcp_ipv4_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
184 const char *sep = ": ";
186 while (cp < ep) {
187 if (cp + 4 > ep)
188 goto corrupt;
189 ND_TCHECK2(*cp, 4);
190 ND_PRINT((ndo, "%s%s", sep, ipaddr_string(ndo, cp)));
191 cp += 4;
192 sep = ", ";
194 return 0;
196 corrupt:
197 ND_PRINT((ndo, ": %s", cstr));
198 ND_TCHECK2(*cp, ep - cp);
199 return 0;
200 trunc:
201 ND_PRINT((ndo, "%s", tstr));
202 return -1;
205 static int
206 ahcp_ipv6_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
208 const char *sep = ": ";
210 while (cp < ep) {
211 if (cp + 17 > ep)
212 goto corrupt;
213 ND_TCHECK2(*cp, 17);
214 #ifdef INET6
215 ND_PRINT((ndo, "%s%s/%u", sep, ip6addr_string(ndo, cp), *(cp + 16)));
216 #else
217 ND_PRINT((ndo, "%s(compiled w/o IPv6)/%u", sep, *(cp + 16)));
218 #endif /* INET6 */
219 cp += 17;
220 sep = ", ";
222 return 0;
224 corrupt:
225 ND_PRINT((ndo, ": %s", cstr));
226 ND_TCHECK2(*cp, ep - cp);
227 return 0;
228 trunc:
229 ND_PRINT((ndo, "%s", tstr));
230 return -1;
233 static int
234 ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
236 const char *sep = ": ";
238 while (cp < ep) {
239 if (cp + 5 > ep)
240 goto corrupt;
241 ND_TCHECK2(*cp, 5);
242 ND_PRINT((ndo, "%s%s/%u", sep, ipaddr_string(ndo, cp), *(cp + 4)));
243 cp += 5;
244 sep = ", ";
246 return 0;
248 corrupt:
249 ND_PRINT((ndo, ": %s", cstr));
250 ND_TCHECK2(*cp, ep - cp);
251 return 0;
252 trunc:
253 ND_PRINT((ndo, "%s", tstr));
254 return -1;
257 /* Data decoders signal truncated data with -1. */
258 static int
259 (* const data_decoders[AHCP1_OPT_MAX + 1])(netdissect_options *, const u_char *, const u_char *) = {
260 /* [AHCP1_OPT_PAD] = */ NULL,
261 /* [AHCP1_OPT_MANDATORY] = */ NULL,
262 /* [AHCP1_OPT_ORIGIN_TIME] = */ ahcp_time_print,
263 /* [AHCP1_OPT_EXPIRES] = */ ahcp_seconds_print,
264 /* [AHCP1_OPT_MY_IPV6_ADDRESS] = */ ahcp_ipv6_addresses_print,
265 /* [AHCP1_OPT_MY_IPV4_ADDRESS] = */ ahcp_ipv4_addresses_print,
266 /* [AHCP1_OPT_IPV6_PREFIX] = */ ahcp_ipv6_prefixes_print,
267 /* [AHCP1_OPT_IPV4_PREFIX] = */ NULL,
268 /* [AHCP1_OPT_IPV6_ADDRESS] = */ ahcp_ipv6_addresses_print,
269 /* [AHCP1_OPT_IPV4_ADDRESS] = */ ahcp_ipv4_addresses_print,
270 /* [AHCP1_OPT_IPV6_PREFIX_DELEGATION] = */ ahcp_ipv6_prefixes_print,
271 /* [AHCP1_OPT_IPV4_PREFIX_DELEGATION] = */ ahcp_ipv4_prefixes_print,
272 /* [AHCP1_OPT_NAME_SERVER] = */ ahcp_ipv6_addresses_print,
273 /* [AHCP1_OPT_NTP_SERVER] = */ ahcp_ipv6_addresses_print,
276 static void
277 ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
279 uint8_t option_no, option_len;
281 while (cp < ep) {
282 /* Option no */
283 ND_TCHECK2(*cp, 1);
284 option_no = *cp;
285 cp += 1;
286 ND_PRINT((ndo, "\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)));
287 if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
288 continue;
289 /* Length */
290 if (cp + 1 > ep)
291 goto corrupt;
292 ND_TCHECK2(*cp, 1);
293 option_len = *cp;
294 cp += 1;
295 if (cp + option_len > ep)
296 goto corrupt;
297 /* Value */
298 if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
299 if (data_decoders[option_no](ndo, cp, cp + option_len) < 0)
300 break; /* truncated and already marked up */
301 } else {
302 ND_PRINT((ndo, " (Length %u)", option_len));
303 ND_TCHECK2(*cp, option_len);
305 cp += option_len;
307 return;
309 corrupt:
310 ND_PRINT((ndo, " %s", cstr));
311 ND_TCHECK2(*cp, ep - cp);
312 return;
313 trunc:
314 ND_PRINT((ndo, "%s", tstr));
317 static void
318 ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
320 uint8_t type, mbz;
321 uint16_t body_len;
323 if (cp + AHCP1_BODY_MIN_LEN > ep)
324 goto corrupt;
325 /* Type */
326 ND_TCHECK2(*cp, 1);
327 type = *cp;
328 cp += 1;
329 /* MBZ */
330 ND_TCHECK2(*cp, 1);
331 mbz = *cp;
332 cp += 1;
333 /* Length */
334 ND_TCHECK2(*cp, 2);
335 body_len = EXTRACT_16BITS(cp);
336 cp += 2;
338 if (ndo->ndo_vflag) {
339 ND_PRINT((ndo, "\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)));
340 if (mbz != 0)
341 ND_PRINT((ndo, ", MBZ %u", mbz));
342 ND_PRINT((ndo, ", Length %u", body_len));
344 if (cp + body_len > ep)
345 goto corrupt;
347 /* Options */
348 if (ndo->ndo_vflag >= 2)
349 ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */
350 else
351 ND_TCHECK2(*cp, body_len);
352 return;
354 corrupt:
355 ND_PRINT((ndo, " %s", cstr));
356 ND_TCHECK2(*cp, ep - cp);
357 return;
358 trunc:
359 ND_PRINT((ndo, "%s", tstr));
362 void
363 ahcp_print(netdissect_options *ndo, const u_char *cp, const u_int len)
365 const u_char *ep = cp + len;
366 uint8_t version;
368 ND_PRINT((ndo, "AHCP"));
369 if (len < 2)
370 goto corrupt;
371 /* Magic */
372 ND_TCHECK2(*cp, 1);
373 if (*cp != AHCP_MAGIC_NUMBER)
374 goto corrupt;
375 cp += 1;
376 /* Version */
377 ND_TCHECK2(*cp, 1);
378 version = *cp;
379 cp += 1;
380 switch (version) {
381 case AHCP_VERSION_1: {
382 ND_PRINT((ndo, " Version 1"));
383 if (len < AHCP1_HEADER_FIX_LEN)
384 goto corrupt;
385 if (!ndo->ndo_vflag) {
386 ND_TCHECK2(*cp, AHCP1_HEADER_FIX_LEN - 2);
387 cp += AHCP1_HEADER_FIX_LEN - 2;
388 } else {
389 /* Hopcount */
390 ND_TCHECK2(*cp, 1);
391 ND_PRINT((ndo, "\n\tHopcount %u", *cp));
392 cp += 1;
393 /* Original Hopcount */
394 ND_TCHECK2(*cp, 1);
395 ND_PRINT((ndo, ", Original Hopcount %u", *cp));
396 cp += 1;
397 /* Nonce */
398 ND_TCHECK2(*cp, 4);
399 ND_PRINT((ndo, ", Nonce 0x%08x", EXTRACT_32BITS(cp)));
400 cp += 4;
401 /* Source Id */
402 ND_TCHECK2(*cp, 8);
403 ND_PRINT((ndo, ", Source Id %s", linkaddr_string(ndo, cp, 0, 8)));
404 cp += 8;
405 /* Destination Id */
406 ND_TCHECK2(*cp, 8);
407 ND_PRINT((ndo, ", Destination Id %s", linkaddr_string(ndo, cp, 0, 8)));
408 cp += 8;
410 /* Body */
411 ahcp1_body_print(ndo, cp, ep);
412 break;
414 default:
415 ND_PRINT((ndo, " Version %u (unknown)", version));
416 break;
418 return;
420 corrupt:
421 ND_PRINT((ndo, " %s", cstr));
422 ND_TCHECK2(*cp, ep - cp);
423 return;
424 trunc:
425 ND_PRINT((ndo, "%s", tstr));