Solved

Winsock can't set TOS field on ICMP packets

Posted on 2007-11-13
12
1,712 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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

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.
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
After creating this article (http://www.experts-exchange.com/articles/23699/Setup-Mikrotik-routers-with-OSPF.html), I decided to make a video (no audio) to show you how to configure the routers and run some trace routes and pings between the 7 sites…

760 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

19 Experts available now in Live!

Get 1:1 Help Now