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