print-ahcp.c 11 KB

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