2 * Routines for DHCPv6 packet disassembly
3 * Jun-ichiro itojun Hagino <itojun@iijlab.net>
4 * IItom Tsutomu MIENO <iitom@utouto.com>
5 * SHIRASAKI Yasuhiro <yasuhiro@gnome.gr.jp>
7 * $Id: packet-dhcpv6.c,v 1.7 2002/08/28 21:00:12 jmayer Exp $
9 * The information used comes from:
10 * draft-ietf-dhc-dhcpv6-26.txt
11 * draft-troan-dhcpv6-opt-prefix-delegation-01.txt
12 * draft-ietf-dhc-dhcpv6-opt-dnsconfig-02.txt
14 * Note that protocol constants are still subject to change, based on IANA
15 * assignment decisions.
17 * Ethereal - Network traffic analyzer
18 * By Gerald Combs <gerald@ethereal.com>
19 * Copyright 1998 Gerald Combs
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
42 #include <epan/int-64bit.h>
43 #include <epan/packet.h>
44 #include <epan/ipv6-utils.h>
46 static int proto_dhcpv6 = -1;
47 static int hf_dhcpv6_msgtype = -1;
49 static guint ett_dhcpv6 = -1;
50 static guint ett_dhcpv6_option = -1;
52 #define UDP_PORT_DHCPV6_DOWNSTREAM 546
53 #define UDP_PORT_DHCPV6_UPSTREAM 547
55 #define DHCPV6_LEASEDURATION_INFINITY 0xffffffff
66 #define RECONFIGURE 10
67 #define INFORMATION_REQUEST 11
71 #define OPTION_CLIENTID 1
72 #define OPTION_SERVERID 2
74 #define OPTION_IA_TA 4
75 #define OPTION_IAADDR 5
77 #define OPTION_PREFERENCE 7
78 #define OPTION_ELAPSED_TIME 8
79 #define OPTION_RELAY_MSG 9
80 /* #define OPTION_SERVER_MSG 10 */
81 #define OPTION_AUTH 11
82 #define OPTION_UNICAST 12
83 #define OPTION_STATUS_CODE 13
84 #define OPTION_RAPID_COMMIT 14
85 #define OPTION_USER_CLASS 15
86 #define OPTION_VENDOR_CLASS 16
87 #define OPTION_VENDOR_OPTS 17
88 #define OPTION_INTERFACE_ID 18
89 #define OPTION_RECONF_MSG 19
90 #define OPTION_RECONF_NONCE 20
92 #define OPTION_DNS_SERVERS 25
93 #define OPTION_DOMAIN_LIST 26
94 #define OPTION_PREFIXDEL 30
95 #define OPTION_PREFIX_INFO 31
96 #define OPTION_PREFIXREQ 32
101 #define DUID_LL_OLD 4
103 static const value_string msgtype_vals[] = {
104 { SOLICIT, "Solicit" },
105 { ADVERTISE, "Advertise" },
106 { REQUEST, "Request" },
107 { CONFIRM, "Confirm" },
109 { REBIND, "Rebind" },
111 { RELEASE, "Release" },
112 { DECLINE, "Decline" },
113 { RECONFIGURE, "Reconfigure" },
114 { INFORMATION_REQUEST, "Information-request" },
115 { RELAY_FORW, "Relay-forw" },
116 { RELAY_REPL, "Relay-repl" },
120 static const value_string opttype_vals[] = {
121 { OPTION_CLIENTID, "Client Identifier" },
122 { OPTION_SERVERID, "Server Identifier" },
123 { OPTION_IA, "Identify Association" },
124 { OPTION_IA_TA, "Identify Association for Temporary Address" },
125 { OPTION_IAADDR, "IA Address" },
126 { OPTION_ORO, "Option Request" },
127 { OPTION_PREFERENCE, "Preference" },
128 { OPTION_ELAPSED_TIME, "Elapsed time" },
129 { OPTION_RELAY_MSG, "Relay Message" },
130 /* { OPTION_SERVER_MSG, "Server message" }, */
131 { OPTION_AUTH, "Authentication" },
132 { OPTION_UNICAST, "Server unicast" },
133 { OPTION_STATUS_CODE, "Status code" },
134 { OPTION_RAPID_COMMIT, "Rapid Commit" },
135 { OPTION_USER_CLASS, "User Class" },
136 { OPTION_VENDOR_CLASS, "Vendor Class" },
137 { OPTION_VENDOR_OPTS, "Vendor-specific Information" },
138 { OPTION_INTERFACE_ID, "Interface-Id" },
139 { OPTION_RECONF_MSG, "Reconfigure Message" },
140 { OPTION_RECONF_NONCE, "Reconfigure Nonce" },
141 { OPTION_DNS_SERVERS, "Domain Name Server" },
142 { OPTION_DOMAIN_LIST, "Domain Search List" },
143 { OPTION_PREFIXDEL, "Prefix Delegation" },
144 { OPTION_PREFIX_INFO, "Prefix Information" },
145 { OPTION_PREFIXREQ, "Prefix Request" },
149 static const value_string statuscode_vals[] =
159 {8, "UseMulticast" },
163 static const value_string duidtype_vals[] =
165 { DUID_LLT, "link-layer address plus time" },
166 { DUID_EN, "assigned by vendor based on Enterprise number" },
167 { DUID_LL, "link-layer address" },
168 { DUID_LL_OLD, "link-layer address (old)" },
172 /* Returns the number of bytes consumed by this option. */
174 dhcpv6_option(tvbuff_t *tvb, proto_tree *bp_tree, int off, int eoff,
182 struct e_in6_addr in6;
185 /* option type and length must be present */
186 if (eoff - off < 4) {
191 opttype = tvb_get_ntohs(tvb, off);
192 optlen = tvb_get_ntohs(tvb, off + 2);
195 if (eoff - off < 4 + optlen) {
200 ti = proto_tree_add_text(bp_tree, tvb, off, 4 + optlen,
201 "%s", val_to_str(opttype, opttype_vals, "DHCP option %u"));
203 subtree = proto_item_add_subtree(ti, ett_dhcpv6_option);
204 proto_tree_add_text(subtree, tvb, off, 2, "option type: %d", opttype);
205 proto_tree_add_text(subtree, tvb, off + 2, 2, "option length: %d",
210 case OPTION_CLIENTID:
211 case OPTION_SERVERID:
213 proto_tree_add_text(subtree, tvb, off, optlen,
214 "DUID: malformed option");
217 duidtype = tvb_get_ntohs(tvb, off);
218 proto_tree_add_text(subtree, tvb, off, 2,
219 "DUID type: %s (%u)",
221 duidtype_vals, "Unknown"),
226 proto_tree_add_text(subtree, tvb, off,
227 optlen, "DUID: malformed option");
230 /* XXX seconds since Jan 1 2000 */
231 proto_tree_add_text(subtree, tvb, off + 2, 2,
233 tvb_get_ntohs(tvb, off + 2));
234 proto_tree_add_text(subtree, tvb, off + 4, 4,
235 "Time: %u", tvb_get_ntohl(tvb, off + 4));
237 proto_tree_add_text(subtree, tvb, off + 8,
238 optlen - 8, "Link-layer address");
243 proto_tree_add_text(subtree, tvb, off,
244 optlen, "DUID: malformed option");
247 proto_tree_add_text(subtree, tvb, off + 2, 4,
248 "enterprise-number");
250 proto_tree_add_text(subtree, tvb, off + 6,
251 optlen - 6, "identifier");
257 proto_tree_add_text(subtree, tvb, off,
258 optlen, "DUID: malformed option");
261 proto_tree_add_text(subtree, tvb, off + 2, 2,
263 tvb_get_ntohs(tvb, off + 2));
265 proto_tree_add_text(subtree, tvb, off + 4,
266 optlen - 4, "Link-layer address");
273 proto_tree_add_text(subtree, tvb, off,
274 optlen, "IA: malformed option");
277 proto_tree_add_text(subtree, tvb, off, 4,
279 tvb_get_ntohl(tvb, off));
280 proto_tree_add_text(subtree, tvb, off+4, 4,
281 "T1: %u", tvb_get_ntohl(tvb, off+4));
282 proto_tree_add_text(subtree, tvb, off+8, 4,
283 "T2: %u", tvb_get_ntohl(tvb, off+8));
286 dhcpv6_option(tvb, subtree, off+12, off + optlen - 12, &at_end_);
291 proto_tree_add_text(subtree, tvb, off,
292 optlen, "IA_TA: malformed option");
295 proto_tree_add_text(subtree, tvb, off, 4,
297 tvb_get_ntohl(tvb, off));
300 dhcpv6_option(tvb, subtree, off+4, off + optlen - 4, &at_end_);
305 proto_tree_add_text(subtree, tvb, off,
306 optlen, "IAADDR: malformed option");
309 tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
310 proto_tree_add_text(subtree, tvb, off,
311 sizeof(in6), "IPv6 address: %s",
313 proto_tree_add_text(subtree, tvb, off+16, 4,
314 "preferred-lifetime: %u",
315 tvb_get_ntohl(tvb, off+16));
316 proto_tree_add_text(subtree, tvb, off+20, 4,
317 "valid-lifetime: %u",
318 tvb_get_ntohl(tvb, off+20));
321 dhcpv6_option(tvb, subtree, off+24, off + optlen - 24, &at_end_);
325 for (i = 0; i < optlen; i += 2) {
326 guint16 requested_opt_code;
327 requested_opt_code = tvb_get_ntohs(tvb, off + i);
328 proto_tree_add_text(subtree, tvb, off + i,
329 2, "Requested Option code: %s (%d)",
330 val_to_str(requested_opt_code,
336 case OPTION_PREFERENCE:
338 proto_tree_add_text(subtree, tvb, off,
339 optlen, "PREFERENCE: malformed option");
342 proto_tree_add_text(subtree, tvb, off, 1,
344 (guint32)tvb_get_guint8(tvb, off));
346 case OPTION_ELAPSED_TIME:
348 proto_tree_add_text(subtree, tvb, off,
349 optlen, "ELAPSED-TIME: malformed option");
352 proto_tree_add_text(subtree, tvb, off, 2,
353 "elapsed-time: %d sec",
354 (guint32)tvb_get_ntohs(tvb, off));
356 case OPTION_RELAY_MSG:
358 proto_tree_add_text(subtree, tvb, off,
359 optlen, "RELAY-MSG: malformed option");
363 dhcpv6_option(tvb, subtree, off, off + optlen, &at_end_);
368 proto_tree_add_text(subtree, tvb, off,
369 optlen, "AUTH: malformed option");
372 proto_tree_add_text(subtree, tvb, off, 1,
374 (guint32)tvb_get_guint8(tvb, off));
375 proto_tree_add_text(subtree, tvb, off+1, 1,
377 (guint32)tvb_get_guint8(tvb, off+1));
378 proto_tree_add_text(subtree, tvb, off+2, 1,
380 (guint32)tvb_get_guint8(tvb, off+2));
381 proto_tree_add_text(subtree, tvb, off+3, 8,
383 proto_tree_add_text(subtree, tvb, off+11, optlen-11,
384 "Authentication Information");
388 proto_tree_add_text(subtree, tvb, off,
389 optlen, "UNICAST: malformed option");
392 tvb_memcpy(tvb, (guint8 *)&in6, off, sizeof(in6));
393 proto_tree_add_text(subtree, tvb, off,
394 sizeof(in6), "IPv6 address: %s",
397 case OPTION_STATUS_CODE:
400 char *status_message = 0;
401 status_code = tvb_get_ntohs(tvb, off);
402 proto_tree_add_text(subtree, tvb, off, 2,
403 "Status Code: %s (%d)",
404 val_to_str(status_code, statuscode_vals,
409 status_message = g_malloc(optlen - 2 + 1);
410 if (status_message != 0){
411 memset(status_message, 0, optlen - 2 + 1);
412 status_message = tvb_memcpy(tvb, status_message, off + 2,
414 proto_tree_add_text(subtree, tvb, off + 2, optlen - 2,
415 "Status Message: %s",
417 g_free(status_message);
421 case OPTION_VENDOR_CLASS:
423 proto_tree_add_text(subtree, tvb, off,
424 optlen, "VENDOR_CLASS: malformed option");
427 proto_tree_add_text(subtree, tvb, off, 4,
428 "enterprise-number: %u",
429 tvb_get_ntohl(tvb, off));
431 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
432 "vendor-class-data");
435 case OPTION_VENDOR_OPTS:
437 proto_tree_add_text(subtree, tvb, off,
438 optlen, "VENDOR_OPTS: malformed option");
441 proto_tree_add_text(subtree, tvb, off, 4,
442 "enterprise-number: %u",
443 tvb_get_ntohl(tvb, off));
445 proto_tree_add_text(subtree, tvb, off+4, optlen-4,
449 case OPTION_INTERFACE_ID:
451 proto_tree_add_text(subtree, tvb, off,
452 optlen, "INTERFACE_ID: malformed option");
455 proto_tree_add_text(subtree, tvb, off, optlen, "Interface-ID");
457 case OPTION_RECONF_MSG:
459 proto_tree_add_text(subtree, tvb, off,
460 optlen, "RECONF_MSG: malformed option");
463 proto_tree_add_text(subtree, tvb, off, optlen,
464 "Reconfigure-type: %s",
465 val_to_str(tvb_get_guint8(tvb, off),
469 case OPTION_RECONF_NONCE:
471 proto_tree_add_text(subtree, tvb, off,
472 optlen, "RECONF_NONCE: malformed option");
475 proto_tree_add_text(subtree, tvb, off, optlen,
476 "Reconfigure-nonce");
478 case OPTION_DNS_SERVERS:
480 proto_tree_add_text(subtree, tvb, off, optlen,
481 "DNS servers address: malformed option");
484 for (i = 0; i < optlen; i += 16) {
485 tvb_memcpy(tvb, (guint8 *)&in6, off + i, sizeof(in6));
486 proto_tree_add_text(subtree, tvb, off + i,
487 sizeof(in6), "DNS servers address: %s",
491 case OPTION_DOMAIN_LIST:
493 proto_tree_add_text(subtree, tvb, off, optlen, "Search String");
496 case OPTION_PREFIXDEL:
499 dhcpv6_option(tvb, subtree, off, off + optlen, &at_end_);
502 case OPTION_PREFIX_INFO:
504 guint32 lease_duration;
505 guint8 prefix_length;
506 struct e_in6_addr in6;
508 lease_duration = tvb_get_ntohl(tvb, off);
509 prefix_length = tvb_get_guint8(tvb, off + 4);
510 if ( lease_duration == DHCPV6_LEASEDURATION_INFINITY) {
511 proto_tree_add_text(subtree, tvb, off, 4,
512 "Lease duration: infinity");
514 proto_tree_add_text(subtree, tvb, off, 4,
515 "Lease duration: %u", lease_duration);
517 proto_tree_add_text(subtree, tvb, off + 4, 1,
518 "Prefix length: %d", prefix_length);
519 tvb_memcpy(tvb, (guint8 *)&in6, off + 5 , sizeof(in6));
520 proto_tree_add_text(subtree, tvb, off + 5,
521 16, "Prefix address: %s",
525 case OPTION_PREFIXREQ:
527 guint8 prefix_length;
528 prefix_length = tvb_get_guint8(tvb, off);
529 proto_tree_add_text(subtree, tvb, off, 1,
530 "Prefix length: %d", prefix_length);
541 dissect_dhcpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
544 proto_tree *bp_tree = NULL;
551 downstream = 0; /* feature reserved */
552 if (check_col(pinfo->cinfo, COL_PROTOCOL))
553 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCPv6");
554 if (check_col(pinfo->cinfo, COL_INFO))
555 col_clear(pinfo->cinfo, COL_INFO);
557 msgtype = tvb_get_guint8(tvb, 0);
559 /* XXX relay agent messages have to be decoded differently */
561 xid = tvb_get_ntohl(tvb, 0) & 0x00ffffff;
563 if (check_col(pinfo->cinfo, COL_INFO)) {
564 col_set_str(pinfo->cinfo, COL_INFO,
571 ti = proto_tree_add_item(tree, proto_dhcpv6, tvb, 0, -1, FALSE);
572 bp_tree = proto_item_add_subtree(ti, ett_dhcpv6);
574 proto_tree_add_uint(bp_tree, hf_dhcpv6_msgtype, tvb, 0, 1,
576 proto_tree_add_text(bp_tree, tvb, 1, 3, "Transaction-ID: 0x%08x", xid);
578 tvb_memcpy(tvb, (guint8 *)&in6, 4, sizeof(in6));
579 proto_tree_add_text(bp_tree, tvb, 4, sizeof(in6),
580 "Server address: %s", ip6_to_str(&in6));
585 eoff = tvb_reported_length(tvb);
588 while (off < eoff && !at_end)
589 off += dhcpv6_option(tvb, bp_tree, off, eoff, &at_end);
593 dissect_dhcpv6_downstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
595 dissect_dhcpv6(tvb, pinfo, tree, TRUE);
599 dissect_dhcpv6_upstream(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
601 dissect_dhcpv6(tvb, pinfo, tree, FALSE);
606 proto_register_dhcpv6(void)
608 static hf_register_info hf[] = {
609 { &hf_dhcpv6_msgtype,
610 { "Message type", "dhcpv6.msgtype", FT_UINT8,
611 BASE_DEC, VALS(msgtype_vals), 0x0,
614 static gint *ett[] = {
619 proto_dhcpv6 = proto_register_protocol("DHCPv6", "DHCPv6", "dhcpv6");
620 proto_register_field_array(proto_dhcpv6, hf, array_length(hf));
621 proto_register_subtree_array(ett, array_length(ett));
625 proto_reg_handoff_dhcpv6(void)
627 dissector_handle_t dhcpv6_handle;
629 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_downstream,
631 dissector_add("udp.port", UDP_PORT_DHCPV6_DOWNSTREAM, dhcpv6_handle);
632 dhcpv6_handle = create_dissector_handle(dissect_dhcpv6_upstream,
634 dissector_add("udp.port", UDP_PORT_DHCPV6_UPSTREAM, dhcpv6_handle);