Ethereal-dev: [Ethereal-dev] improved NTP decoding
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Matthias Drochner <M.Drochner@xxxxxxxxxxxxx>
Date: Wed, 12 Nov 2003 13:39:01 +0100
Hi - I'll append a patch which improves NTP decoding. It fixes 2 problems: -"mode 6" and "mode 7" control packets (as used by ntpq and ntpdc, respectively) were not recognized, leading to nonsense -the code couldn't deal with the new NTP4 autokey extension data; everything unknown was labeled "MAC" My patch doesn't decode every detail as the protocol if quite complex. For the control packets it does as much as needed to get to the request code. In the autokey stuff, it avoids the cryptographic details. This is my first try writing an ethereal decoder, so it would be good if someone experienced looked over it. Please Cc: me directly. I'm not subscribed to the list. best regards Matthias
$NetBSD$ --- packet-ntp.c.orig 2003-07-10 03:20:12.000000000 +0200 +++ packet-ntp.c @@ -186,7 +186,111 @@ static const struct { { NULL, NULL} }; +#define NTP_EXT_R_MASK 0x80 + +static const value_string ext_r_types[] = { + { 0, "Request" }, + { 1, "Response" }, + { 0, NULL} +}; + +#define NTP_EXT_ERROR_MASK 0x40 +#define NTP_EXT_VN_MASK 0x3f + +static const value_string ext_op_types[] = { + { 0, "NULL" }, + { 1, "ASSOC" }, + { 2, "CERT" }, + { 3, "COOK" }, + { 4, "AUTO" }, + { 5, "TAI" }, + { 6, "SIGN" }, + { 7, "IFF" }, + { 8, "GQ" }, + { 9, "MV" }, + { 0, NULL} +}; + +#define NTPCTRL_R_MASK 0x80 + +#define ctrl_r_types ext_r_types + +#define NTPCTRL_ERROR_MASK 0x40 +#define NTPCTRL_MORE_MASK 0x20 +#define NTPCTRL_OP_MASK 0x1f + +static const value_string ctrl_op_types[] = { + { 0, "UNSPEC" }, + { 1, "READSTAT" }, + { 2, "READVAR" }, + { 3, "WRITEVAR" }, + { 4, "READCLOCK" }, + { 5, "WRITECLOCK" }, + { 6, "SETTRAP" }, + { 7, "ASYNCMSG" }, + { 31, "UNSETTRAP" }, + { 0, NULL} +}; + +#define NTPPRIV_R_MASK 0x80 + +#define priv_r_types ext_r_types + +#define NTPPRIV_MORE_MASK 0x40 + +#define NTPPRIV_AUTH_MASK 0x80 +#define NTPPRIV_SEQ_MASK 0x7f + +static const value_string priv_impl_types[] = { + { 0, "UNIV" }, + { 2, "XNTPD_OLD (pre-IPv6)" }, + { 3, "XNTPD" }, + { 0, NULL} +}; + +static const value_string priv_rc_types[] = { + { 0, "PEER_LIST" }, + { 1, "PEER_LIST_SUM" }, + { 2, "PEER_INFO" }, + { 3, "PEER_STATS" }, + { 4, "SYS_INFO" }, + { 5, "SYS_STATS" }, + { 6, "IO_STATS" }, + { 7, "MEM_STATS" }, + { 8, "LOOP_INFO" }, + { 9, "TIMER_STATS" }, + { 10, "CONFIG" }, + { 11, "UNCONFIG" }, + { 12, "SET_SYS_FLAG" }, + { 13, "CLR_SYS_FLAG" }, + { 16, "GET_RESTRICT" }, + { 17, "RESADDFLAGS" }, + { 18, "RESSUBFLAGS" }, + { 19, "UNRESTRICT" }, + { 20, "MON_GETLIST" }, + { 21, "RESET_STATS" }, + { 22, "RESET_PEER" }, + { 23, "REREAD_KEYS" }, + { 26, "TRUSTKEY" }, + { 27, "UNTRUSTKEY" }, + { 28, "AUTHINFO" }, + { 29, "TRAPS" }, + { 30, "ADD_TRAP" }, + { 31, "CLR_TRAP" }, + { 32, "REQUEST_KEY" }, + { 33, "CONTROL_KEY" }, + { 34, "GET_CTLSTATS" }, + { 36, "GET_CLOCKINFO" }, + { 37, "SET_CLKFUDGE" }, + { 38, "GET_KERNEL" }, + { 39, "GET_CLKBUGINFO" }, + { 42, "MON_GETLIST_1" }, + { 43, "HOSTNAME_ASSOCID" }, + { 0, NULL} +}; + static int proto_ntp = -1; + static int hf_ntp_flags = -1; static int hf_ntp_flags_li = -1; static int hf_ntp_flags_vn = -1; @@ -204,8 +308,46 @@ static int hf_ntp_xmt = -1; static int hf_ntp_keyid = -1; static int hf_ntp_mac = -1; +static int hf_ntp_ext = -1; +static int hf_ntp_ext_flags = -1; +static int hf_ntp_ext_flags_r = -1; +static int hf_ntp_ext_flags_error = -1; +static int hf_ntp_ext_flags_vn = -1; +static int hf_ntp_ext_op = -1; +static int hf_ntp_ext_len = -1; +static int hf_ntp_ext_associd = -1; +static int hf_ntp_ext_tstamp = -1; +static int hf_ntp_ext_fstamp = -1; +static int hf_ntp_ext_vallen = -1; +static int hf_ntp_ext_val = -1; +static int hf_ntp_ext_siglen = -1; +static int hf_ntp_ext_sig = -1; + +static int hf_ntpctrl_flags2 = -1; +static int hf_ntpctrl_flags2_r = -1; +static int hf_ntpctrl_flags2_error = -1; +static int hf_ntpctrl_flags2_more = -1; +static int hf_ntpctrl_flags2_opcode = -1; + +static int hf_ntppriv_flags_r = -1; +static int hf_ntppriv_flags_more = -1; +static int hf_ntppriv_auth_seq = -1; +static int hf_ntppriv_auth = -1; +static int hf_ntppriv_seq = -1; +static int hf_ntppriv_impl = -1; +static int hf_ntppriv_reqcode = -1; + static gint ett_ntp = -1; static gint ett_ntp_flags = -1; +static gint ett_ntp_ext = -1; +static gint ett_ntp_ext_flags = -1; +static gint ett_ntpctrl_flags2 = -1; +static gint ett_ntppriv_auth_seq = -1; + +static void dissect_ntp_std(tvbuff_t *, proto_tree *, guint8); +static void dissect_ntp_ctrl(tvbuff_t *, proto_tree *, guint8); +static void dissect_ntp_priv(tvbuff_t *, proto_tree *, guint8); +static void dissect_ntp_ext(tvbuff_t *, proto_tree *, guint *); /* ntp_fmt_ts - converts NTP timestamp to human readable string. * reftime - 64bit timestamp (IN) @@ -248,9 +390,51 @@ ntp_fmt_ts(const guint8 *reftime, char* static void dissect_ntp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - proto_tree *ntp_tree, *flags_tree; - proto_item *ti, *tf; + proto_tree *ntp_tree; + proto_item *ti; guint8 flags; + char *infostr; + void (*dissector)(tvbuff_t *, proto_item *, guint8); + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "NTP"); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + flags = tvb_get_guint8(tvb, 0); + switch (flags & NTP_MODE_MASK) { + default: + infostr = "NTP"; + dissector = dissect_ntp_std; + break; + case NTP_MODE_CTRL: + infostr = "NTP control"; + dissector = dissect_ntp_ctrl; + break; + case NTP_MODE_PRIV: + infostr = "NTP private"; + dissector = dissect_ntp_priv; + break; + } + + if (check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, infostr); + + if (tree) { + /* Adding NTP item and subtree */ + ti = proto_tree_add_item(tree, proto_ntp, tvb, 0, -1, FALSE); + ntp_tree = proto_item_add_subtree(ti, ett_ntp); + + (*dissector)(tvb, ntp_tree, flags); + } +} + +static void +dissect_ntp_std(tvbuff_t *tvb, proto_tree *ntp_tree, guint8 flags) +{ + proto_tree *flags_tree; + proto_item *tf; guint8 stratum; guint8 ppoll; gint8 precision; @@ -264,19 +448,8 @@ dissect_ntp(tvbuff_t *tvb, packet_info * const guint8 *xmt; gchar buff[NTP_TS_SIZE]; int i; + guint macofs; - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "NTP"); - - if (check_col(pinfo->cinfo, COL_INFO)) - col_set_str(pinfo->cinfo, COL_INFO, "NTP"); - - if (tree) { - /* Adding NTP item and subtree */ - ti = proto_tree_add_item(tree, proto_ntp, tvb, 0, -1, FALSE); - ntp_tree = proto_item_add_subtree(ti, ett_ntp); - - flags = tvb_get_guint8(tvb, 0); tf = proto_tree_add_uint(ntp_tree, hf_ntp_flags, tvb, 0, 1, flags); @@ -412,20 +585,161 @@ dissect_ntp(tvbuff_t *tvb, packet_info * "Transmit Time Stamp: %s", ntp_fmt_ts(xmt, buff)); + macofs = 48; + while (tvb_reported_length_remaining(tvb, macofs) > 20) + dissect_ntp_ext(tvb, ntp_tree, &macofs); + /* When the NTP authentication scheme is implemented, the * Key Identifier and Message Digest fields contain the * message authentication code (MAC) information defined in * Appendix C of RFC-1305. Will print this as hex code for now. */ - if ( tvb_reported_length_remaining(tvb, 48) >= 4 ) - proto_tree_add_item(ntp_tree, hf_ntp_keyid, tvb, 48, 4, + if ( tvb_reported_length_remaining(tvb, macofs) >= 4 ) + proto_tree_add_item(ntp_tree, hf_ntp_keyid, tvb, macofs, 4, FALSE); - if ( tvb_reported_length_remaining(tvb, 52) > 0 ) - proto_tree_add_item(ntp_tree, hf_ntp_mac, tvb, 52, - tvb_reported_length_remaining(tvb, 52), + if ( tvb_reported_length_remaining(tvb, macofs + 4) > 0 ) + proto_tree_add_item(ntp_tree, hf_ntp_mac, tvb, macofs + 4, + -1, FALSE); +} +static void +dissect_ntp_ext(tvbuff_t *tvb, proto_tree *ntp_tree, guint *pos) +{ + proto_tree *ext_tree, *flags_tree; + proto_item *tf; + guint16 extlen; + guint8 flags, op; + guint32 help32, vallen, siglen; + guint sigpos; + guint p = *pos; + + extlen = tvb_get_ntohs(tvb, p+2); + if (extlen < 8 || extlen % 8) { + /* XXX force an error */ + *pos += tvb_reported_length_remaining(tvb, p); + return; } + *pos += extlen; + + if (p != 48) { + /* + * XXX can have any number of extension blocks, + * don't know how to deal with this in ethereal, + * so just decode the first. + */ + return; + } + + tf = proto_tree_add_item(ntp_tree, hf_ntp_ext, tvb, p, extlen, FALSE); + ext_tree = proto_item_add_subtree(tf, ett_ntp_ext); + + flags = tvb_get_guint8(tvb, p); + tf = proto_tree_add_uint(ext_tree, hf_ntp_ext_flags, tvb, p, 1, + flags); + flags_tree = proto_item_add_subtree(tf, ett_ntp_ext_flags); + proto_tree_add_uint(flags_tree, hf_ntp_ext_flags_r, tvb, p, 1, flags); + proto_tree_add_uint(flags_tree, hf_ntp_ext_flags_error, tvb, p, 1, + flags); + proto_tree_add_uint(flags_tree, hf_ntp_ext_flags_vn, tvb, p, 1, + flags); + + op = tvb_get_guint8(tvb, p+1); + proto_tree_add_uint(ext_tree, hf_ntp_ext_op, tvb, p+1, 1, op); + + proto_tree_add_uint(ext_tree, hf_ntp_ext_len, tvb, p+2, 2, extlen); + + if ((flags & NTP_EXT_VN_MASK) != 2) { + /* don't care about autokey v1 */ + return; + } + + help32 = tvb_get_ntohl(tvb, p+4); + proto_tree_add_uint(ext_tree, hf_ntp_ext_associd, tvb, p+4, 4, help32); + + if (extlen < 20) + return; + + help32 = tvb_get_ntohl(tvb, p+8); + proto_tree_add_uint(ext_tree, hf_ntp_ext_tstamp, tvb, p+8, 4, help32); + help32 = tvb_get_ntohl(tvb, p+12); + proto_tree_add_uint(ext_tree, hf_ntp_ext_fstamp, tvb, p+12, 4, help32); + /* XXX fstamp can be server flags */ + + vallen = tvb_get_ntohl(tvb, p+16); + proto_tree_add_uint(ext_tree, hf_ntp_ext_vallen, tvb, p+16, 4, vallen); + if (vallen > 0) + proto_tree_add_item(ext_tree, hf_ntp_ext_val, tvb, p+20, vallen, + FALSE); + + sigpos = p+20 + ((vallen + 3) & (-4)); + if (sigpos > p + extlen - 4) + return; + siglen = tvb_get_ntohl(tvb, sigpos); + proto_tree_add_uint(ext_tree, hf_ntp_ext_siglen, tvb, sigpos, 4, siglen); + if (siglen > 0) + proto_tree_add_item(ext_tree, hf_ntp_ext_sig, tvb, + sigpos + 4, siglen, FALSE); +} + +static void +dissect_ntp_ctrl(tvbuff_t *tvb, proto_tree *ntp_tree, guint8 flags) +{ + proto_tree *flags_tree; + proto_item *tf; + guint8 flags2; + + tf = proto_tree_add_uint(ntp_tree, hf_ntp_flags, tvb, 0, 1, flags); + + /* Adding flag subtree and items */ + flags_tree = proto_item_add_subtree(tf, ett_ntp_flags); + proto_tree_add_uint(flags_tree, hf_ntp_flags_li, tvb, 0, 1, flags); + proto_tree_add_uint(flags_tree, hf_ntp_flags_vn, tvb, 0, 1, flags); + proto_tree_add_uint(flags_tree, hf_ntp_flags_mode, tvb, 0, 1, flags); + + flags2 = tvb_get_guint8(tvb, 1); + tf = proto_tree_add_uint(ntp_tree, hf_ntpctrl_flags2, tvb, 1, 1, + flags2); + flags_tree = proto_item_add_subtree(tf, ett_ntpctrl_flags2); + proto_tree_add_uint(flags_tree, hf_ntpctrl_flags2_r, tvb, 1, 1, + flags2); + proto_tree_add_uint(flags_tree, hf_ntpctrl_flags2_error, tvb, 1, 1, + flags2); + proto_tree_add_uint(flags_tree, hf_ntpctrl_flags2_more, tvb, 1, 1, + flags2); + proto_tree_add_uint(flags_tree, hf_ntpctrl_flags2_opcode, tvb, 1, 1, + flags2); +} + +static void +dissect_ntp_priv(tvbuff_t *tvb, proto_tree *ntp_tree, guint8 flags) +{ + proto_tree *flags_tree; + proto_item *tf; + guint8 auth_seq, impl, reqcode; + + tf = proto_tree_add_uint(ntp_tree, hf_ntp_flags, tvb, 0, 1, flags); + + /* Adding flag subtree and items */ + flags_tree = proto_item_add_subtree(tf, ett_ntp_flags); + proto_tree_add_uint(flags_tree, hf_ntppriv_flags_r, tvb, 0, 1, flags); + proto_tree_add_uint(flags_tree, hf_ntppriv_flags_more, tvb, 0, 1, + flags); + proto_tree_add_uint(flags_tree, hf_ntp_flags_vn, tvb, 0, 1, flags); + proto_tree_add_uint(flags_tree, hf_ntp_flags_mode, tvb, 0, 1, flags); + + auth_seq = tvb_get_guint8(tvb, 1); + tf = proto_tree_add_uint(ntp_tree, hf_ntppriv_auth_seq, tvb, 1, 1, + auth_seq); + flags_tree = proto_item_add_subtree(tf, ett_ntppriv_auth_seq); + proto_tree_add_uint(flags_tree, hf_ntppriv_auth, tvb, 1, 1, auth_seq); + proto_tree_add_uint(flags_tree, hf_ntppriv_seq, tvb, 1, 1, auth_seq); + + impl = tvb_get_guint8(tvb, 2); + proto_tree_add_uint(ntp_tree, hf_ntppriv_impl, tvb, 2, 1, impl); + + reqcode = tvb_get_guint8(tvb, 3); + proto_tree_add_uint(ntp_tree, hf_ntppriv_reqcode, tvb, 3, 1, reqcode); } void @@ -480,10 +794,95 @@ proto_register_ntp(void) { &hf_ntp_mac, { "Message Authentication Code", "ntp.mac", FT_BYTES, BASE_HEX, NULL, 0, "Message Authentication Code", HFILL }}, + + { &hf_ntp_ext, { + "Extension", "ntp.ext", FT_NONE, BASE_NONE, + NULL, 0, "Extension", HFILL }}, + { &hf_ntp_ext_flags, { + "Flags", "ntp.ext.flags", FT_UINT8, BASE_HEX, + NULL, 0, "Flags (Response/Error/Version)", HFILL }}, + { &hf_ntp_ext_flags_r, { + "Response bit", "ntp.ext.flags.r", FT_UINT8, BASE_DEC, + VALS(ext_r_types), NTP_EXT_R_MASK, "Response bit", HFILL }}, + { &hf_ntp_ext_flags_error, { + "Error bit", "ntp.ext.flags.error", FT_UINT8, BASE_DEC, + NULL, NTP_EXT_ERROR_MASK, "Error bit", HFILL }}, + { &hf_ntp_ext_flags_vn, { + "Version", "ntp.ext.flags.vn", FT_UINT8, BASE_DEC, + NULL, NTP_EXT_VN_MASK, "Version", HFILL }}, + { &hf_ntp_ext_op, { + "Opcode", "ntp.ext.op", FT_UINT8, BASE_DEC, + VALS(ext_op_types), 0, "Opcode", HFILL }}, + { &hf_ntp_ext_len, { + "Extension length", "ntp.ext.len", FT_UINT16, BASE_DEC, + NULL, 0, "Extension length", HFILL }}, + { &hf_ntp_ext_associd, { + "Association ID", "ntp.ext.associd", FT_UINT32, BASE_DEC, + NULL, 0, "Association ID", HFILL }}, + { &hf_ntp_ext_tstamp, { + "Timestamp", "ntp.ext.tstamp", FT_UINT32, BASE_HEX, + NULL, 0, "Timestamp", HFILL }}, + { &hf_ntp_ext_fstamp, { + "File Timestamp", "ntp.ext.fstamp", FT_UINT32, BASE_HEX, + NULL, 0, "File Timestamp", HFILL }}, + { &hf_ntp_ext_vallen, { + "Value length", "ntp.ext.vallen", FT_UINT32, BASE_DEC, + NULL, 0, "Value length", HFILL }}, + { &hf_ntp_ext_val, { + "Value", "ntp.ext.val", FT_BYTES, BASE_HEX, + NULL, 0, "Value", HFILL }}, + { &hf_ntp_ext_siglen, { + "Signature length", "ntp.ext.siglen", FT_UINT32, BASE_DEC, + NULL, 0, "Signature length", HFILL }}, + { &hf_ntp_ext_sig, { + "Signature", "ntp.ext.sig", FT_BYTES, BASE_HEX, + NULL, 0, "Signature", HFILL }}, + + { &hf_ntpctrl_flags2, { + "Flags 2", "ntpctrl.flags2", FT_UINT8, BASE_HEX, + NULL, 0, "Flags (Response/Error/More/Opcode)", HFILL }}, + { &hf_ntpctrl_flags2_r, { + "Response bit", "ntpctrl.flags2.r", FT_UINT8, BASE_DEC, + VALS(ctrl_r_types), NTPCTRL_R_MASK, "Response bit", HFILL }}, + { &hf_ntpctrl_flags2_error, { + "Error bit", "ntpctrl.flags2.error", FT_UINT8, BASE_DEC, + NULL, NTPCTRL_ERROR_MASK, "Error bit", HFILL }}, + { &hf_ntpctrl_flags2_more, { + "More bit", "ntpctrl.flags2.more", FT_UINT8, BASE_DEC, + NULL, NTPCTRL_MORE_MASK, "More bit", HFILL }}, + { &hf_ntpctrl_flags2_opcode, { + "Opcode", "ntpctrl.flags2.opcode", FT_UINT8, BASE_DEC, + VALS(ctrl_op_types), NTPCTRL_OP_MASK, "Opcode", HFILL }}, + + { &hf_ntppriv_flags_r, { + "Response bit", "ntppriv.flags.r", FT_UINT8, BASE_DEC, + VALS(priv_r_types), NTPPRIV_R_MASK, "Response bit", HFILL }}, + { &hf_ntppriv_flags_more, { + "More bit", "ntppriv.flags.more", FT_UINT8, BASE_DEC, + NULL, NTPPRIV_MORE_MASK, "More bit", HFILL }}, + { &hf_ntppriv_auth_seq, { + "Auth, sequence", "ntppriv.auth_seq", FT_UINT8, BASE_DEC, + NULL, 0, "Auth bit, sequence number", HFILL }}, + { &hf_ntppriv_auth, { + "Auth bit", "ntppriv.auth", FT_UINT8, BASE_DEC, + NULL, NTPPRIV_AUTH_MASK, "Auth bit", HFILL }}, + { &hf_ntppriv_seq, { + "Sequence number", "ntppriv.seq", FT_UINT8, BASE_DEC, + NULL, NTPPRIV_SEQ_MASK, "Sequence number", HFILL }}, + { &hf_ntppriv_impl, { + "Implementation", "ntppriv.impl", FT_UINT8, BASE_DEC, + VALS(priv_impl_types), 0, "Implementation", HFILL }}, + { &hf_ntppriv_reqcode, { + "Request code", "ntppriv.reqcode", FT_UINT8, BASE_DEC, + VALS(priv_rc_types), 0, "Request code", HFILL }}, }; static gint *ett[] = { &ett_ntp, &ett_ntp_flags, + &ett_ntp_ext, + &ett_ntp_ext_flags, + &ett_ntpctrl_flags2, + &ett_ntppriv_auth_seq, }; proto_ntp = proto_register_protocol("Network Time Protocol", "NTP",
- Follow-Ups:
- Re: [Ethereal-dev] improved NTP decoding
- From: Guy Harris
- Re: [Ethereal-dev] improved NTP decoding
- Prev by Date: Re: [Ethereal-dev] timestamp resolution of various OSes ...
- Next by Date: [Ethereal-dev] specific packet decoding/altering question
- Previous by thread: Re: [Ethereal-dev] timestamp resolution of various OSes ...
- Next by thread: Re: [Ethereal-dev] improved NTP decoding
- Index(es):