Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Winsock can't set TOS field on ICMP packets

Posted on 2007-11-13
12
Medium Priority
?
1,807 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:Tim Titus
11 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:Tim Titus
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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:Tim Titus
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
 
LVL 4

Accepted Solution

by:
yuy2002 earned 2000 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

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

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

We recently endured a series of broadcast storms that caused our ISP to shut us down for brief periods of time. After going through a multitude of tests, we determined that the issue was related to Intel NIC drivers on some new HP desktop computers …
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
Suggested Courses

877 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