ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

tracert.c
Go to the documentation of this file.
00001  /*
00002  * PROJECT:     ReactOS trace route utility
00003  * LICENSE:     GPL - See COPYING in the top level directory
00004  * FILE:        base/applications/network/tracert.c
00005  * PURPOSE:     Trace network paths through networks
00006  * COPYRIGHT:   Copyright 2006 - 2007 Ged Murphy <gedmurphy@reactos.org>
00007  *
00008  */
00009 
00010 #include "tracert.h"
00011 
00012 //#define TRACERT_DBG
00013 
00014 CHAR cHostname[256];            // target hostname
00015 CHAR cDestIP[18];               // target IP
00016 
00017 
00018 static VOID
00019 DebugPrint(LPTSTR lpString, ...)
00020 {
00021 #ifdef TRACERT_DBG
00022     va_list args;
00023     va_start(args, lpString);
00024     _vtprintf(lpString, args);
00025     va_end(args);
00026 #else
00027     UNREFERENCED_PARAMETER(lpString);
00028 #endif
00029 }
00030 
00031 
00032 static VOID
00033 Usage(VOID)
00034 {
00035     _tprintf(_T("\nUsage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name\n\n"
00036                 "Options:\n"
00037                 "    -d                 Do not resolve addresses to hostnames.\n"
00038                 "    -h maximum_hops    Maximum number of hops to search for target.\n"
00039                 "    -j host-list       Loose source route along host-list.\n"
00040                 "    -w timeout         Wait timeout milliseconds for each reply.\n\n"));
00041 
00042     _tprintf(_T("NOTES\n-----\n"
00043            "- Setting TTL values is not currently supported in ReactOS, so the trace will\n"
00044            "  jump straight to the destination. This feature will be implemented soon.\n"
00045            "- Host info is not currently available in ReactOS and will fail with strange\n"
00046            "  results. Use -d to force it not to resolve IP's.\n"
00047            "- For testing purposes, all should work as normal in a Windows environment\n\n"));
00048 }
00049 
00050 
00051 static BOOL
00052 ParseCmdline(int argc,
00053              LPCTSTR argv[],
00054              PAPPINFO pInfo)
00055 {
00056     INT i;
00057 
00058     if (argc < 2)
00059     {
00060        Usage();
00061        return FALSE;
00062     }
00063     else
00064     {
00065         for (i = 1; i < argc; i++)
00066         {
00067             if (argv[i][0] == _T('-'))
00068             {
00069                 switch (argv[i][1])
00070                 {
00071                     case _T('d'):
00072                         pInfo->bResolveAddresses = FALSE;
00073                     break;
00074 
00075                     case _T('h'):
00076                         _stscanf(argv[i+1], _T("%d"), &pInfo->iMaxHops);
00077                     break;
00078 
00079                     case _T('j'):
00080                         _tprintf(_T("-j is not yet implemented.\n"));
00081                     break;
00082 
00083                     case _T('w'):
00084                         _stscanf(argv[i+1], _T("%d"), &pInfo->iTimeOut);
00085                     break;
00086 
00087                     default:
00088                     {
00089                         _tprintf(_T("%s is not a valid option.\n"), argv[i]);
00090                         Usage();
00091                         return FALSE;
00092                     }
00093                 }
00094             }
00095             else
00096                /* copy target address */
00097                _tcsncpy(cHostname, argv[i], 255);
00098         }
00099     }
00100 
00101     return TRUE;
00102 }
00103 
00104 
00105 static WORD
00106 CheckSum(PUSHORT data,
00107          UINT size)
00108 {
00109     DWORD dwSum = 0;
00110 
00111     while (size > 1)
00112     {
00113         dwSum += *data++;
00114         size -= sizeof(USHORT);
00115     }
00116 
00117     if (size)
00118         dwSum += *(UCHAR*)data;
00119 
00120     dwSum = (dwSum >> 16) + (dwSum & 0xFFFF);
00121     dwSum += (dwSum >> 16);
00122 
00123     return (USHORT)(~dwSum);
00124 }
00125 
00126 
00127 static VOID
00128 SetupTimingMethod(PAPPINFO pInfo)
00129 {
00130     LARGE_INTEGER PerformanceCounterFrequency;
00131 
00132     /* check if performance counters are available */
00133     pInfo->bUsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency);
00134 
00135     if (pInfo->bUsePerformanceCounter)
00136     {
00137         /* restrict execution to first processor on SMP systems */
00138         if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0)
00139             pInfo->bUsePerformanceCounter = FALSE;
00140 
00141         pInfo->TicksPerMs.QuadPart  = PerformanceCounterFrequency.QuadPart / 1000;
00142         pInfo->TicksPerUs.QuadPart  = PerformanceCounterFrequency.QuadPart / 1000000;
00143     }
00144     else
00145     {
00146         pInfo->TicksPerMs.QuadPart = 1;
00147         pInfo->TicksPerUs.QuadPart = 1;
00148     }
00149 }
00150 
00151 
00152 static BOOL
00153 ResolveHostname(PAPPINFO pInfo)
00154 {
00155     HOSTENT *hp;
00156     ULONG addr;
00157 
00158     ZeroMemory(&pInfo->dest, sizeof(pInfo->dest));
00159 
00160     /* if address is not a dotted decimal */
00161     if ((addr = inet_addr(cHostname))== INADDR_NONE)
00162     {
00163        if ((hp = gethostbyname(cHostname)) != 0)
00164        {
00165           //CopyMemory(&pInfo->dest.sin_addr, hp->h_addr, hp->h_length);
00166           pInfo->dest.sin_addr = *((struct in_addr *)hp->h_addr);
00167           pInfo->dest.sin_family = hp->h_addrtype;
00168        }
00169        else
00170        {
00171           _tprintf(_T("Unable to resolve target system name %s.\n"), cHostname);
00172           return FALSE;
00173        }
00174     }
00175     else
00176     {
00177         pInfo->dest.sin_addr.s_addr = addr;
00178         pInfo->dest.sin_family = AF_INET;
00179     }
00180 
00181     _tcscpy(cDestIP, inet_ntoa(pInfo->dest.sin_addr));
00182 
00183     return TRUE;
00184 }
00185 
00186 
00187 static LONGLONG
00188 GetTime(PAPPINFO pInfo)
00189 {
00190     LARGE_INTEGER Time;
00191 
00192     /* Get the system time using preformance counters if available */
00193     if (pInfo->bUsePerformanceCounter)
00194     {
00195         if (QueryPerformanceCounter(&Time))
00196         {
00197             return Time.QuadPart;
00198         }
00199     }
00200 
00201     /* otherwise fall back to GetTickCount */
00202     Time.u.LowPart = (DWORD)GetTickCount();
00203     Time.u.HighPart = 0;
00204 
00205     return (LONGLONG)Time.u.LowPart;
00206 }
00207 
00208 
00209 static BOOL
00210 SetTTL(SOCKET sock,
00211        INT iTTL)
00212 {
00213     if (setsockopt(sock,
00214                    IPPROTO_IP,
00215                    IP_TTL,
00216                    (const char *)&iTTL,
00217                    sizeof(iTTL)) == SOCKET_ERROR)
00218     {
00219        DebugPrint(_T("TTL setsockopt failed : %d. \n"), WSAGetLastError());
00220        return FALSE;
00221     }
00222 
00223     return TRUE;
00224 }
00225 
00226 
00227 static BOOL
00228 CreateSocket(PAPPINFO pInfo)
00229 {
00230     pInfo->icmpSock = WSASocket(AF_INET,
00231                                 SOCK_RAW,
00232                                 IPPROTO_ICMP,
00233                                 0,
00234                                 0,
00235                                 0);
00236 
00237     if (pInfo->icmpSock == INVALID_SOCKET)
00238     {
00239         INT err = WSAGetLastError();
00240         DebugPrint(_T("Could not create socket : %d.\n"), err);
00241 
00242         if (err == WSAEACCES)
00243         {
00244             _tprintf(_T("\n\nYou must have access to raw sockets (admin) to run this program!\n\n"));
00245         }
00246 
00247         return FALSE;
00248     }
00249 
00250     return TRUE;
00251 }
00252 
00253 
00254 static VOID
00255 PreparePacket(PAPPINFO pInfo,
00256               USHORT iSeqNum)
00257 {
00258     /* assemble ICMP echo request packet */
00259     pInfo->SendPacket->icmpheader.type     = ECHO_REQUEST;
00260     pInfo->SendPacket->icmpheader.code     = 0;
00261     pInfo->SendPacket->icmpheader.checksum = 0;
00262     pInfo->SendPacket->icmpheader.id       = (USHORT)GetCurrentProcessId();
00263     pInfo->SendPacket->icmpheader.seq      = htons((USHORT)iSeqNum);
00264 
00265     /* calculate checksum of packet */
00266     pInfo->SendPacket->icmpheader.checksum  = CheckSum((PUSHORT)&pInfo->SendPacket->icmpheader,
00267                                                        sizeof(ICMP_HEADER) + PACKET_SIZE);
00268 }
00269 
00270 
00271 static INT
00272 SendPacket(PAPPINFO pInfo)
00273 {
00274     INT iSockRet;
00275 
00276     DebugPrint(_T("\nsending packet of %d bytes... "), PACKET_SIZE);
00277 
00278     /* get time packet was sent */
00279     pInfo->lTimeStart = GetTime(pInfo);
00280 
00281     iSockRet = sendto(pInfo->icmpSock,              //socket
00282                       (char *)&pInfo->SendPacket->icmpheader,//buffer
00283                       sizeof(ICMP_HEADER) + PACKET_SIZE,//size of buffer
00284                       0,                            //flags
00285                       (SOCKADDR *)&pInfo->dest,     //destination
00286                       sizeof(pInfo->dest));         //address length
00287 
00288     if (iSockRet == SOCKET_ERROR)
00289     {
00290         if (WSAGetLastError() == WSAEACCES)
00291         {
00292             /* FIXME: Is this correct? */
00293             _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n"));
00294             WSACleanup();
00295             HeapFree(GetProcessHeap(), 0, pInfo);
00296             exit(-1);
00297         }
00298         else
00299         {
00300             DebugPrint(_T("sendto failed %d\n"), WSAGetLastError());
00301         }
00302     }
00303     else
00304     {
00305         DebugPrint(_T("sent %d bytes\n"), iSockRet);
00306     }
00307 
00308     return iSockRet;
00309 }
00310 
00311 
00312 static BOOL
00313 ReceivePacket(PAPPINFO pInfo)
00314 {
00315     TIMEVAL timeVal;
00316     FD_SET readFDS;
00317     INT iSockRet = 0, iSelRet;
00318     INT iFromLen;
00319     BOOL bRet = FALSE;
00320 
00321     iFromLen = sizeof(pInfo->source);
00322 
00323     DebugPrint(_T("Receiving packet. Available buffer, %d bytes... "), MAX_PING_PACKET_SIZE);
00324 
00325     /* monitor icmpSock for incomming connections */
00326     FD_ZERO(&readFDS);
00327     FD_SET(pInfo->icmpSock, &readFDS);
00328 
00329     /* set timeout values */
00330     timeVal.tv_sec  = pInfo->iTimeOut / 1000;
00331     timeVal.tv_usec = pInfo->iTimeOut % 1000;
00332 
00333     iSelRet = select(0,
00334                      &readFDS,
00335                      NULL,
00336                      NULL,
00337                      &timeVal);
00338 
00339     if (iSelRet == SOCKET_ERROR)
00340     {
00341         DebugPrint(_T("select() failed in sendPacket() %d\n"), WSAGetLastError());
00342     }
00343     else if (iSelRet == 0) /* if socket timed out */
00344     {
00345         _tprintf(_T("   *  "));
00346     }
00347     else if ((iSelRet != SOCKET_ERROR) && (iSelRet != 0))
00348     {
00349         iSockRet = recvfrom(pInfo->icmpSock,            // socket
00350                            (char *)pInfo->RecvPacket,  // buffer
00351                            MAX_PING_PACKET_SIZE,        // size of buffer
00352                            0,                           // flags
00353                            (SOCKADDR *)&pInfo->source,  // source address
00354                            &iFromLen);                  // address length
00355 
00356         if (iSockRet != SOCKET_ERROR)
00357         {
00358             /* get time packet was recieved */
00359             pInfo->lTimeEnd = GetTime(pInfo);
00360             DebugPrint(_T("reveived %d bytes\n"), iSockRet);
00361             bRet = TRUE;
00362         }
00363         else
00364         {
00365             DebugPrint(_T("recvfrom failed: %d\n"), WSAGetLastError());
00366         }
00367     }
00368 
00369     return bRet;
00370 }
00371 
00372 
00373 static INT
00374 DecodeResponse(PAPPINFO pInfo)
00375 {
00376     unsigned short header_len = pInfo->RecvPacket->h_len * 4;
00377 
00378     /* cast the recieved packet into an ECHO reply and a TTL Exceed and check the ID*/
00379     ECHO_REPLY_HEADER *IcmpHdr = (ECHO_REPLY_HEADER *)((char*)pInfo->RecvPacket + header_len);
00380 
00381     /* Make sure the reply is ok */
00382     if (PACKET_SIZE < header_len + ICMP_MIN_SIZE)
00383     {
00384         DebugPrint(_T("too few bytes from %s\n"), inet_ntoa(pInfo->dest.sin_addr));
00385         return -2;
00386     }
00387 
00388     switch (IcmpHdr->icmpheader.type)
00389     {
00390            case TTL_EXCEEDED :
00391                 _tprintf(_T("%3ld ms"), (ULONG)((pInfo->lTimeEnd - pInfo->lTimeStart) / pInfo->TicksPerMs.QuadPart));
00392                 return 0;
00393 
00394            case ECHO_REPLY :
00395                 if (IcmpHdr->icmpheader.id != (USHORT)GetCurrentProcessId())
00396                 {
00397                 /* FIXME: our network stack shouldn't allow this... */
00398                 /* we've picked up a packet not related to this process probably from another local program. We ignore it */
00399                     DebugPrint(_T("Rouge packet: header id %d, process id  %d"), IcmpHdr->icmpheader.id, GetCurrentProcessId());
00400                     return -1;
00401                 }
00402                 _tprintf(_T("%3ld ms"), (ULONG)((pInfo->lTimeEnd - pInfo->lTimeStart) / pInfo->TicksPerMs.QuadPart));
00403                 return 1;
00404 
00405            case DEST_UNREACHABLE :
00406                 _tprintf(_T("  *  "));
00407                 return 2;
00408     }
00409 
00410     return -3;
00411 }
00412 
00413 
00414 static BOOL
00415 AllocateBuffers(PAPPINFO pInfo)
00416 {
00417     pInfo->SendPacket = (PECHO_REPLY_HEADER)HeapAlloc(GetProcessHeap(),
00418                                                       0,
00419                                                       sizeof(ECHO_REPLY_HEADER) + PACKET_SIZE);
00420     if (!pInfo->SendPacket)
00421         return FALSE;
00422 
00423     pInfo->RecvPacket = (PIPv4_HEADER)HeapAlloc(GetProcessHeap(),
00424                                                 0,
00425                                                 MAX_PING_PACKET_SIZE);
00426     if (!pInfo->RecvPacket)
00427     {
00428         HeapFree(GetProcessHeap(),
00429                  0,
00430                  pInfo->SendPacket);
00431 
00432         return FALSE;
00433     }
00434 
00435     return TRUE;
00436 }
00437 
00438 
00439 static INT
00440 Driver(PAPPINFO pInfo)
00441 {
00442     INT iHopCount = 1;              // hop counter. default max is 30
00443     BOOL bFoundTarget = FALSE;      // Have we reached our destination yet
00444     INT iRecieveReturn;             // RecieveReturn return value
00445     PECHO_REPLY_HEADER icmphdr;
00446     INT iTTL = 1;
00447 
00448     INT ret = -1;
00449 
00450     //temps for getting host name
00451     CHAR cHost[256];
00452     CHAR cServ[256];
00453     CHAR *ip;
00454 
00455     SetupTimingMethod(pInfo);
00456 
00457     if (AllocateBuffers(pInfo) &&
00458         ResolveHostname(pInfo) &&
00459         CreateSocket(pInfo))
00460     {
00461         /* print tracing info to screen */
00462         _tprintf(_T("\nTracing route to %s [%s]\n"), cHostname, cDestIP);
00463         _tprintf(_T("over a maximum of %d hop"), pInfo->iMaxHops);
00464         pInfo->iMaxHops > 1 ? _tprintf(_T("s:\n\n")) : _tprintf(_T(":\n\n"));
00465 
00466         /* run until we hit either max hops, or find the target */
00467         while ((iHopCount <= pInfo->iMaxHops) &&
00468                (bFoundTarget != TRUE))
00469         {
00470             USHORT iSeqNum = 0;
00471             INT i;
00472 
00473             _tprintf(_T("%3d   "), iHopCount);
00474 
00475             /* run 3 pings for each hop */
00476             for (i = 0; i < 3; i++)
00477             {
00478                 if (SetTTL(pInfo->icmpSock, iTTL) != TRUE)
00479                 {
00480                     DebugPrint(_T("error in Setup()\n"));
00481                     return ret;
00482                 }
00483 
00484                 PreparePacket(pInfo, iSeqNum);
00485 
00486                 if (SendPacket(pInfo) != SOCKET_ERROR)
00487                 {
00488                     BOOL bAwaitPacket = FALSE; // indicates whether we have recieved a good packet
00489 
00490                     do
00491                     {
00492                         /* Receive replies until we get a successful read, or a fatal error */
00493                         if ((iRecieveReturn = ReceivePacket(pInfo)) < 0)
00494                         {
00495                             /* FIXME: consider moving this into RecievePacket */
00496                             /* check the seq num in the packet, if it's bad wait for another */
00497                             WORD hdrLen = pInfo->RecvPacket->h_len * 4;
00498                             icmphdr = (ECHO_REPLY_HEADER *)((char*)&pInfo->RecvPacket + hdrLen);
00499                             if (icmphdr->icmpheader.seq != iSeqNum)
00500                             {
00501                                 _tprintf(_T("bad sequence number!\n"));
00502                                 continue;
00503                             }
00504                         }
00505 
00506                         if (iRecieveReturn)
00507                         {
00508                             if (DecodeResponse(pInfo) < 0)
00509                                 bAwaitPacket = TRUE;
00510                         }
00511 
00512                     } while (bAwaitPacket);
00513                 }
00514 
00515                 iSeqNum++;
00516                 _tprintf(_T("   "));
00517             }
00518 
00519             if(pInfo->bResolveAddresses)
00520             {
00521                 INT iNameInfoRet;               // getnameinfo return value
00522                /* gethostbyaddr() and getnameinfo() are
00523                 * unimplemented in ROS at present.
00524                 * Alex has advised he will be implementing getnameinfo.
00525                 * I've used that for the time being for testing in Windows*/
00526 
00527                   //ip = inet_addr(inet_ntoa(source.sin_addr));
00528                   //host = gethostbyaddr((char *)&ip, 4, 0);
00529 
00530                   ip = inet_ntoa(pInfo->source.sin_addr);
00531 
00532                   iNameInfoRet = getnameinfo((SOCKADDR *)&pInfo->source,
00533                                              sizeof(SOCKADDR),
00534                                              cHost,
00535                                              256,
00536                                              cServ,
00537                                              256,
00538                                              NI_NUMERICSERV);
00539                   if (iNameInfoRet == 0)
00540                   {
00541                      /* if IP address resolved to a hostname,
00542                       * print the IP address after it */
00543                       if (lstrcmpA(cHost, ip) != 0)
00544                           _tprintf(_T("%s [%s]"), cHost, ip);
00545                       else
00546                           _tprintf(_T("%s"), cHost);
00547                   }
00548                   else
00549                   {
00550                       DebugPrint(_T("error: %d"), WSAGetLastError());
00551                       DebugPrint(_T(" getnameinfo failed: %d"), iNameInfoRet);
00552                       _tprintf(_T("%s"), inet_ntoa(pInfo->source.sin_addr));
00553                   }
00554 
00555             }
00556             else
00557                _tprintf(_T("%s"), inet_ntoa(pInfo->source.sin_addr));
00558 
00559             _tprintf(_T("\n"));
00560 
00561             /* check if we've arrived at the target */
00562             if (strcmp(cDestIP, inet_ntoa(pInfo->source.sin_addr)) == 0)
00563                 bFoundTarget = TRUE;
00564             else
00565             {
00566                 iTTL++;
00567                 iHopCount++;
00568                 Sleep(500);
00569             }
00570         }
00571         _tprintf(_T("\nTrace complete.\n"));
00572         ret = 0;
00573     }
00574 
00575     return ret;
00576 }
00577 
00578 
00579 static VOID
00580 Cleanup(PAPPINFO pInfo)
00581 {
00582     if (pInfo->icmpSock)
00583         closesocket(pInfo->icmpSock);
00584 
00585     WSACleanup();
00586 
00587     if (pInfo->SendPacket)
00588         HeapFree(GetProcessHeap(),
00589                  0,
00590                  pInfo->SendPacket);
00591 
00592     if (pInfo->RecvPacket)
00593         HeapFree(GetProcessHeap(),
00594                  0,
00595                  pInfo->RecvPacket);
00596 }
00597 
00598 
00599 #if defined(_UNICODE) && defined(__GNUC__)
00600 static
00601 #endif
00602 int _tmain(int argc, LPCTSTR argv[])
00603 {
00604     PAPPINFO pInfo;
00605     WSADATA wsaData;
00606     int ret = -1;
00607 
00608     pInfo = (PAPPINFO)HeapAlloc(GetProcessHeap(),
00609                                 HEAP_ZERO_MEMORY,
00610                                 sizeof(APPINFO));
00611     if (pInfo)
00612     {
00613         pInfo->bResolveAddresses = TRUE;
00614         pInfo->iMaxHops = 30;
00615         pInfo->iTimeOut = 1000;
00616 
00617         if (ParseCmdline(argc, argv, pInfo))
00618         {
00619             if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
00620             {
00621                 DebugPrint(_T("WSAStartup failed.\n"));
00622             }
00623             else
00624             {
00625                 ret = Driver(pInfo);
00626                 Cleanup(pInfo);
00627             }
00628         }
00629 
00630         HeapFree(GetProcessHeap(),
00631                  0,
00632                  pInfo);
00633     }
00634 
00635     return ret;
00636 }
00637 
00638 
00639 #if defined(_UNICODE) && defined(__GNUC__)
00640 /* HACK - MINGW HAS NO OFFICIAL SUPPORT FOR wmain()!!! */
00641 int main( int argc, char **argv )
00642 {
00643     WCHAR **argvW;
00644     int i, j, Ret = 1;
00645 
00646     if ((argvW = malloc(argc * sizeof(WCHAR*))))
00647     {
00648         /* convert the arguments */
00649         for (i = 0, j = 0; i < argc; i++)
00650         {
00651             if (!(argvW[i] = malloc((strlen(argv[i]) + 1) * sizeof(WCHAR))))
00652             {
00653                 j++;
00654             }
00655             swprintf(argvW[i], L"%hs", argv[i]);
00656         }
00657 
00658         if (j == 0)
00659         {
00660             /* no error converting the parameters, call wmain() */
00661             Ret = wmain(argc, (LPCTSTR *)argvW);
00662         }
00663 
00664         /* free the arguments */
00665         for (i = 0; i < argc; i++)
00666         {
00667             if (argvW[i])
00668                 free(argvW[i]);
00669         }
00670         free(argvW);
00671     }
00672 
00673     return Ret;
00674 }
00675 #endif

Generated on Sat May 26 2012 04:16:15 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.