//-------------------------------------------------------------------- // NtpParser - implementation // Copyright (C) Microsoft Corporation, 2000 // // Created by: Louis Thomas (louisth), 2-29-00 // Based upon the parser created by kumarp, 23-June-1999 // // NTP parser for NetMon // #include #include #include #include #include #include #include "..\lib\EndianSwap.inl" //#define MODULEPRIVATE static // so statics show up in VC #define MODULEPRIVATE // statics don't show up in ntsd either! #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) //-------------------------------------------------------------------- // Forward declarations VOID WINAPIV Ntp_FormatSummary(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatNtpTime(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatStratum(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatPollInterval(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatPrecision(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatRootDelay(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatRootDispersion(LPPROPERTYINST pPropertyInst); VOID WINAPIV Ntp_FormatRefId(LPPROPERTYINST pPropertyInst); //-------------------------------------------------------------------- // Property Value Labels // Leap Indicator LABELED_BYTE NtpLIVals[]={ {0xc0, NULL}, {0x00, "LI: no warning"}, {0x40, "LI: last minute has 61 seconds"}, {0x80, "LI: last minute has 59 seconds"}, {0xc0, "LI: clock not synchronized"}, }; SET NtpLISet={ARRAYSIZE(NtpLIVals), NtpLIVals}; // Version LABELED_BYTE NtpVersionVals[]={ {0x38, NULL}, {0x00, "Version: 0"}, {0x08, "Version: 1"}, {0x10, "Version: 2"}, {0x18, "Version: 3"}, {0x20, "Version: 4"}, {0x28, "Version: 5"}, {0x30, "Version: 6"}, {0x38, "Version: 7"}, }; SET NtpVersionSet={ARRAYSIZE(NtpVersionVals), NtpVersionVals}; // Mode LABELED_BYTE NtpModeVals[]={ {7, NULL}, {0, "Mode: reserved"}, {1, "Mode: symmetric active"}, {2, "Mode: symmetric passive"}, {3, "Mode: client"}, {4, "Mode: server"}, {5, "Mode: broadcast"}, {6, "Mode: reserved for NTP control message"}, {7, "Mode: reserved for private use"}, }; SET NtpModeSet={ARRAYSIZE(NtpModeVals), NtpModeVals}; enum { NTP_MODE_Reserved=0, NTP_MODE_SymmetricActive, NTP_MODE_SymmetricPassive, NTP_MODE_Client, NTP_MODE_Server, NTP_MODE_Broadcast, NTP_MODE_Control, NTP_MODE_Private, }; //-------------------------------------------------------------------- // property ordinals (These must be kept in sync with the contents of NtpPropertyTable) enum { Ntp_Summary=0, Ntp_LeapIndicator, Ntp_Version, Ntp_Mode, Ntp_Stratum, Ntp_PollInterval, Ntp_Precision, Ntp_RootDelay, Ntp_RootDispersion, Ntp_RefId, Ntp_ReferenceTimeStamp, Ntp_OriginateTimeStamp, Ntp_ReceiveTimeStamp, Ntp_TransmitTimeStamp }; // Properties PROPERTYINFO NtpPropertyTable[]={ { 0, 0, "Summary", "Summary of the NTP Packet", PROP_TYPE_SUMMARY, PROP_QUAL_NONE, NULL, 80, // max string size Ntp_FormatSummary }, { 0, 0, "LI", "Leap Indicator", PROP_TYPE_BYTE, PROP_QUAL_LABELED_BITFIELD, &NtpLISet, 80, FormatPropertyInstance }, { 0, 0, "Version", "NTP Version", PROP_TYPE_BYTE, PROP_QUAL_LABELED_BITFIELD, &NtpVersionSet, 80, FormatPropertyInstance }, { 0, 0, "Mode", "Mode", PROP_TYPE_BYTE, PROP_QUAL_LABELED_BITFIELD, &NtpModeSet, 80, FormatPropertyInstance }, { 0, 0, "Stratum", "Stratum", PROP_TYPE_BYTE, PROP_QUAL_NONE, NULL, 80, Ntp_FormatStratum }, { 0, 0, "Poll Interval", "Maximum interval between two successive messages", PROP_TYPE_BYTE, PROP_QUAL_NONE, NULL, 80, Ntp_FormatPollInterval }, { 0, 0, "Precision", "Precision of the local clock", PROP_TYPE_BYTE, PROP_QUAL_NONE, NULL, 80, Ntp_FormatPrecision }, { 0, 0, "Root Delay", "Total roundtrip delay to the primary reference source", PROP_TYPE_DWORD, PROP_QUAL_NONE, NULL, 80, Ntp_FormatRootDelay }, { 0, 0, "Root Dispersion", "Nominal error relative to the primary reference source", PROP_TYPE_DWORD, PROP_QUAL_NONE, NULL, 80, Ntp_FormatRootDispersion }, { 0, 0, "Reference Identifier", "Reference source identifier", PROP_TYPE_DWORD, PROP_QUAL_NONE, NULL, 80, Ntp_FormatRefId }, { 0, 0, "Reference Timestamp", "Time server was last synchronized", PROP_TYPE_LARGEINT, PROP_QUAL_NONE, NULL, 150, Ntp_FormatNtpTime }, { 0, 0, "Originate Timestamp", "Time at client when packet was transmitted", PROP_TYPE_LARGEINT, PROP_QUAL_NONE, NULL, 150, Ntp_FormatNtpTime }, { 0, 0, "Receive Timestamp", "Time at server when packet was received", PROP_TYPE_LARGEINT, PROP_QUAL_NONE, NULL, 150, Ntp_FormatNtpTime }, { 0, 0, "Transmit Timestamp", "Time at server when packet was transmitted", PROP_TYPE_LARGEINT, PROP_QUAL_NONE, NULL, 150, Ntp_FormatNtpTime }, }; //#################################################################### //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatSummary(LPPROPERTYINST pPropertyInst) { BYTE bMode=(*pPropertyInst->lpByte)&7; switch (bMode) { case NTP_MODE_Client: lstrcpy(pPropertyInst->szPropertyText, "Client request"); break; case NTP_MODE_Server: lstrcpy(pPropertyInst->szPropertyText, "Server response"); break; case NTP_MODE_SymmetricActive: lstrcpy(pPropertyInst->szPropertyText, "Active request"); break; case NTP_MODE_SymmetricPassive: lstrcpy(pPropertyInst->szPropertyText, "Passive reponse"); break; case NTP_MODE_Broadcast: lstrcpy(pPropertyInst->szPropertyText, "Time broadcast"); break; default: lstrcpy(pPropertyInst->szPropertyText, "Other NTP packet"); break; } } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatStratum(LPPROPERTYINST pPropertyInst) { unsigned __int8 nStratum=(*pPropertyInst->lpByte); char * szMeaning; if (0==nStratum) { szMeaning="unspecified or unavailable"; } else if (1==nStratum) { szMeaning="primary reference (syncd by radio clock)"; } else if (nStratum<16) { szMeaning="secondary reference (syncd by NTP)"; } else { szMeaning="reserved"; } wsprintf(pPropertyInst->szPropertyText, "Stratum: 0x%02X = %u = %s", nStratum, nStratum, szMeaning); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatPollInterval(LPPROPERTYINST pPropertyInst) { char * szMeaning; char szBuf[30]; signed __int8 nPollInterval=(*pPropertyInst->lpByte); if (0==nPollInterval) { szMeaning="unspecified"; } else if (nPollInterval<4 || nPollInterval>14) { szMeaning="out of valid range"; } else { wsprintf(szBuf, "%ds", 1<szPropertyText, "Poll Interval: 0x%02X = %d = %s", (unsigned __int8)nPollInterval, nPollInterval, szMeaning); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatPrecision(LPPROPERTYINST pPropertyInst) { char * szMeaning; char szBuf[30]; signed __int8 nPrecision=(*pPropertyInst->lpByte); if (0==nPrecision) { szMeaning="unspecified"; } else if (nPrecision>-2 || nPrecision<-31) { szMeaning="out of valid range"; } else { szMeaning=szBuf; char * szUnit="s"; double dTickInterval=1.0/(1<<(-nPrecision)); if (dTickInterval<1) { dTickInterval*=1000; szUnit="ms"; } if (dTickInterval<1) { dTickInterval*=1000; szUnit="µs"; } if (dTickInterval<1) { dTickInterval*=1000; szUnit="ns"; } sprintf(szBuf, "%g%s per tick", dTickInterval, szUnit); } wsprintf(pPropertyInst->szPropertyText, "Precision: 0x%02X = %d = %s", (unsigned __int8)nPrecision, nPrecision, szMeaning); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatRootDelay(LPPROPERTYINST pPropertyInst) { char * szMeaning; char szBuf[30]; DWORD dwRootDelay=EndianSwap((unsigned __int32)*pPropertyInst->lpDword); if (0==dwRootDelay) { szMeaning="unspecified"; } else { szMeaning=szBuf; sprintf(szBuf, "%gs", ((double)((signed __int32)dwRootDelay))/0x00010000); } wsprintf(pPropertyInst->szPropertyText, "Root Delay: 0x%04X.%04Xs = %s", dwRootDelay>>16, dwRootDelay&0x0000FFFF, szMeaning); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatRootDispersion(LPPROPERTYINST pPropertyInst) { char * szMeaning; char szBuf[30]; DWORD dwRootDispersion=EndianSwap((unsigned __int32)*pPropertyInst->lpDword); if (0==dwRootDispersion) { szMeaning="unspecified"; } else { szMeaning=szBuf; sprintf(szBuf, "%gs", ((double)((signed __int32)dwRootDispersion))/0x00010000); } wsprintf(pPropertyInst->szPropertyText, "Root Dispersion: 0x%04X.%04Xs = %s", dwRootDispersion>>16, dwRootDispersion&0x0000FFFF, szMeaning); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatRefId(LPPROPERTYINST pPropertyInst) { char * szMeaning; char szBuf[30]; DWORD dwRefID=EndianSwap((unsigned __int32)*pPropertyInst->lpDword); unsigned __int8 nStratum=*(pPropertyInst->lpByte-11); unsigned int nVersion=*(pPropertyInst->lpByte-12); nVersion&=0x38; nVersion>>=3; if (0==dwRefID) { szMeaning="unspecified"; } else if (0==nStratum || 1==nStratum) { szMeaning=szBuf; char szId[5]; szId[0]=pPropertyInst->lpByte[0]; szId[1]=pPropertyInst->lpByte[1]; szId[2]=pPropertyInst->lpByte[2]; szId[3]=pPropertyInst->lpByte[3]; szId[4]='\0'; sprintf(szBuf, "source name: \"%s\"", szId); } else if (nVersion<4) { szMeaning=szBuf; sprintf(szBuf, "source IP: %u.%u.%u.%u", pPropertyInst->lpByte[0], pPropertyInst->lpByte[1], pPropertyInst->lpByte[2], pPropertyInst->lpByte[3]); } else { szMeaning=szBuf; sprintf(szBuf, "last reference timestamp fraction: %gs", ((double)dwRefID)/(4294967296.0)); } wsprintf(pPropertyInst->szPropertyText, "Reference Identifier: 0x%08X = %s", dwRefID, szMeaning); } //-------------------------------------------------------------------- // conversion constants #define NTPTIMEOFFSET (0x014F373BFDE04000) #define FIVETOTHESEVETH (0x001312D) //-------------------------------------------------------------------- // convert from big-endian NTP-stye timestamp to little-endian NT-style timestamp unsigned __int64 NtTimeFromNtpTime(unsigned __int64 qwNtpTime) { //return (qwNtpTime*(10**7)/(2**32))+NTPTIMEOFFSET // ==> //return (qwNtpTime*(5**7)/(2**25))+NTPTIMEOFFSET // ==> //return ((qwNTPtime*FIVETOTHESEVETH)>>25)+NTPTIMEOFFSET; // ==> // Note: 'After' division, we round (instead of truncate) the result for better precision unsigned __int64 qwTemp; qwNtpTime=EndianSwap(qwNtpTime); qwTemp=((qwNtpTime&0x00000000FFFFFFFF)*FIVETOTHESEVETH); qwTemp += qwTemp&0x0000000001000000; //rounding step: if 25th bit is set, round up return (qwTemp>>25) + (((qwNtpTime>>32)*FIVETOTHESEVETH)<<7) + NTPTIMEOFFSET; } //-------------------------------------------------------------------- void FormatNtTimeStr(unsigned __int64 qwNtTime, char * szTime) { DWORD dwNanoSecs, dwSecs, dwMins, dwHours, dwDays; dwNanoSecs=(DWORD)(qwNtTime%10000000); qwNtTime/=10000000; dwSecs=(DWORD)(qwNtTime%60); qwNtTime/=60; dwMins=(DWORD)(qwNtTime%60); qwNtTime/=60; dwHours=(DWORD)(qwNtTime%24); dwDays=(DWORD)(qwNtTime/24); wsprintf(szTime, "%u %02u:%02u:%02u.%07us", dwDays, dwHours, dwMins, dwSecs, dwNanoSecs); } //-------------------------------------------------------------------- VOID WINAPIV Ntp_FormatNtpTime(LPPROPERTYINST pPropertyInst) { LARGE_INTEGER liNtpTime; unsigned __int64 qwNtTime; unsigned __int64 qwNtTimeEpoch; char szTime[64]; char szTimeEpoch[64]; liNtpTime=*pPropertyInst->lpLargeInt; qwNtTime=NtTimeFromNtpTime((((unsigned __int64) liNtpTime.HighPart) << 32) | liNtpTime.LowPart); if (liNtpTime.HighPart || liNtpTime.LowPart) { FormatNtTimeStr(qwNtTime, szTime); } else { lstrcpy(szTime, "(not specified)"); } wsprintf(szTimeEpoch, " -- %I64d00ns", ((((unsigned __int64)liNtpTime.HighPart) << 32) | liNtpTime.LowPart));; wsprintf(pPropertyInst->szPropertyText, "%s: 0x%08X.%08Xs %s = %s", pPropertyInst->lpPropertyInfo->Label, EndianSwap((unsigned __int32)liNtpTime.LowPart), EndianSwap((unsigned __int32)liNtpTime.HighPart), szTimeEpoch, szTime); } //#################################################################### //-------------------------------------------------------------------- // Create our property database and handoff sets. void BHAPI Ntp_Register(HPROTOCOL hNtp) { unsigned int nIndex; // tell netmon to make reserve some space for our property table CreatePropertyDatabase(hNtp, ARRAYSIZE(NtpPropertyTable)); // add our properties to netmon's database for(nIndex=0; nIndex0) { // and call the formatter for each ((FORMAT)(p->lpPropertyInfo->InstanceData))(p); p++; } return NMERR_SUCCESS; } //#################################################################### //-------------------------------------------------------------------- // AutoInstall - return all of the information neede to install us PPF_PARSERDLLINFO WINAPI ParserAutoInstallInfo() { PPF_PARSERDLLINFO pParserDllInfo; PPF_PARSERINFO pParserInfo; DWORD NumProtocols; DWORD NumHandoffs; PPF_HANDOFFSET pHandoffSet; PPF_HANDOFFENTRY pHandoffEntry; // Allocate memory for parser info: NumProtocols=1; pParserDllInfo=(PPF_PARSERDLLINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PF_PARSERDLLINFO) + NumProtocols * sizeof(PF_PARSERINFO)); if(pParserDllInfo==NULL) { return NULL; } // fill in the parser DLL info pParserDllInfo->nParsers=NumProtocols; // fill in the individual parser infos... // Ntp ============================================================== pParserInfo=&(pParserDllInfo->ParserInfo[0]); wsprintf(pParserInfo->szProtocolName, "NTP"); wsprintf(pParserInfo->szComment, "Network Time Protocol"); wsprintf(pParserInfo->szHelpFile, ""); // the incoming handoff set ---------------------------------------------- // allocate NumHandoffs = 1; pHandoffSet = (PPF_HANDOFFSET)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( PF_HANDOFFSET ) + NumHandoffs * sizeof( PF_HANDOFFENTRY) ); if( pHandoffSet == NULL ) { // just return early return pParserDllInfo; } // fill in the incoming handoff set pParserInfo->pWhoHandsOffToMe = pHandoffSet; pHandoffSet->nEntries = NumHandoffs; pHandoffEntry = &(pHandoffSet->Entry[0]); wsprintf( pHandoffEntry->szIniFile, "TCPIP.INI" ); wsprintf( pHandoffEntry->szIniSection, "UDP_HandoffSet" ); wsprintf( pHandoffEntry->szProtocol, "NTP" ); pHandoffEntry->dwHandOffValue = 123; pHandoffEntry->ValueFormatBase = HANDOFF_VALUE_FORMAT_BASE_DECIMAL; return pParserDllInfo; } //-------------------------------------------------------------------- // Tell netmon about our entry points. extern "C" BOOL WINAPI DllMain(HANDLE hInstance, ULONG Command, LPVOID Reserved) { //MessageBox(NULL, "DLLEntry", "NTP ha ha", MB_OK); static HPROTOCOL hNtp=NULL; static unsigned int nAttached=0; // what type of call is this switch(Command) { case DLL_PROCESS_ATTACH: // are we loading for the first time? if (nAttached==0) { // the first time in we need to tell netmon // about ourselves ENTRYPOINTS NtpEntryPoints={ Ntp_Register, Ntp_Deregister, Ntp_RecognizeFrame, Ntp_AttachProperties, Ntp_FormatProperties }; hNtp=CreateProtocol("NTP", &NtpEntryPoints, ENTRYPOINTS_SIZE); } nAttached++; break; case DLL_PROCESS_DETACH: nAttached--; // are we detaching our last instance? if (nAttached==0) { // last guy out needs to clean up DestroyProtocol(hNtp); } break; } // Netmon parsers ALWAYS return TRUE. return TRUE; }