[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1837
  • Last Modified:

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?
0
Tim Titus
Asked:
Tim Titus
1 Solution
 
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
 
yuy2002Commented:
In the packet IP header, you will see Differentiated Service Field, but not Type Of Service.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
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:
//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:
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

Featured Post

[Webinar] Improve your customer journey

A positive customer journey is important in attracting and retaining business. To improve this experience, you can use Google Maps APIs to increase checkout conversions, boost user engagement, and optimize order fulfillment. Learn how in this webinar presented by Dito.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now