简体   繁体   中英

sendto() : Invalid argument - raw socket

I want to access ip header using raw socket, change TTL value and forward the packet to the client. Adress of server is 192.168.1.5 and adress of client is 192.168.1.3. I have problem with sendto() function, error handling prints out: sendto() failed: Invalid argument. My code is here:

#include<netinet/in.h>
#include<errno.h>
#include<netdb.h>
#include<stdio.h> //For standard things
#include<stdlib.h>    //malloc
#include<string.h>    //strlen
#include<netinet/ip_icmp.h>   //Provides declarations for icmp header
#include<netinet/udp.h>   //Provides declarations for udp header
#include<netinet/tcp.h>   //Provides declarations for tcp header
#include<netinet/ip.h>    //Provides declarations for ip header
#include<netinet/if_ether.h>  //For ETH_P_ALL
#include<net/ethernet.h>  //For ether_header
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{

int soket;

soket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));

if (soket<0)
{

    printf("Error creating socket\n");
    return -1;
}
else 
    printf("\Socket OK\n\n");

unsigned char *buffer = (unsigned char *) malloc(65536);
memset (buffer,0,65536);
struct sockaddr saddr;
struct sockaddr_in source,dest;
int saddr_len = sizeof (saddr);
int dest_len = sizeof (dest);

source.sin_family = AF_INET;
dest.sin_family = AF_INET;
// Port numbers
source.sin_port = htons(53);
dest.sin_port = htons(53);
// IP addresses
source.sin_addr.s_addr = inet_addr ("192.168.1.5");
dest.sin_addr.s_addr = inet_addr ("192.168.1.3");

setsockopt(soket, SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1 
);


if (bind(soket, (struct sockaddr*) &source, sizeof(source)) < 0) {
perror("bind failed\n");
close(soket);
return -1;
}
if (recvfrom(soket,buffer,65536,0,(struct sockaddr *)&dest,&dest_len)<0)
{
    printf ("Paket nije primljen\n");
    return -1;
}

else
    printf ("Paket je primljen\n\n");
fflush (stdin);

//EXTRACTING THE IP HEADER
unsigned short iphdrlen;
struct iphdr *ip = (struct iphdr*)(buffer + sizeof(struct ethhdr));
memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = ip->saddr;
memset(&dest, 0, sizeof(dest));
dest.sin_addr.s_addr = ip->daddr;

printf ("Changing TTL:\n\n");

ip->ttl=0;

if(sendto(soket, &ip, sizeof (ip), 0, (struct sockaddr *)&dest, 
sizeof(dest)) < 0)
// Verify
{
perror("Error sending\n");
exit(-1);
}
else
{
printf("Sending OK\n");
sleep(2);
} 

close(soket);
return 0;
}

What is wrong with this code and arguments for sendto()? Can anyone help, please?

Two issues (with how sendto() is called):

  1. When you define

     struct iphdr *ip 

    then

     sizeof(ip) 

    returns the size of a pointer.

    What you want is the size of struct iphdr when calling sendto() .

  2. As ip is a pointer already, just pass it, do not pass its address.


From the docs :

 ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len); 

...

message

Points to a buffer containing the message to be sent.

length

Specifies the size of the message in bytes.


So to fix this change

  ... sendto(soket, &ip, sizeof (ip), ....

to be

  ... sendto(soket, ip, sizeof (*ip), ....

or (the same) but nicer, as dropping the useless parenthesis

  ... sendto(soket, ip, sizeof *ip, ....

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM