From: Michael Richardson Date: Sat, 4 Jan 2014 15:56:47 +0000 (-0500) Subject: Merge branch 'master' of git+ssh://bpf.tcpdump.org/tcpdump/master/git/tcpdump X-Git-Tag: tcpdump-4.6.0~301 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/3f78017c596d4d4172f817d96238d6b958796796?hp=3ea7a6988e7a038e1b0604a56c828b929c60d0d5 Merge branch 'master' of git+ssh://bpf.tcpdump.org/tcpdump/master/git/tcpdump --- diff --git a/print-icmp6.c b/print-icmp6.c index 4045ffac..c4f99878 100644 --- a/print-icmp6.c +++ b/print-icmp6.c @@ -490,8 +490,7 @@ static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_ #define abs(a) ((0 < (a)) ? (a) : -(a)) #endif -/* inline the various RPL definitions */ -#define ND_RPL_MESSAGE 0x9B +#include "rpl.h" static const struct tok icmp6_type_values[] = { { ICMP6_DST_UNREACH, "destination unreachable"}, @@ -630,72 +629,6 @@ static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, IPPROTO_ICMPV6)); } -enum ND_RPL_CODE { - ND_RPL_DIS =0x00, - ND_RPL_DIO =0x01, - ND_RPL_DAO =0x02, - ND_RPL_DAO_ACK=0x03, - ND_RPL_SDIS =0x80, - ND_RPL_SDIO =0x81, - ND_RPL_SDAO =0x82, - ND_RPL_SDAO_ACK=0x83, - ND_RPL_SCC =0x8A, -}; - -enum ND_RPL_DIO_FLAGS { - ND_RPL_DIO_GROUNDED = 0x80, - ND_RPL_DIO_DATRIG = 0x40, - ND_RPL_DIO_DASUPPORT= 0x20, - ND_RPL_DIO_RES4 = 0x10, - ND_RPL_DIO_RES3 = 0x08, - ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ -}; - -enum ND_RPL_SUBOPT { - RPL_OPT_PAD0 = 0, - RPL_OPT_PADN = 1, - RPL_DIO_METRICS = 2, - RPL_DIO_ROUTINGINFO = 3, - RPL_DIO_CONFIG = 4, - RPL_DAO_RPLTARGET = 5, - RPL_DAO_TRANSITINFO = 6, - RPL_DIO_DESTPREFIX = 8, - RPL_DAO_RPLTARGET_DESC=9, -}; - -#define RPL_DIO_GROUND_FLAG 0x80 -#define RPL_DIO_MOP_SHIFT 3 -#define RPL_DIO_MOP_MASK (7 << RPL_DIO_MOP_SHIFT) -#define RPL_DIO_PRF_SHIFT 0 -#define RPL_DIO_PRF_MASK (7 << RPL_DIO_PRF_SHIFT) -#define RPL_DIO_GROUNDED(X) ((X)&RPL_DIO_GROUND_FLAG) -#define RPL_DIO_MOP(X) (((X)&RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT) -#define RPL_DIO_PRF(X) (((X)&RPL_DIO_PRF_MASK) >> RPL_DIO_PRF_SHIFT) - - -struct nd_rpl_dio { - u_int8_t rpl_instanceid; - u_int8_t rpl_version; - u_int16_t rpl_dagrank; - u_int8_t rpl_mopprf; /* bit 7=G, 5-3=MOP, 2-0=PRF */ - u_int8_t rpl_dtsn; - u_int8_t rpl_flags; /* Dest. Advertisement Trigger Seq Number */ - u_int8_t rpl_resv1; - u_int8_t rpl_dagid[16]; -}; -struct nd_rpl_option { - u_int8_t rpl_dio_type; - u_int8_t rpl_dio_len; /* suboption length, not including type/len */ - u_int8_t rpl_dio_data[0]; -}; - -enum RPL_DIO_MOP { - RPL_DIO_NONSTORING= 0x0, - RPL_DIO_STORING = 0x1, - RPL_DIO_NONSTORING_MULTICAST = 0x2, - RPL_DIO_STORING_MULTICAST = 0x3, -}; - const struct tok rpl_mop_values[] = { { RPL_DIO_NONSTORING, "nonstoring"}, { RPL_DIO_STORING, "storing"}, @@ -718,28 +651,73 @@ const struct tok rpl_subopt_values[] = { }; static void -rpl_dio_print(netdissect_options *ndo, - const struct icmp6_hdr *hdr _U_, - const u_char *bp, u_int length) +rpl_format_dagid(char dagid_str[65], u_char *dagid) { - struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; - char dagid[65]; - char *d = dagid; + char *d = dagid_str; int i; - ND_TCHECK(dio->rpl_dagid); for(i=0;i<16;i++) { - if(isprint(dio->rpl_dagid[i])) { - *d++ = dio->rpl_dagid[i]; + if(isprint(dagid[i])) { + *d++ = dagid[i]; } else { - int cnt=snprintf(d,4,"0x%02x", - dio->rpl_dagid[i]); + int cnt=snprintf(d,4,"0x%02x", dagid[i]); d += cnt; } } *d++ = '\0'; +} + +static void +rpl_dio_printopt(netdissect_options *ndo, + struct rpl_dio_genoption *opt, + u_int length) +{ + length -= sizeof(struct rpl_dio_genoption); + ND_TCHECK(opt->rpl_dio_len); + + while((opt->rpl_dio_type == RPL_OPT_PAD0 && + (u_char *)opt < ndo->ndo_snapend) || + ND_TTEST2(*opt,(opt->rpl_dio_len+2))) { + + unsigned int optlen = opt->rpl_dio_len+2; + if(opt->rpl_dio_type == RPL_OPT_PAD0) { + optlen = 1; + ND_PRINT((ndo, " opt:pad0")); + } else { + ND_PRINT((ndo, " opt:%s len:%u ", + tok2str(rpl_subopt_values, "%subopt:%u", opt->rpl_dio_type), + optlen)); + if(ndo->ndo_vflag > 2) { + unsigned int paylen = opt->rpl_dio_len; + if(paylen > length) paylen = length; + hex_print(ndo, + " ", + opt->rpl_dio_data, /* content of DIO option */ + paylen); + } + } + opt = (struct rpl_dio_genoption *)(((char *)opt) + optlen); + length -= optlen; + } + return; +trunc: + ND_PRINT((ndo," [|truncated]")); + return; +} + +static void +rpl_dio_print(netdissect_options *ndo, + const struct icmp6_hdr *hdr _U_, + const u_char *bp, u_int length) +{ + struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; + char dagid_str[65]; + + ND_TCHECK(*dio); + rpl_format_dagid(dagid_str, dio->rpl_dagid); + ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]", - dagid, + dagid_str, dio->rpl_dtsn, dio->rpl_instanceid, dio->rpl_dagrank, @@ -748,34 +726,80 @@ rpl_dio_print(netdissect_options *ndo, RPL_DIO_PRF(dio->rpl_mopprf))); if(ndo->ndo_vflag > 1) { - struct nd_rpl_option *opt = (struct nd_rpl_option *)&dio[1]; - length -= sizeof(struct nd_rpl_dio); - ND_TCHECK(opt->rpl_dio_len); - while((opt->rpl_dio_type == RPL_OPT_PAD0 && - (u_char *)opt < ndo->ndo_snapend) || - ND_TTEST2(*opt,(opt->rpl_dio_len+2))) { - unsigned int optlen = opt->rpl_dio_len+2; - if(opt->rpl_dio_type == RPL_OPT_PAD0) { - optlen = 1; - ND_PRINT((ndo, " opt:pad0")); - } else { - ND_PRINT((ndo, " opt:%s len:%u ", - tok2str(rpl_subopt_values, "%subopt:%u", opt->rpl_dio_type), - optlen)); - if(ndo->ndo_vflag > 2) { - unsigned int paylen = opt->rpl_dio_len; - if(paylen > length) paylen = length; - hex_print(ndo, - " ", - (u_char *)&opt[1], /* content of DIO option */ - paylen); - } - } - opt = (struct nd_rpl_option *)(((char *)opt) + optlen); - length -= optlen; - } + struct rpl_dio_genoption *opt = (struct rpl_dio_genoption *)&dio[1]; + rpl_dio_printopt(ndo, opt, length); + } + return; +trunc: + ND_PRINT((ndo," [|truncated]")); + return; +} + +static void +rpl_dao_print(netdissect_options *ndo, + const struct icmp6_hdr *hdr _U_, + const u_char *bp, u_int length) +{ + struct nd_rpl_dao *dao = (struct nd_rpl_dao *)bp; + u_char *dao_end = (u_char *)&dao[1]; + char dagid_str[65]; + + ND_TCHECK(*dao); + + strcpy(dagid_str,""); + if(RPL_DAO_D(dao->rpl_flags)) { + ND_TTEST2(dao->rpl_dagid, 16); + rpl_format_dagid(dagid_str, dao->rpl_dagid); + dao_end += DAGID_LEN; + } + + ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u]", + dagid_str, + dao->rpl_daoseq, + dao->rpl_instanceid)); + + if(ndo->ndo_vflag > 1) { + struct rpl_dio_genoption *opt = (struct rpl_dio_genoption *)dao_end; + rpl_dio_printopt(ndo, opt, length); + } + return; + +trunc: + ND_PRINT((ndo," [|truncated]")); + return; +} + +static void +rpl_daoack_print(netdissect_options *ndo, + const struct icmp6_hdr *hdr _U_, + const u_char *bp, u_int length) +{ + struct nd_rpl_daoack *daoack = (struct nd_rpl_daoack *)bp; + u_char *daoack_end = (u_char *)&daoack[1]; + char dagid_str[65]; + + ND_TCHECK(*daoack); + + strcpy(dagid_str,""); + if(RPL_DAOACK_D(daoack->rpl_flags)) { + ND_TTEST2(daoack->rpl_dagid, 16); + rpl_format_dagid(dagid_str, daoack->rpl_dagid); + daoack_end += DAGID_LEN; + } + + ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,status:%u]", + dagid_str, + daoack->rpl_daoseq, + daoack->rpl_instanceid, + daoack->rpl_status)); + + /* no officially defined options for DAOACK, but print anyway, we find*/ + if(ndo->ndo_vflag > 1) { + struct rpl_dio_genoption *opt = (struct rpl_dio_genoption *)daoack_end; + rpl_dio_printopt(ndo, opt, length); } return; + trunc: ND_PRINT((ndo," [|truncated]")); return; @@ -790,18 +814,23 @@ rpl_print(netdissect_options *ndo, int basecode= hdr->icmp6_code & 0x7f; if(secured) { - ND_PRINT((ndo, ", (SEC)")); + ND_PRINT((ndo, ", (SEC) [worktodo]")); + /* XXX + * the next header pointer needs to move forward to + * skip the secure part. + */ + return; } else { ND_PRINT((ndo, ", (CLR)")); } switch(basecode) { - case ND_RPL_DIS: + case ND_RPL_DAG_IS: ND_PRINT((ndo, "DODAG Information Solicitation")); if(ndo->ndo_vflag) { } break; - case ND_RPL_DIO: + case ND_RPL_DAG_IO: ND_PRINT((ndo, "DODAG Information Object")); if(ndo->ndo_vflag) { rpl_dio_print(ndo, hdr, bp, length); @@ -810,11 +839,13 @@ rpl_print(netdissect_options *ndo, case ND_RPL_DAO: ND_PRINT((ndo, "Destination Advertisement Object")); if(ndo->ndo_vflag) { + rpl_dao_print(ndo, hdr, bp, length); } break; case ND_RPL_DAO_ACK: ND_PRINT((ndo, "Destination Advertisement Object Ack")); if(ndo->ndo_vflag) { + rpl_daoack_print(ndo, hdr, bp, length); } break; default: diff --git a/rpl.h b/rpl.h new file mode 100644 index 00000000..764e9a81 --- /dev/null +++ b/rpl.h @@ -0,0 +1,166 @@ +#ifndef _RPL_H_ + +/* + * NOTE: the contents of this file are an interpretation of RFC6550. + * no copyright is asserted on this file, as it transcribes + * a public specification. + * + */ + +#define PACKED __attribute__((packed)) + +/* + * DIO: Updated to RFC6550, as published in 2012: section 6. (page 30) + */ + +#define ND_RPL_MESSAGE 155 /* 0x9B */ + +enum ND_RPL_CODE { + ND_RPL_DAG_IS=0x00, + ND_RPL_DAG_IO=0x01, + ND_RPL_DAO =0x02, + ND_RPL_DAO_ACK=0x03, + ND_RPL_SEC_DAG_IS = 0x80, + ND_RPL_SEC_DAG_IO = 0x81, + ND_RPL_SEC_DAG = 0x82, + ND_RPL_SEC_DAG_ACK= 0x83, + ND_RPL_SEC_CONSIST= 0x84, +}; + +enum ND_RPL_DIO_FLAGS { + ND_RPL_DIO_GROUNDED = 0x80, + ND_RPL_DIO_DATRIG = 0x40, + ND_RPL_DIO_DASUPPORT= 0x20, + ND_RPL_DIO_RES4 = 0x10, + ND_RPL_DIO_RES3 = 0x08, + ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ +}; + +#define DAGID_LEN 16 + +/* section 6 of draft-ietf-roll-rpl-19 */ +struct nd_rpl_security { + u_int8_t rpl_sec_t_reserved; /* bit 7 is T-bit */ + u_int8_t rpl_sec_algo; + u_int16_t rpl_sec_kim_lvl_flags; /* bit 15/14, KIM */ + /* bit 10-8, LVL, bit 7-0 flags */ + u_int32_t rpl_sec_counter; + u_int8_t rpl_sec_ki[0]; /* depends upon kim */ +} PACKED; + +/* section 6.2.1, DODAG Information Solication (DIS_IS) */ +struct nd_rpl_dis_is { + u_int8_t rpl_dis_flags; + u_int8_t rpl_dis_reserved; + u_int8_t rpl_dis_options[0]; +} PACKED; + +/* section 6.3.1, DODAG Information Object (DIO) */ +struct nd_rpl_dio { + u_int8_t rpl_instanceid; + u_int8_t rpl_version; + u_int16_t rpl_dagrank; + u_int8_t rpl_mopprf; /* bit 7=G, 5-3=MOP, 2-0=PRF */ + u_int8_t rpl_dtsn; /* Dest. Advertisement Trigger Sequence Number */ + u_int8_t rpl_flags; /* no flags defined yet */ + u_int8_t rpl_resv1; + u_int8_t rpl_dagid[DAGID_LEN]; +} PACKED; +#define RPL_DIO_GROUND_FLAG 0x80 +#define RPL_DIO_MOP_SHIFT 3 +#define RPL_DIO_MOP_MASK (7 << RPL_DIO_MOP_SHIFT) +#define RPL_DIO_PRF_SHIFT 0 +#define RPL_DIO_PRF_MASK (7 << RPL_DIO_PRF_SHIFT) +#define RPL_DIO_GROUNDED(X) ((X)&RPL_DIO_GROUND_FLAG) +#define RPL_DIO_MOP(X) (enum RPL_DIO_MOP)(((X)&RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT) +#define RPL_DIO_PRF(X) (((X)&RPL_DIO_PRF_MASK) >> RPL_DIO_PRF_SHIFT) + +enum RPL_DIO_MOP { + RPL_DIO_NONSTORING= 0x0, + RPL_DIO_STORING = 0x1, + RPL_DIO_NONSTORING_MULTICAST = 0x2, + RPL_DIO_STORING_MULTICAST = 0x3, +}; + +enum RPL_SUBOPT { + RPL_OPT_PAD0 = 0, + RPL_OPT_PADN = 1, + RPL_DIO_METRICS = 2, + RPL_DIO_ROUTINGINFO = 3, + RPL_DIO_CONFIG = 4, + RPL_DAO_RPLTARGET = 5, + RPL_DAO_TRANSITINFO = 6, + RPL_DIO_DESTPREFIX = 8, + RPL_DAO_RPLTARGET_DESC=9, +}; + +struct rpl_dio_genoption { + u_int8_t rpl_dio_type; + u_int8_t rpl_dio_len; /* suboption length, not including type/len */ + u_int8_t rpl_dio_data[0]; +} PACKED; + +#define RPL_DIO_LIFETIME_INFINITE 0xffffffff +#define RPL_DIO_LIFETIME_DISCONNECT 0 + +struct rpl_dio_destprefix { + u_int8_t rpl_dio_type; + u_int8_t rpl_dio_len; + u_int8_t rpl_dio_prefixlen; /* in bits */ + u_int8_t rpl_dio_prf; /* flags, including Route Preference */ + u_int32_t rpl_dio_prefixlifetime; /* in seconds */ + u_int8_t rpl_dio_prefix[0]; /* variables number of bytes */ +} PACKED; + +/* section 6.4.1, DODAG Information Object (DIO) */ +struct nd_rpl_dao { + u_int8_t rpl_instanceid; + u_int8_t rpl_flags; /* bit 7=K, 6=D */ + u_int8_t rpl_resv; + u_int8_t rpl_daoseq; + u_int8_t rpl_dagid[0]; /* [DAGID_LEN] present when D set. */ +} PACKED; + +/* indicates if this DAO is to be acK'ed */ +#define RPL_DAO_K_SHIFT 7 +#define RPL_DAO_K_MASK (1 << RPL_DAO_K_SHIFT) +#define RPL_DAO_K(X) (((X)&RPL_DAO_K_MASK) >> RPL_DAO_K_SHIFT) + +/* indicates if the DAGID is present */ +#define RPL_DAO_D_SHIFT 6 +#define RPL_DAO_D_MASK (1 << RPL_DAO_D_SHIFT) +#define RPL_DAO_D(X) (((X)&RPL_DAO_D_MASK) >> RPL_DAO_D_SHIFT) + +struct rpl_dao_target { + u_int8_t rpl_dao_type; + u_int8_t rpl_dao_len; + u_int8_t rpl_dao_flags; /* unused */ + u_int8_t rpl_dao_prefixlen; /* in bits */ + u_int8_t rpl_dao_prefix[0]; /* variables number of bytes */ +} PACKED; + +/* section 6.5.1, Destination Advertisement Object Acknowledgement (DAO-ACK) */ +struct nd_rpl_daoack { + u_int8_t rpl_instanceid; + u_int8_t rpl_flags; /* bit 7=D */ + u_int8_t rpl_daoseq; + u_int8_t rpl_status; + u_int8_t rpl_dagid[0]; /* [DAGID_LEN] present when D set. */ +} PACKED; +/* indicates if the DAGID is present */ +#define RPL_DAOACK_D_SHIFT 7 +#define RPL_DAOACK_D_MASK (1 << RPL_DAOACK_D_SHIFT) +#define RPL_DAOACK_D(X) (((X)&RPL_DAOACK_D_MASK) >> RPL_DAOACK_D_SHIFT) + + + +#define _RPL_H_ +#endif /* _RPL_H_ */ + +/* + * Local Variables: + * c-basic-offset:4 + * c-style: whitesmith + * End: + */ + diff --git a/tests/19-pickdag.out b/tests/19-pickdag.out index 69a63826..0a81604a 100644 --- a/tests/19-pickdag.out +++ b/tests/19-pickdag.out @@ -1,2 +1,2 @@ IP6 (hlim 64, next-header ICMPv6 (58) payload length: 48) fe80::216:3eff:fe11:3424 > ff02::1: [icmp6 sum ok] ICMP6, RPL, (CLR)DODAG Information Object [dagid:T10x0,seq:10,instance:42,rank:768,grounded,mop:storing,prf:0] opt:destprefix len:15 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 -IP6 (hlim 64, next-header ICMPv6 (58) payload length: 56) fe80::216:3eff:fe11:3424 > fe80::216:3eff:fe11:3424: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object +IP6 (hlim 64, next-header ICMPv6 (58) payload length: 56) fe80::216:3eff:fe11:3424 > fe80::216:3eff:fe11:3424: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object [dagid:T10x0,seq:10,instance:42] opt:rpltarget len:25 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 diff --git a/tests/19-pickdagvvv.out b/tests/19-pickdagvvv.out index 4f438bae..fc6cbd46 100644 --- a/tests/19-pickdagvvv.out +++ b/tests/19-pickdagvvv.out @@ -1,2 +1,2 @@ IP6 (hlim 64, next-header ICMPv6 (58) payload length: 48) fe80::216:3eff:fe11:3424 > ff02::1: [icmp6 sum ok] ICMP6, RPL, (CLR)DODAG Information Object [dagid:T10x0,seq:10,instance:42,rank:768,grounded,mop:storing,prf:0] opt:destprefix len:15 0x0000: 3000 0000 0000 2001 0db8 0001 00 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 -IP6 (hlim 64, next-header ICMPv6 (58) payload length: 56) fe80::216:3eff:fe11:3424 > fe80::216:3eff:fe11:3424: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object +IP6 (hlim 64, next-header ICMPv6 (58) payload length: 56) fe80::216:3eff:fe11:3424 > fe80::216:3eff:fe11:3424: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object [dagid:T10x0,seq:10,instance:42] opt:rpltarget len:25 0x0000: 0080 2001 0db8 0001 0000 0216 3eff fe11 0x0010: 3424 0000 0000 00 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 opt:pad0 diff --git a/tests/dio.out b/tests/dio.out index 4f0c1894..02912af6 100644 --- a/tests/dio.out +++ b/tests/dio.out @@ -1 +1 @@ -IP6 (hlim 255, next-header ICMPv6 (58) payload length: 24) fe80::1000:ff:fe64:6423 > ff02::1: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object +IP6 (hlim 255, next-header ICMPv6 (58) payload length: 24) fe80::1000:ff:fe64:6423 > ff02::1: [icmp6 sum ok] ICMP6, RPL, (CLR)Destination Advertisement Object [dagid:,seq:1,instance:0]