LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (http://www.linuxquestions.org/questions/linux-networking-3/)
-   -   Please Help me : Sendto: Invalid argument PF_PACKET SOCK_DGRAM htons(ETH_P_IP) (http://www.linuxquestions.org/questions/linux-networking-3/please-help-me-sendto-invalid-argument-pf_packet-sock_dgram-htons-eth_p_ip-689308/)

tuxtuxtux 12-09-2008 09:01 AM

Please Help me : Sendto: Invalid argument PF_PACKET SOCK_DGRAM htons(ETH_P_IP)
 
Hi ,

Can somebody please help me find the problem with the code posted below.In that i am trying to get SOCK_DGRAM packets through ethernet device(both eth0 and lo) and calculating checksums and then printing IP and TCP headers along with checksum.I recieve packets using recvfrom function.I managed to get all the fields correct(i think so) including checksums.I am using a little endian machine. Then i try to send the same packet back to interface without any change.I use sendto for this purpose.But whatever i do sendto always returns "Invalid argument" error.I am after this problem for three days and could not advance past this error.I have browsed internet for a solution and tried all that i think might be causing the problem.but no success.Now i have no option other than posting it here and hoping that somebody will take a look at the code.

Here is the code....
(I have pasted a sample output also at the end.)


Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>


#define MY_MAXLEN 65535
#define BYTE unsigned char
#define WORD unsigned short

#define IP_VERSION 4

#define WINDOW_SIZE 256;

#define URG 0x20
#define ACK 0x10
#define PSH 0x8
#define RST 0x4
#define SYN 0x2
#define FIN 0x1

#define TRUE 1
#define FALSE 0

unsigned short in_cksum(unsigned short *addr,unsigned short len)
{
register int nleft = len;
register unsigned short *w = addr;
register int sum = 0;
unsigned short answer = 0;

                          while (nleft > 1)
                          {
                                    sum += *w++;
                                    nleft -= 2;
                          }
                          if (nleft == 1)
                          {
                                      *(u_char *)(&answer) = *(u_char *)w ;
                                      sum += answer;
                          }
                          sum = (sum >> 16) + (sum & 0xffff);
                          sum += (sum >> 16);
                          answer = ~sum;
                          return(ntohs(answer));
}

#pragma pack(1)
typedef struct
{
struct in_addr src_addr;
struct in_addr dst_addr;
BYTE res;
BYTE proto;
WORD tcp_len;
}PSEUDO_HDR;

/* i386 is little-endian. */

/*Linux localhost.localdomain 2.6.23.13 #2 PREEMPT Tue Jan 15 13:18:33 IST 2008 i686 i686 i386 GNU/Linux*/


int main()
{
int my_packet_sock;
BYTE my_buf[MY_MAXLEN];
int ret=0;
int i=0;
struct packet_mreq sockopt;
struct sockaddr_ll from;
socklen_t fromlen=0;
struct ip *iph=NULL;
struct tcphdr *tcph=NULL;
PSEUDO_HDR pseudo_hdr;
int len=0,padding=0;
BYTE *tmp_buf=NULL;
short tmp_sum=0;



               
    if((my_packet_sock=socket(PF_PACKET,SOCK_DGRAM,htons(ETH_P_IP)))==-1)
    {
                perror("Socket Creation");
                return FALSE;
    }

    printf("\nSocket Created Succefully\n");

    sockopt.mr_ifindex=1; /* interface index */
    sockopt.mr_type=PACKET_MR_PROMISC;/* action */
    sockopt.mr_alen=0; /* address length */
    sockopt.mr_address[0]='\0'; /* physical layer address */

  if(setsockopt(my_packet_sock,SOL_PACKET,PACKET_ADD_MEMBERSHIP,(void
*)&sockopt,sizeof(sockopt))==-1)
  {
          perror("Set Socket Options");
          return FALSE;
  }
  printf("\nSocket Options Set Succefully\n");


  fromlen=sizeof(struct sockaddr_ll);
  memset((BYTE *)&from,0x0,fromlen);
  while((ret=recvfrom(my_packet_sock,(BYTE *)my_buf,MY_MAXLEN,0,(struct sockaddr *)&from,&fromlen))>0)
  {
        iph=(struct ip *)my_buf;
        printf("\nIP Total Bytes Read=%d\nip header
        length=%d:ip version=%d:ip type of service=%d:ip total length=
        %d:ip identification=%d:ip fragment offset field=%d:ip time to
        live=%d:ip protocol =%d:ip checksum=%x:ip source address=%s:
        ip destaddress=%s\n",ret,iph->ip_hl,iph->ip_v,iph->ip_tos,
        ntohs(iph->ip_len),iph->ip_id,iph->ip_off,iph->ip_ttl,
        iph->ip_p,ntohs(iph->ip_sum),inet_ntoa(iph->ip_src),inet_ntoa(iph->ip_dst));


      tmp_sum=iph->ip_sum;
      iph->ip_sum=0;

      printf("\n\nIP check sum is %x \n",in_cksum((unsigned short *)my_buf,iph->ip_hl)*4));

      iph->ip_sum=tmp_sum;

      printf("\nfromlen=%d,family=%x,protocol=%x,ifindex=%x,hatype=%x,
      pkttype=%x,halen=%d "           
      ,fromlen,from.sll_family,ntohs(from.sll_protocol),from.sll_ifindex,
        from.sll_hatype,from.sll_pkttype,from.sll_halen);

        for(i=0;i<8;i++)
        {
            printf(" %X",from.sll_addr[i]);
        }
        printf("\n");
        i=0;

        if(iph->ip_p==IPPROTO_TCP)
        {
              tcph=(struct tcphdr *)&my_buf[(iph->ip_hl)*4];

              printf("\nTCP source port=%d,destination
              port=%d,seq=%ld,ack=%ld,res1=%d,doff=%d,FIN=%d,SYN=%d,RST=%d,
              PSH=%d,ACK=%d,URG=%d,res2=%d,window=%d,check=%x,urg_ptr=%d\n",
              ntohs(tcph->source),ntohs(tcph->dest),ntohs(tcph->seq),
              ntohs(tcph->ack_seq),tcph->res1,tcph->doff,tcph->fin,
              tcph->syn,tcph->rst,tcph->psh,tcph->ack,tcph->urg,
              tcph->res2,ntohs(tcph->window),ntohs(tcph->check),
              ntohs(tcph->urg_ptr));

              tmp_sum=tcph->check;
              tcph->check=0;

              pseudo_hdr.src_addr=iph->ip_src;
              pseudo_hdr.dst_addr=iph->ip_dst;
              pseudo_hdr.res=0;
              pseudo_hdr.proto=iph->ip_p;
              pseudo_hdr.tcp_len=htons(ntohs(iph->ip_len)-((iph->ip_hl)*4));

              padding= (ntohs(iph->ip_len) - ((iph->ip_hl) * 4) - ((tcph->doff) *4))%2;
              len=ntohs(pseudo_hdr.tcp_len)+sizeof(PSEUDO_HDR)+padding;


              tmp_buf=calloc(len,1);

              memcpy(tmp_buf,(PSEUDO_HDR *)&pseudo_hdr,sizeof(PSEUDO_HDR));
              memcpy(tmp_buf+sizeof(PSEUDO_HDR),(BYTE     
              *)&my_buf[(iph->ip_hl)*4],ntohs(pseudo_hdr.tcp_len));

              printf("\nTCP check sum is %x Pseudo size is %d Padding is     
              %d",in_cksum((unsigned short *)tmp_buf,len),sizeof(PSEUDO_HDR),padding);

              free(tmp_buf);
              tcph->check=tmp_sum;

              if(tcph->ack)
              {
                  if(sendto(my_packet_sock,my_buf,ntohs(iph->ip_len),0,(struct sockaddr     
                  *)&from,fromlen)==-1)
                  {
                          perror("Sendto");
                  }
                  else
                  {
                          printf("\nSendto Success\n");
                  }

            }
        }
    }
    perror("Read Socket");
    return FALSE;
}



Here is the output i get


[root@localhost rsocket]# ./dgram_sock.o

Socket Created Succefully

Socket Options Set Succefully

IP Total Bytes Read=52
ip header length=5:ip version=4:ip type of service=0:ip total length=52:ip identification=0:ip fragment offset field=64:ip time to live=48:ip protocol =6:ip checksum=d514:ip source address=202.58.12.98:ip dest address=202.58.12.98


IP check sum is d514

fromlen=18,family=11,protocol=800,ifindex=2,hatype=1,pkttype=0,halen=6 0 B 45 B6 70 40 0 0

TCP source port=80,destination port=41047,seq=59778,ack=62938,res1=0,doff=8,FIN=0,SYN=0,RST=0,PSH=0,ACK=1,URG=0,res2=0,window=64,ch eck=77c4,urg_ptr=0

Sendto: Invalid argument
TCP check sum is 77c4 Pseudo size is 12 Padding is 0
IP Total Bytes Read=52
ip header length=5:ip version=4:ip type of service=0:ip total length=52:ip identification=0:ip fragment offset field=64:ip time to live=48:ip protocol =6:ip checksum=d514:ip source address=202.58.12.98:ip dest address=202.58.12.98


IP check sum is d514

fromlen=18,family=11,protocol=800,ifindex=2,hatype=1,pkttype=0,halen=6 0 B 45 B6 70 40 0 0

TCP source port=80,destination port=41046,seq=59672,ack=63117,res1=0,doff=8,FIN=0,SYN=0,RST=0,PSH=0,ACK=1,URG=0,res2=0,window=71,ch eck=7916,urg_ptr=0

Sendto: Invalid argument

Thanks for reading,
somebody please help...........

tuxtuxtux 12-09-2008 09:57 PM

Thanks,i got the answer...
 
Hello everybody,

That issue is solved now.
Thanks to Rob from another forum.
I am posting it here for anybody
who is interested.

the solution in Rob's own words is..

"But, try this: just before the sendto() reset "fromlen" to the full "sizeof (struct sockaddr_ll)"...Why? If I'm reading my local kernel source correctly, sendto() on a packet socket will fail with EINVAL if you pass it any length less than that... And, yet, recvfrom() will give
you a short length which only corresponds to the sll_halen + rest of preceding fields (ie: only counting the length of the actual filled-in hardware address)... One of those two is likely wrong and should change in the kernel, IMHO... (I'd say that sendmsg() should be flexible enough to accept the shorter address...) But, failing changing the kernel, it looks like you have to bow to its wishes and pass it the full length... *shrug* "

...that was the issue and it is solved now.

"Bow your head,kneel and Worship.... the KERNEL"

thanks,
sree

skarthiga24 02-24-2010 06:45 AM

hi

can you tell what change you did in the piece of code,that worked properly now.

thanks
karthiga

daniel.reus 03-24-2010 07:08 AM

Wow, A decently formulated question and you actually took the effort to post back when you found the answer... Respect :)


All times are GMT -5. The time now is 09:50 AM.