X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/111ff8a61dd320445f1d5167559cf65bfc2c26ca..ffa1470e5c7ff0e50028d085a481dc797b0b51ed:/print-dhcp6.c diff --git a/print-dhcp6.c b/print-dhcp6.c index 066759ae..73b7b383 100644 --- a/print-dhcp6.c +++ b/print-dhcp6.c @@ -27,31 +27,35 @@ * SUCH DAMAGE. */ /* - * draft-ietf-dhc-dhcpv6-22.txt + * RFC3315: DHCPv6 + * supported DHCPv6 options: + * RFC3319, + * RFC3633, + * RFC3646, + * draft-ietf-dhc-dhcpv6-opt-timeconfig-03.txt, + * draft-ietf-dhc-lifetime-00.txt, */ #ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.18 2002-06-11 17:08:44 itojun Exp $"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.35 2004-07-06 22:16:03 guy Exp $"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include -#include -#include +#include -#include - -#include #include #include -#include #include "interface.h" #include "addrtoname.h" +#include "extract.h" + +/* lease duration */ +#define DHCP6_DURATITION_INFINITE 0xffffffff /* Error Values */ #define DH6ERR_FAILURE 16 @@ -61,8 +65,19 @@ static const char rcsid[] = #define DH6ERR_OPTUNAVAIL 20 /* Message type */ +#define DH6_SOLICIT 1 +#define DH6_ADVERTISE 2 +#define DH6_REQUEST 3 +#define DH6_CONFIRM 4 +#define DH6_RENEW 5 +#define DH6_REBIND 6 #define DH6_REPLY 7 +#define DH6_RELEASE 8 +#define DH6_DECLINE 9 +#define DH6_RECONFIGURE 10 #define DH6_INFORM_REQ 11 +#define DH6_RELAY_FORW 12 +#define DH6_RELAY_REPLY 13 /* DHCP6 base packet format */ struct dhcp6 { @@ -70,61 +85,258 @@ struct dhcp6 { u_int8_t m; u_int32_t x; } dh6_msgtypexid; - struct in6_addr dh6_servaddr; /* options follow */ -} __attribute__ ((__packed__)); +}; #define dh6_msgtype dh6_msgtypexid.m #define dh6_xid dh6_msgtypexid.x #define DH6_XIDMASK 0x00ffffff -/* option */ -#define DH6OPT_DUID 1 /* TBD */ -#define DH6OPT_DNS 11 /* TBD */ +/* DHCPv6 relay messages */ +struct dhcp6_relay { + u_int8_t dh6relay_msgtype; + u_int8_t dh6relay_hcnt; + u_int8_t dh6relay_linkaddr[16]; /* XXX: badly aligned */ + u_int8_t dh6relay_peeraddr[16]; + /* options follow */ +}; + +/* options */ +#define DH6OPT_CLIENTID 1 +#define DH6OPT_SERVERID 2 +#define DH6OPT_IA_NA 3 +#define DH6OPT_IA_TMP 4 +#define DH6OPT_IADDR 5 +#define DH6OPT_ORO 6 +#define DH6OPT_PREFERENCE 7 +# define DH6OPT_PREF_MAX 255 +#define DH6OPT_ELAPSED_TIME 8 +#define DH6OPT_RELAY_MSG 9 +/*#define DH6OPT_SERVER_MSG 10 deprecated */ +#define DH6OPT_AUTH 11 +# define DH6OPT_AUTHPROTO_DELAYED 2 +# define DH6OPT_AUTHPROTO_RECONFIG 3 +# define DH6OPT_AUTHALG_HMACMD5 1 +# define DH6OPT_AUTHRDM_MONOCOUNTER 0 +# define DH6OPT_AUTHRECONFIG_KEY 1 +# define DH6OPT_AUTHRECONFIG_HMACMD5 2 +#define DH6OPT_UNICAST 12 +#define DH6OPT_STATUS_CODE 13 +# define DH6OPT_STCODE_SUCCESS 0 +# define DH6OPT_STCODE_UNSPECFAIL 1 +# define DH6OPT_STCODE_NOADDRAVAIL 2 +# define DH6OPT_STCODE_NOBINDING 3 +# define DH6OPT_STCODE_NOTONLINK 4 +# define DH6OPT_STCODE_USEMULTICAST 5 +# define DH6OPT_STCODE_NOPREFIXAVAIL 6 +#define DH6OPT_RAPID_COMMIT 14 +#define DH6OPT_USER_CLASS 15 +#define DH6OPT_VENDOR_CLASS 16 +#define DH6OPT_VENDOR_OPTS 17 +#define DH6OPT_INTERFACE_ID 18 +#define DH6OPT_RECONF_MSG 19 +#define DH6OPT_RECONF_ACCEPT 20 +#define DH6OPT_SIP_SERVER_D 21 +#define DH6OPT_SIP_SERVER_A 22 +#define DH6OPT_DNS 23 +#define DH6OPT_DNSNAME 24 +#define DH6OPT_IA_PD 25 +#define DH6OPT_IA_PD_PREFIX 26 + +/* + * The old prefix delegation option used in the service specification document + * (200206xx version) by NTT Communications. + */ +#define DH6OPT_PREFIX_DELEGATION 30 +#define DH6OPT_PREFIX_INFORMATION 31 +#define DH6OPT_PREFIX_REQUEST 32 + +/* + * The following one is an unassigned number. + * We temporarily use values as of KAME snap 20040322. + */ +#define DH6OPT_NTP_SERVERS 35 +#define DH6OPT_LIFETIME 36 + struct dhcp6opt { u_int16_t dh6opt_type; u_int16_t dh6opt_len; /* type-dependent data follows */ +}; + +struct dhcp6_ia { + u_int16_t dh6opt_ia_type; + u_int16_t dh6opt_ia_len; + u_int32_t dh6opt_ia_iaid; + u_int32_t dh6opt_ia_t1; + u_int32_t dh6opt_ia_t2; +}; + +struct dhcp6_ia_prefix { + u_int16_t dh6opt_ia_prefix_type; + u_int16_t dh6opt_ia_prefix_len; + u_int32_t dh6opt_ia_prefix_pltime; + u_int32_t dh6opt_ia_prefix_vltime; + u_int8_t dh6opt_ia_prefix_plen; + struct in6_addr dh6opt_ia_prefix_addr; +} __attribute__ ((__packed__)); + +struct dhcp6_auth { + u_int16_t dh6opt_auth_type; + u_int16_t dh6opt_auth_len; + u_int8_t dh6opt_auth_proto; + u_int8_t dh6opt_auth_alg; + u_int8_t dh6opt_auth_rdm; + u_int8_t dh6opt_auth_rdinfo[8]; + /* authentication information follows */ } __attribute__ ((__packed__)); +static const char * +dhcp6opt_name(int type) +{ + static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */ + + if (type > 65535) + return "INVALID option"; + + switch(type) { + case DH6OPT_CLIENTID: + return "client ID"; + case DH6OPT_SERVERID: + return "server ID"; + case DH6OPT_IA_NA: + return "IA_NA"; + case DH6OPT_ORO: + return "option request"; + case DH6OPT_PREFERENCE: + return "preference"; + case DH6OPT_ELAPSED_TIME: + return "elapsed time"; + case DH6OPT_RELAY_MSG: + return "relay message"; + case DH6OPT_AUTH: + return "authentication"; + case DH6OPT_UNICAST: + return "server unicast"; + case DH6OPT_STATUS_CODE: + return "status code"; + case DH6OPT_RAPID_COMMIT: + return "rapid commit"; + case DH6OPT_USER_CLASS: + return "user class"; + case DH6OPT_VENDOR_CLASS: + return "vendor class"; + case DH6OPT_VENDOR_OPTS: + return "vendor-specific info"; + case DH6OPT_INTERFACE_ID: + return "interface ID"; + case DH6OPT_RECONF_MSG: + return "reconfigure message"; + case DH6OPT_RECONF_ACCEPT: + return "reconfigure accept"; + case DH6OPT_SIP_SERVER_D: + return "SIP servers domain"; + case DH6OPT_SIP_SERVER_A: + return "SIP servers address"; + case DH6OPT_DNS: + return "DNS"; + case DH6OPT_DNSNAME: + return "DNS name"; + case DH6OPT_PREFIX_DELEGATION: + return "prefix delegation"; + case DH6OPT_PREFIX_INFORMATION: + return "prefix information"; + case DH6OPT_IA_PD: + return "IA_PD"; + case DH6OPT_IA_PD_PREFIX: + return "IA_PD prefix"; + case DH6OPT_NTP_SERVERS: + return "NTP Server"; + case DH6OPT_LIFETIME: + return "lifetime"; + default: + snprintf(genstr, sizeof(genstr), "opt_%d", type); + return(genstr); + } +} + +static const char * +dhcp6stcode(int code) +{ + static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */ + + if (code > 255) + return "INVALID code"; + + switch(code) { + case DH6OPT_STCODE_SUCCESS: + return "success"; + case DH6OPT_STCODE_UNSPECFAIL: + return "unspec failure"; + case DH6OPT_STCODE_NOADDRAVAIL: + return "no addresses"; + case DH6OPT_STCODE_NOBINDING: + return "no binding"; + case DH6OPT_STCODE_NOTONLINK: + return "not on-link"; + case DH6OPT_STCODE_USEMULTICAST: + return "use multicast"; + case DH6OPT_STCODE_NOPREFIXAVAIL: + return "no prefixes"; + default: + snprintf(genstr, sizeof(genstr), "code%d", code); + return(genstr); + } +} + static void -dhcp6opt_print(u_char *cp, u_char *ep) +dhcp6opt_print(const u_char *cp, const u_char *ep) { struct dhcp6opt *dh6o; u_char *tp; - int i; + size_t i; + u_int16_t opttype; size_t optlen; + u_int16_t val16; + u_int32_t val32; + struct in6_addr addr6; + struct dhcp6_ia ia; + struct dhcp6_ia_prefix ia_prefix; + struct dhcp6_auth authopt; + u_int authinfolen, authrealmlen; if (cp == ep) return; while (cp < ep) { - if (ep - cp < sizeof(*dh6o)) + if (ep < cp + sizeof(*dh6o)) goto trunc; dh6o = (struct dhcp6opt *)cp; - optlen = ntohs(dh6o->dh6opt_len); - if (ep - cp < sizeof(*dh6o) + optlen) + optlen = EXTRACT_16BITS(&dh6o->dh6opt_len); + if (ep < cp + sizeof(*dh6o) + optlen) goto trunc; - switch (ntohs(dh6o->dh6opt_type)) { - case DH6OPT_DUID: - printf(" (duid"); /*)*/ + opttype = EXTRACT_16BITS(&dh6o->dh6opt_type); + printf(" (%s", dhcp6opt_name(opttype)); + switch (opttype) { + case DH6OPT_CLIENTID: + case DH6OPT_SERVERID: if (optlen < 2) { /*(*/ - printf(" ??)"); + printf(" ?)"); break; } tp = (u_char *)(dh6o + 1); - switch (ntohs(*(u_int16_t *)tp)) { + switch (EXTRACT_16BITS(tp)) { case 1: if (optlen >= 2 + 6) { - printf(" hwaddr/time time %u type %u ", - ntohl(*(u_int32_t *)&tp[2]), - ntohs(*(u_int16_t *)&tp[6])); + printf(" hwaddr/time type %u time %u ", + EXTRACT_16BITS(&tp[2]), + EXTRACT_32BITS(&tp[4])); for (i = 8; i < optlen; i++) printf("%02x", tp[i]); /*(*/ printf(")"); } else { /*(*/ - printf(" ??)"); + printf(" ?)"); } break; case 2: @@ -136,37 +348,277 @@ dhcp6opt_print(u_char *cp, u_char *ep) printf(")"); } else { /*(*/ - printf(" ??)"); + printf(" ?)"); } break; case 3: if (optlen >= 2 + 2) { printf(" hwaddr type %u ", - ntohs(*(u_int16_t *)&tp[2])); + EXTRACT_16BITS(&tp[2])); for (i = 4; i < optlen; i++) printf("%02x", tp[i]); /*(*/ printf(")"); } else { /*(*/ - printf(" ??)"); + printf(" ?)"); } + break; + default: + printf(" type %d)", EXTRACT_16BITS(tp)); + break; } break; + case DH6OPT_ORO: + if (optlen % 2) { + printf(" ?)"); + break; + } + tp = (u_char *)(dh6o + 1); + for (i = 0; i < optlen; i += 2) { + u_int16_t opt; + + memcpy(&opt, &tp[i], sizeof(opt)); + printf(" %s", dhcp6opt_name(ntohs(opt))); + } + printf(")"); + break; + case DH6OPT_PREFERENCE: + if (optlen != 1) { + printf(" ?)"); + break; + } + printf(" %d)", *((u_char *)(dh6o + 1) + 1)); + break; + case DH6OPT_ELAPSED_TIME: + if (optlen != 2) { + printf(" ?)"); + break; + } + memcpy(&val16, dh6o + 1, sizeof(val16)); + val16 = ntohs(val16); + printf(" %d)", (int)val16); + break; + case DH6OPT_RELAY_MSG: + printf(" ("); + dhcp6_print((const u_char *)(dh6o + 1), optlen); + printf(")"); + break; + case DH6OPT_AUTH: + if (optlen < sizeof(authopt) - sizeof(*dh6o)) { + printf(" ?)"); + break; + } + memcpy(&authopt, dh6o, sizeof(authopt)); + switch (authopt.dh6opt_auth_proto) { + case DH6OPT_AUTHPROTO_DELAYED: + printf(" proto: delayed"); + break; + case DH6OPT_AUTHPROTO_RECONFIG: + printf(" proto: reconfigure"); + break; + default: + printf(" proto: %d", + authopt.dh6opt_auth_proto); + break; + } + switch (authopt.dh6opt_auth_alg) { + case DH6OPT_AUTHALG_HMACMD5: + /* XXX: may depend on the protocol */ + printf(", alg: HMAC-MD5"); + break; + default: + printf(", alg: %d", authopt.dh6opt_auth_alg); + break; + } + switch (authopt.dh6opt_auth_rdm) { + case DH6OPT_AUTHRDM_MONOCOUNTER: + printf(", RDM: mono"); + break; + default: + printf(", RDM: %d", authopt.dh6opt_auth_rdm); + break; + } + tp = (u_char *)&authopt.dh6opt_auth_rdinfo; + printf(", RD:"); + for (i = 0; i < 4; i++, tp += sizeof(val16)) + printf(" %04x", EXTRACT_16BITS(tp)); + + /* protocol dependent part */ + tp = (u_char *)dh6o + sizeof(authopt); + authinfolen = + optlen + sizeof(*dh6o) - sizeof(authopt); + switch (authopt.dh6opt_auth_proto) { + case DH6OPT_AUTHPROTO_DELAYED: + if (authinfolen == 0) + break; + if (authinfolen < 20) { + printf(" ??"); + break; + } + authrealmlen = authinfolen - 20; + if (authrealmlen > 0) { + printf(", realm: "); + } + for (i = 0; i < authrealmlen; i++, tp++) + printf("%02x", *tp); + printf(", key ID: %08x", EXTRACT_32BITS(tp)); + tp += 4; + printf(", HMAC-MD5:"); + for (i = 0; i < 4; i++, tp+= 4) + printf(" %08x", EXTRACT_32BITS(tp)); + break; + case DH6OPT_AUTHPROTO_RECONFIG: + if (authinfolen != 17) { + printf(" ??"); + break; + } + switch (*tp++) { + case DH6OPT_AUTHRECONFIG_KEY: + printf(" reconfig-key"); + break; + case DH6OPT_AUTHRECONFIG_HMACMD5: + printf(" type: HMAC-MD5"); + break; + default: + printf(" type: ??"); + break; + } + printf(" value:"); + for (i = 0; i < 4; i++, tp+= 4) + printf(" %08x", EXTRACT_32BITS(tp)); + break; + default: + printf(" ??"); + break; + } + + printf(")"); + break; + case DH6OPT_RAPID_COMMIT: /* nothing todo */ + printf(")"); + break; + case DH6OPT_INTERFACE_ID: + /* + * Since we cannot predict the encoding, print hex dump + * at most 10 characters. + */ + for (i = 0; i < optlen && i < 10; i++) + printf("%02x", ((u_char *)(dh6o + 1))[i]); + break; + case DH6OPT_RECONF_MSG: + tp = (u_char *)(dh6o + 1); + switch (*tp) { + case DH6_RENEW: + printf(" for renew)"); + break; + case DH6_INFORM_REQ: + printf(" for inf-req)"); + break; + default: + printf(" for ?\?\?(%02x))", *tp); + break; + } + break; + case DH6OPT_RECONF_ACCEPT: /* nothing todo */ + printf(")"); + break; + case DH6OPT_SIP_SERVER_A: case DH6OPT_DNS: - printf(" (dnsserver"); /*)*/ + case DH6OPT_NTP_SERVERS: if (optlen % 16) { - /*(*/ - printf(" ??)"); + printf(" ?)"); break; } tp = (u_char *)(dh6o + 1); for (i = 0; i < optlen; i += 16) printf(" %s", ip6addr_string(&tp[i])); - /*(*/ printf(")"); + break; + case DH6OPT_PREFIX_DELEGATION: + dhcp6opt_print((u_char *)(dh6o + 1), + (u_char *)(dh6o + 1) + optlen); + printf(")"); + break; + case DH6OPT_PREFIX_INFORMATION: + if (optlen % 21) + printf(" ?)"); + memcpy(&addr6, (u_char *)(dh6o + 1) + 5, + sizeof(addr6)); + printf(" %s/%d", ip6addr_string(&addr6), + (int)*((u_char *)(dh6o + 1) + 4)); + memcpy(&val32, dh6o + 1, sizeof(val32)); + val32 = ntohl(val32); + if (val32 == DHCP6_DURATITION_INFINITE) + printf(" lease-duration: infinite)"); + else + printf(" lease-duration: %u)", val32); + break; + case DH6OPT_STATUS_CODE: + if (optlen < 2) { + printf(" ?)"); + break; + } + memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16)); + val16 = ntohs(val16); + printf(" %s)", dhcp6stcode(val16)); + break; + case DH6OPT_IA_NA: + case DH6OPT_IA_PD: + if (optlen < sizeof(ia) - 4) { + printf(" ?)"); + break; + } + memcpy(&ia, (u_char *)dh6o, sizeof(ia)); + ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid); + ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1); + ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2); + printf(" IAID:%lu T1:%lu T2:%lu", + (unsigned long)ia.dh6opt_ia_iaid, + (unsigned long)ia.dh6opt_ia_t1, + (unsigned long)ia.dh6opt_ia_t2); + if (optlen > sizeof(ia) - 4) { + /* there are sub-options */ + dhcp6opt_print((u_char *)dh6o + sizeof(ia), + (u_char *)(dh6o + 1) + optlen); + } + printf(")"); + break; + case DH6OPT_IA_PD_PREFIX: + if (optlen < sizeof(ia_prefix) - 4) { + printf(" ?)"); + break; + } + memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix)); + printf(" %s/%d", + ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr), + ia_prefix.dh6opt_ia_prefix_plen); + ia_prefix.dh6opt_ia_prefix_pltime = + ntohl(ia_prefix.dh6opt_ia_prefix_pltime); + ia_prefix.dh6opt_ia_prefix_vltime = + ntohl(ia_prefix.dh6opt_ia_prefix_vltime); + printf(" pltime:%lu vltime:%lu", + (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime, + (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime); + if (optlen > sizeof(ia_prefix) - 4) { + /* there are sub-options */ + dhcp6opt_print((u_char *)dh6o + + sizeof(ia_prefix), + (u_char *)(dh6o + 1) + optlen); + } + printf(")"); + break; + case DH6OPT_LIFETIME: + if (optlen != 4) { + printf(" ?)"); + break; + } + memcpy(&val32, dh6o + 1, sizeof(val32)); + val32 = ntohl(val32); + printf(" %d)", (int)val32); + break; default: - printf(" (opt-%u)", ntohs(dh6o->dh6opt_type)); + printf(")"); break; } @@ -182,27 +634,63 @@ trunc: * Print dhcp6 packets */ void -dhcp6_print(register const u_char *cp, u_int length, - u_int16_t sport, u_int16_t dport) +dhcp6_print(const u_char *cp, u_int length) { struct dhcp6 *dh6; - u_char *ep; + struct dhcp6_relay *dh6relay; + const u_char *ep; u_char *extp; const char *name; printf("dhcp6"); ep = (u_char *)snapend; + if (cp + length < ep) + ep = cp + length; dh6 = (struct dhcp6 *)cp; - TCHECK(dh6->dh6_servaddr); + dh6relay = (struct dhcp6_relay *)cp; + TCHECK(dh6->dh6_xid); switch (dh6->dh6_msgtype) { + case DH6_SOLICIT: + name = "solicit"; + break; + case DH6_ADVERTISE: + name = "advertise"; + break; + case DH6_REQUEST: + name = "request"; + break; + case DH6_CONFIRM: + name = "confirm"; + break; + case DH6_RENEW: + name = "renew"; + break; + case DH6_REBIND: + name = "rebind"; + break; case DH6_REPLY: name = "reply"; break; + case DH6_RELEASE: + name = "release"; + break; + case DH6_DECLINE: + name = "decline"; + break; + case DH6_RECONFIGURE: + name = "reconfigure"; + break; case DH6_INFORM_REQ: name= "inf-req"; break; + case DH6_RELAY_FORW: + name= "relay-fwd"; + break; + case DH6_RELAY_REPLY: + name= "relay-reply"; + break; default: name = NULL; break; @@ -211,8 +699,10 @@ dhcp6_print(register const u_char *cp, u_int length, if (!vflag) { if (name) printf(" %s", name); - else + else if (dh6->dh6_msgtype != DH6_RELAY_FORW && + dh6->dh6_msgtype != DH6_RELAY_REPLY) { printf(" msgtype-%u", dh6->dh6_msgtype); + } return; } @@ -222,10 +712,24 @@ dhcp6_print(register const u_char *cp, u_int length, printf(" %s (", name); /*)*/ else printf(" msgtype-%u (", dh6->dh6_msgtype); /*)*/ - printf("xid=%x", ntohl(dh6->dh6_xid) & DH6_XIDMASK); - printf(" server=%s", ip6addr_string(&dh6->dh6_servaddr)); - extp = (u_char *)(dh6 + 1); - dhcp6opt_print(extp, ep); + if (dh6->dh6_msgtype != DH6_RELAY_FORW && + dh6->dh6_msgtype != DH6_RELAY_REPLY) { + printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK); + extp = (u_char *)(dh6 + 1); + dhcp6opt_print(extp, ep); + } else { /* relay messages */ + struct in6_addr addr6; + + TCHECK(dh6relay->dh6relay_peeraddr); + + memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6)); + printf("linkaddr=%s", ip6addr_string(&addr6)); + + memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6)); + printf(" peeraddr=%s", ip6addr_string(&addr6)); + + dhcp6opt_print((u_char *)(dh6relay + 1), ep); + } /*(*/ printf(")"); return;