Winsock can't set TOS field on ICMP packets

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?
Tim TitusCTOAsked:
Who is Participating?
 
yuy2002Commented:
//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
 
yuy2002Commented:
Hi,ttitus
Make sure you restart your computer and  you'd better to modify the registry in programming .

Good luck,
Charles
0
 
Tim TitusCTOAuthor Commented:
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
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
yuy2002Commented:
In the packet IP header, you will see Differentiated Service Field, but not Type Of Service.
0
 
yuy2002Commented:
"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
 
Tim TitusCTOAuthor Commented:
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
 
yuy2002Commented:
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
 
yuy2002Commented:
I have set the DiffServ to 0x02 successfully according to the code.
0
 
yuy2002Commented:
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
 
Computer101Commented:
Forced accept.

Computer101
EE Admin
0
 
ChizlCommented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.