CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    May 2004
    Posts
    34

    Sending UDP Raw socket

    I truly need help on this. I am trying to write a test program that simulate a network environment that have 5 clients and 1 server. To do so, I need to be able to edit IP header to change it's source address and various other values in the header. To change it, I need to use socket raw and IP_HRINCL socket option.

    However, it doesn't work during the send with error 10049, "Address not available" from WSAGetLastError(). I am wondering how would I do so, and can I please look at a simple example on how to change your IP header and send it. By the way, I am using winsock with VC++, and my os is XP. I know there are some issues regarding XP's compatibility with Raw socket. In addition, if winsock is not a viable option, is there anyway for me to write in lower socket?

    Here's my code

    Code:
    #include <iostream>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    
    using namespace std;
    
    int initialize();
    
    void main()
    {
    	initialize();
    	SOCKET sock = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
    	int error;
    	char on = 1; 
    	setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)); 
    
    
    	if(sock == INVALID_SOCKET)
    		cout << "Crap raw socket " << endl;
    
    	/*  Header data */
    	unsigned char header[32] = {0x45,0x00,0x00,0x20,0x01,0xf1,0x00,0x00,0x05,0x11,0x9c,0x0a,0x05,0x3a,0x38,0x02,0xe0,
    		0x02,0xfa,0x93};
    	
    	memset(header+20,0,12);
    	
    	SOCKADDR_IN sock_add;
    	sock_add.sin_family = AF_INET;
    	sock_add.sin_port = htons(1542);
    	sock_add.sin_addr.s_addr = inet_addr("192.168.1.1");
    	
    	error = sendto(sock,(char*)header,32,0,(LPSOCKADDR)&sock_add,sizeof(SOCKADDR_IN));
    	
    	
    }
    
    int initialize()
    {
    	int t;
    	/*  Before any Winsock function to work, we need to call to wsock.dll to initialize those 
    		functions */
    	WSADATA wsa_data;
    	t = WSAStartup(MAKEWORD(1,1), &wsa_data);
    
    	if(t != 0)
    		return -1;
    	else 
    		return 0;
    }

  2. #2
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    Well '10049' WSAEADDRNOTAVAIL "The requested address is not valid in its context". Seems like the source address is not right. Using struct for header is always better and easier. For using UDP you may have to change the socket to IPPROTO_UDP. As for IP_HDRINCL you should be getting in XP if you have admin previlage. I'm pasting the header of IP and UDP for your easy reference.
    Code:
    // The IP header structure
    //
    typedef struct _iphdr 
    {
      unsigned char  h_len:4;    // Length
      unsigned char  ver:4;      // IP Version
      unsigned char  tos;        // Type of service
      unsigned short totlen;     // Total length of the packet
      unsigned short id;         // Unique identifier
      unsigned short offset;     // Fragment offset field
      unsigned char  ttl;        // Time to live
      unsigned char  proto;      // Protocol(TCP,UDP,ICMP,IGMP...)
      unsigned short checksum;   // IP checksum
    
      unsigned int srcIP;        // Source IP address
      unsigned int destIP;       // Destination IP address
    }IpHeader, * LPIpHeader;
    
    // The UDP header structure
    //
    typedef struct _udphdr
    {
        unsigned short sport;       // Source Port    
        unsigned short dport;       // Destination Port   
        unsigned short Length;     // Length      
        unsigned short Checksum;    // Checksum    
                 
    }UdpHeader, * LPUdpHeader;
    PS: You also need winsock 2 (link to ws2_32.lib)
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  3. #3
    Join Date
    May 2004
    Posts
    34
    I am wondering is it possible that you write a simple code on how to initialize those value and send it?

  4. #4
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    Well, I don't exactly have the udp header initing codes. Hope you can make out the rest.
    Code:
        memset(sendBuf,0,2048);
      
      iphdr = (IpHeader *) sendBuf;  // the ip header now points to the top of the sendBuf
      udphdr=(UdpHeader *) (sendBuf + sizeof(IpHeader));  // the udp header points to the part next to the ip header
    
        iphdr->ver    = 4;
      iphdr->len    = 5;
      iphdr->tos    = 0;
      iphdr->tot_len  = sizeof (IpHeader) + sizeof (UdpHeader) + (the data);
      iphdr->id    = 1;
      iphdr->offset  = 0;
      iphdr->ttl    = 255;
      iphdr->protocol  = IPPROTO_UDP;  //UDP
      iphdr->checksum  = 0;
    
      iphdr->srcaddr  = inet_addr ("1.2.3.4"); // your source id
      iphdr->destaddr = sock_addr.sin_addr.s_addr;
    
       // Initalize the UDP header
       //
       iUdpSize = sizeof(udpHdr) + strlen(strMessage);
    
       udpHdr.sport = htons(iFromPort) ;
       udpHdr.dport = htons(iToPort) ;
       udpHdr.Length = htons(iUdpSize) ;
       udpHdr.Checksum = 0 ;
    
      // fill the data
    
       udpHdr.Checksum  = checksum(pseudo header+udp header+ data);
      iphdr->checksum  = checksum((unsigned short *) iphdr, sizeof(IpHeader));
    to calculate the check sum you need a psuedo header
    Code:
    typedef struct _PSHeader 
    {
      unsigned long srcaddr;
      unsigned long destaddr;
    
      unsigned char  zero;
      unsigned char  protocol;
      unsigned short len;
    
    }PSHeader;
    Fill the PSHeader. the psuedo header, the udp header along with the data should be passed to check sum function.

    The checksum function.
    Code:
    USHORT checksum(USHORT *buffer, int size)
    {
      unsigned long cksum=0;
    
        while (size > 1)
        {
            cksum += *buffer++;
            size  -= sizeof(USHORT);   
        }
        
      if (size)
        {
            cksum += *(UCHAR*)buffer;   
        }
        
      cksum  = (cksum >> 16) + (cksum & 0xffff);
        cksum += (cksum >> 16); 
        
      return (USHORT)(~cksum); 
    }
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  5. #5
    Join Date
    May 2004
    Posts
    34
    Well, the question now is that I cannot write the newly created data into header. What happen is that the socket treat the information as data and attach the appropriate IP header and UDP header with it. Let say if i created a data with all the appropriate header information, how do I send it? and what socket option should I set?

  6. #6
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    If I correctly got what you asked, you send using the sendto() as it is showed in your code which is pasted. All you have to do to the above code(yours) is to fill the header using struct as I've shown, rather that the way you are using. Rest every thing is fine. The SOCKADDR_IN structure that you fill just before calling sendto() won't matter much (whether it is right or wrong) because the information is already in your header.

    Hope that helps
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  7. #7
    Join Date
    May 2004
    Posts
    34
    Well, this is my code. the problem I have now is that 10049 from WSAGetLastError(). One possible reason is that the socket cannot find the appropriate interface to send the data. However, i highly doubt that's the case. I don't think checksum is an issue since the receiving end will simply drop the packet. The main concern is how to send it.

    Code:
    void main()
    {
    	initialize();
    	SOCKET sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
    	SOCKADDR_IN sock_addr;
    	char on = 1; 
    	setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)); 
    
    	unsigned char sendBuf[2048];
    	memset(sendBuf,0,2048);
    	
    	unsigned char data[20];
    	memset(data,0,20);
    
    	IpHeader *iphdr;
    	UdpHeader *udphdr, udpHdr;
    	int iUdpSize, error;
    	PSHeader pseudo_header;
    
    	
    	iphdr = (IpHeader *)   sendBuf;  // the ip header now points to the top of the sendBuf
    	udphdr=	(UdpHeader *) (sendBuf + sizeof(IpHeader));  // the udp header points to the part next to the ip header
    
    	sock_addr.sin_family = AF_INET;
    	sock_addr.sin_port = htons (1526);
    	sock_addr.sin_addr.s_addr = inet_addr("2.3.4.5");
    	
    	iphdr->ver    = 4;
    	iphdr->h_len    = 5;
    	iphdr->tos    = 0;
    	iphdr->totlen  = sizeof (IpHeader) + sizeof (UdpHeader) + sizeof(data);
    	iphdr->id    = 1;
    	iphdr->offset  = 0;
    	iphdr->ttl    = 255;
    	iphdr->proto  = IPPROTO_UDP;  //UDP
    	iphdr->checksum  = 0;
    
    	iphdr->srcIP  = inet_addr ("5.57.52.11"); // your source id
    	iphdr->destIP = sock_addr.sin_addr.s_addr;
    
    	// Initalize the UDP header
    	//
    	iUdpSize = sizeof(udpHdr) + strlen((char*)data);
    
    	udphdr->sport = htons(1564) ;
    	udphdr->dport = htons(1700) ;
    	udphdr->Length = htons(iUdpSize) ;
    	udphdr->Checksum = 0 ;
    
    	//calculate UDP CheckSum
    	pseudo_header.destaddr = inet_addr("192.168.1.1");
    	pseudo_header.srcaddr = inet_addr("1.2.3.4");
    	pseudo_header.zero = 0;
    	pseudo_header.protocol = 17;
    	pseudo_header.len = sizeof(data) + sizeof(udphdr);
    	
    	// fill the data
    	udpHdr.Checksum  = checksum((unsigned short*) udphdr,sizeof(pseudo_header));
    	iphdr->checksum  = checksum((unsigned short *) iphdr, sizeof(IpHeader));
    
    	for(int i=0;i<40;i++)
    		printf("%x",sendBuf[i]);
    
    	error = sendto(sock,(char*)sendBuf,40,0,(LPSOCKADDR)&sock_addr,sizeof(SOCKADDR_IN));
    
    	if(error == SOCKET_ERROR)
    		cout << WSAGetLastError() << endl;
    	else
    		cout << "sent" << endl;
    
    }

  8. #8
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    The error that you got is the address is wrong. The checksum was calculated wrongly including many other omission and mistakes. I've quickly created a working version of your code and attached. I recommend you to compare with your code study/play with it before setting out. Point is that you should understand the underlying working principle of it.

    Attached Files Attached Files
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  9. #9
    Join Date
    May 2004
    Posts
    34
    Thank Matt, one lesson well learned.

  10. #10
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    You are welcome...
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  11. #11
    Join Date
    May 2004
    Posts
    34

    Does raw socket works with IPv6?

    Does this method works with IPv6? If not, what are other ways to config header parameters in ipV6? I understand that IPv6 uses different header than IPv4, but does the socket recognize it by simply look at the "version parameter"?

  12. #12
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    It should work with IPv6. However you should note that the header struct for v6 and that of v4 are entirely different. Version feild is the same, but simply changing the vesion no won't change from 4 to 6. For instance IPv4's header is 20 bytes(not fixed though), but IPv6's header is fixed to 40 bytes. 4 does have checksum, but 6 relies on the upper layer protocols to do it.

    The most important thing, however is, your os should support IPv6 before you can send IPv6 packets
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  13. #13
    Join Date
    Feb 2003
    Location
    Bangalore, India
    Posts
    1,354
    triple 7 is not a nice no. (on my no of posts)
    Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.

    * While posting code sections please use CODE tags
    * Please check the codeguru FAQ and do a little search to see if your question have been answered before.
    * Like a post, Rate The Post
    * I blog: Network programming, Bible

    I do all things thru CHRIST who strengthens me

  14. #14
    Join Date
    Jun 2002
    Location
    Madrid - Spain
    Posts
    28

    Re: Sending UDP Raw socket

    Hello, Mathew!

    I get your code working perfectly on Windows 2000.
    Thank you very much.

    But when I run it on Windows XP (SP3), the 'sendto' function fails with error 10004.

    I've read that, starting XP SP2, Windows does not allow sending packets with spoofed IP.
    BUT I do not spoof the IP: Even when I enter my own IP as the source and a valid IP within my LAN as destination, it fails with error 10004.

    Any hints on how to work around this and get your code working under Windows XP?

    Thank you very much!

    Ricardo Vazquez.
    Madrid, Spain.

  15. #15
    Join Date
    Jun 2002
    Location
    Madrid - Spain
    Posts
    28

    Re: Sending UDP Raw socket

    Sorry:

    I was wrong:

    If source IP is my own it works under WinXP.

    But, then again:
    Is there any way to get Mathew's code working with a different source IP under WinXP after SP2?

    Kind regards,

    Ricardo.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured