Solved

Winsock can't set TOS field on ICMP packets

Posted on 2007-11-13
12
1,722 Views
Last Modified: 2013-11-29
I'm trying to create a simple PING program in C to transmit ICMP packets with specific TOS bits set.

I followed KB248611 (http://support.microsoft.com/kb/248611) and set the registry correctly.  Microsoft's "ping" program is able to set the TOS bit correctly now.

My program uses Winsock and setsockopt to set the TOS field, but the resulting packets still don't have the TOS field set (I use a sniffer to verify).  Does anyone have any experience doing this with Winsock and setsockopt?
0
Comment
Question by:ttitus
12 Comments
 
LVL 4

Expert Comment

by:yuy2002
ID: 20277926
Hi,ttitus
Make sure you restart your computer and  you'd better to modify the registry in programming .

Good luck,
Charles
0
 

Author Comment

by:ttitus
ID: 20277934
I have confirmed that the registry entry is changed on my computer because the native "ping" program is now able to set the TOS field.  It was unable to do this before I applied the registry change.  Thus, this confirms that the registry is set correctly.

The problem is that I cannot seem to get winsock and setsockopt to work correctly.
0
 
LVL 4

Expert Comment

by:yuy2002
ID: 20278341
In the packet IP header, you will see Differentiated Service Field, but not Type Of Service.
0
 
LVL 4

Expert Comment

by:yuy2002
ID: 20278365
"This design change is because the former ToS and precedence bits specified in Request For Comment (RFC) 1349 have been made obsolete by RFCs 2474 and 2475. These RFCs replaced ToS with Differentiated Services (DiffServ)."
Do you get "Differentiated Service Field"?
0
 

Author Comment

by:ttitus
ID: 20281722
Sorry, I see TOS and DiffServe as the same field (which it is, but I used the "old" term).  I want to set the DiffServe field, but have not been able to do this programatically with setsockopt.  I'm interested in hearing from anyone who has used setsockopt to set the DiffServe field successfully.
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 4

Accepted Solution

by:
yuy2002 earned 500 total points
ID: 20287192
//initial windows socket
      ret = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(ret != 0)
    {
          LogPrint(LOG_Error,"WSAStartup failed\r\n");
            return;
      }


      FP_DPS_Socket = socket(AF_INET, SOCK_DGRAM, 0);
      if( SOCKET_ERROR == FP_DPS_Socket)
      {
            LogPrint(LOG_Error,"Creating socket failed\r\n");
            return;
      }

      optset = 0x02;
      optlen = sizeof(optset);
                     setsockopt(FP_DPS_Socket, IPPROTO_IP, IP_TOS, &optset, optlen);
                   
                     if (connect(FP_DPS_Socket, (struct sockaddr*)&remoteDpsAddr,
            sizeof(remoteDpsAddr)) == SOCKET_ERROR)
      {
            LogPrint(LOG_Error,"Connecting to dps failed\r\n");
            closesocket(FP_DPS_Socket);             
            return ;
      }

      FD_SET(FP_DPS_Socket, &readset);
      

      // Set socket param eg NO Block ....
      unsigned long optcntl = 1;
      ioctlsocket(FP_DPS_Socket, FIONBIO, &optcntl);
0
 
LVL 4

Expert Comment

by:yuy2002
ID: 20287200
ip.h:
...
#define IPTOS_TOS_MASK          0x1E
#define IPTOS_TOS(tos)          ((tos)&IPTOS_TOS_MASK)
#define IPTOS_LOWDELAY          0x10
#define IPTOS_THROUGHPUT        0x08
#define IPTOS_RELIABILITY       0x04
#define IPTOS_MINCOST           0x02
...
0
 
LVL 4

Expert Comment

by:yuy2002
ID: 20287213
I have set the DiffServ to 0x02 successfully according to the code.
0
 
LVL 4

Expert Comment

by:yuy2002
ID: 20297131
Ping:
int CPing::Ping(LPCTSTR pszHostName, CPingReply& pr, int nPings, UCHAR nTTL, DWORD dwTimeout, int nPacketSize, UCHAR nTOS, BOOL bDontFragment)
{
      pr.nError = -1;
      pr.minRTT = ULONG_MAX;
      pr.maxRTT = 0;
      pr.avgRTT = 0;

      //For correct operation of the T2A macro, see TN059
      USES_CONVERSION;

      //Use the High performace counter to get an accurate RTT
      LARGE_INTEGER Frequency;
      Frequency.QuadPart = 0;
      if (!QueryPerformanceFrequency(&Frequency))
      {
            TRACE(_T("Failed to get the high performance counter frequency\n"));
            return -1;
      }
      __int64 nTimerFrequency = Frequency.QuadPart;

      //Resolve the address of the host to connect to
      sockaddr_in dest;
      memset(&dest,0,sizeof(dest));
      LPSTR lpszAscii = T2A((LPTSTR) pszHostName);
      unsigned long addr = inet_addr(lpszAscii);
      if (addr == INADDR_NONE)
      {
            //Not a dotted address, then do a lookup of the name
            hostent* hp = gethostbyname(lpszAscii);
            if (hp)
            {
                  memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
                  dest.sin_family = hp->h_addrtype;
            }
            else
            {
                  TRACE(_T("CPing::PingUsingWinsock, Could not resolve the host name %s\n"), pszHostName);
                  CString temp;
                  temp.Format("Could not resolve host name \"%s\" ", pszHostName);
                  AfxMessageBox(temp);
                  return -1;
            }
      }
      else
      {
            dest.sin_addr.s_addr = addr;
            dest.sin_family = AF_INET;
      }

      //Create the raw socket
      SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
      if (sockRaw == INVALID_SOCKET)
      {
            TRACE(_T("CPing::PingUsingWinsock, Failed to create a raw socket\n"));
            return -1;
      }

      SOCKADDR_IN sockLocalAddress;
      ZeroMemory(&sockLocalAddress, sizeof(sockLocalAddress));
      sockLocalAddress.sin_family = AF_INET;
      sockLocalAddress.sin_port = htons((u_short)0);

      LPHOSTENT lphost;
      lphost = gethostbyname(NULL);
      if (lphost != NULL)
            sockLocalAddress.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
      else
      {
            return -1;
      }

      if (bind(sockRaw, (sockaddr*) &sockLocalAddress, sizeof(sockLocalAddress)) == SOCKET_ERROR)
    {
            TRACE(_T("CPing::PingUsingWinsock, Failed to bind to specified address\n"));
            return -1;
    }

      //Set the TTL on the socket  
      int nTempTTL = nTTL;
      if (setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char*) &nTempTTL, sizeof(nTempTTL)) == SOCKET_ERROR)
      {
            TRACE(_T("CPing::PingUsingWinsock, Failed to set the TTL value on the socket\n"));
            return -1;
      }

      //Set the TOS on the socket  
      int nTempTos = nTOS;
      if (setsockopt(sockRaw, IPPROTO_IP, IP_TOS, (char*) &nTempTos, sizeof(nTempTos)) == SOCKET_ERROR)
      {
            TRACE(_T("CPing::PingUsingWinsock, Failed to set the Tos value on the socket\n"));
            return -1;
      }

      //Set the Don't Fragment flag on the socket  
      if (bDontFragment)
      {
            if (setsockopt(sockRaw, IPPROTO_IP, IP_DONTFRAGMENT, (char*) &bDontFragment, sizeof(bDontFragment)) == SOCKET_ERROR)
            {
                  TRACE(_T("CPing::PingUsingWinsock, Failed to set the Don't Fragment value on the socket\n"));
                  return -1;
            }
      }
 
      //Allocate the ICMP packet
      int nBufSize = nPacketSize + sizeof(ICMP_HEADER);
      char* pICMP = new char[nBufSize];
      FillIcmpData((LPICMP_HEADER) pICMP, nBufSize);

      //Get the tick count prior to sending the packet
      LARGE_INTEGER TimerTick;
      VERIFY(QueryPerformanceCounter(&TimerTick));
      __int64 nStartTick = TimerTick.QuadPart;

      for (int i=0; i<nPings; i++)
      {
            //Send of the packet
            int nWrote = sendto(sockRaw, pICMP, nBufSize, 0, (sockaddr*)&dest, sizeof(dest));
            if (nWrote == SOCKET_ERROR)
            {
                  TRACE(_T("CPing::PingUsingWinsock, sendto failed\n"));

                  delete [] pICMP;

                  DWORD dwError = GetLastError();
                  closesocket(sockRaw);
                  SetLastError(dwError);

                  return -1;
            }

            //allocate the recv buffer
            char* pRecvBuf = new char[MAX_ICMP_PACKET_SIZE];
            BOOL bReadable;
            sockaddr_in from;
            int nFromlen = sizeof(from);
            int nRead = 0;

            //Allow the specified timeout
            if (IsSocketReadible(sockRaw, dwTimeout, bReadable))
            {
                  if (bReadable)
                  {
                        //Receive the response
                        nRead = recvfrom(sockRaw, pRecvBuf, MAX_ICMP_PACKET_SIZE, 0, (sockaddr*)&from, &nFromlen);
                  }
                  else
                  {
                        TRACE(_T("CPing::PingUsingWinsock, timeout occured while awaiting recvfrom\n"));
                        closesocket(sockRaw);

                        delete [] pICMP;
                        delete [] pRecvBuf;

                        //set the error to timed out
                        SetLastError(WSAETIMEDOUT);

                        return -1;
                  }
            }
            else
            {
                  TRACE(_T("CPing::PingUsingWinsock, IsReadible call failed\n"));

                  delete [] pICMP;
                  delete [] pRecvBuf;

                  DWORD dwError = GetLastError();
                  closesocket(sockRaw);
                  SetLastError(dwError);

                  return -1;
            }

            //Get the current tick count
            QueryPerformanceCounter(&TimerTick);

            //Now check the return response from recvfrom
            if (nRead == SOCKET_ERROR)
            {
                  TRACE(_T("CPing::PingUsingWinsock, recvfrom call failed\n"));

                  delete [] pICMP;
                  delete [] pRecvBuf;

                  DWORD dwError = GetLastError();
                  closesocket(sockRaw);
                  SetLastError(dwError);

                  return -1;
            }

            //Decode the response we got back
            pr.nError = DecodeResponse(pRecvBuf, nRead, &from);

            pr.Address = from.sin_addr;
            ULONG rtt = (ULONG) ((TimerTick.QuadPart - nStartTick) * 1000 / nTimerFrequency);
            pr.avgRTT += rtt;
            if (pr.maxRTT < rtt)
                  pr.maxRTT = rtt;
            if (pr.minRTT > rtt)
                  pr.minRTT = rtt;
            delete [] pRecvBuf;
      }
      pr.avgRTT /= nPings;
      //Don't forget to release out socket
      closesocket(sockRaw);

      //Free up the memory we allocated
      delete [] pICMP;

      //return the status
      return pr.nError;
}
0
 
LVL 1

Expert Comment

by:Computer101
ID: 20633878
Forced accept.

Computer101
EE Admin
0
 
LVL 4

Expert Comment

by:Chizl
ID: 20639546
Sorry I'm late on this, but FYI..  

setsockopt works up to 2000..   WinXP you have to set a registry key to turn it on.  Vista, this API has been removed completely.
0

Featured Post

Give your grad a cloud of their own!

With up to 8TB of storage, give your favorite graduate their own personal cloud to centralize all their photos, videos and music in one safe place. They can save, sync and share all their stuff, and automatic photo backup helps free up space on their smartphone and tablet.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
drawing animated level bar based on numbers 3 88
L2 to EIGRP slow migration? 27 97
Not needed 13 94
show out valin of json for debugging in visaul c++ 1 16
How to remove superseded packages in windows w60 or w61 installation media (.wim) or online system to prevent unnecessary space. w60 means Windows Vista or Windows Server 2008. w61 means Windows 7 or Windows Server 2008 R2. There are various …
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now