Error with sendto() function: Invalid Argument Error - sockets

I am working on writing a ping CLI program for linux and I have been getting errno 22: invalid argument in the sendto() function. I don't understand why, all the arguments seem to be correct.
Here is where I call the function:
// send echo request
bytesSent = sendto(socketFD, // socket file descriptor
(char*)&packet, PacketSize, // packet and size
0, // flags
(sockaddr*)DestinationAddr, (socklen_t)sizeof(DestinationAddr)); // destination address and size
'packet' looks like this:
(I call initializePacket() in the function where I call sendto())
struct PacketData {
icmphdr header;
char message[PacketSize - sizeof(header)]; // want total size to be 64 bytes
};
PacketData initializePacket(int &transmitted) {
PacketData packet = {};
packet.header.type = ICMP_ECHO; // set ICMP type to Echo
packet.header.un.echo.id = getpid() & 0xFFFF; // set id (ICMP field is 16 bits)
packet.header.checksum = 0; // fixed checksum because data is unchanging
packet.header.un.echo.sequence = transmitted++;
// fill up message
memset(&packet.message, '0', sizeof(packet.message));
packet.message[PacketSize - sizeof(packet.header) - 1] = '\0';
return packet;
}
'DestinationAddr' is this:
// variables needed to store IP Address
addrinfo* result;
sockaddr_in* DestinationAddr;
char ipString[INET_ADDRSTRLEN];
// get IP Address and store in result (passed by reference)
if (getIPAddress(argv[1], result) != 0) {
std::cout << "Invalid IP Address. Terminating ...\n";
exit(EXIT_FAILURE);
}
else {
DestinationAddr = (sockaddr_in*)result->ai_addr; // get struct from resulting linked list
void* address;
address = &DestinationAddr->sin_addr; // store IP Address
inet_ntop(result->ai_family, address, ipString, sizeof(ipString)); // convert binary IP to string
std::cout << "IP: " << ipString << std::endl;
}
And the getIPAddress() function is:
int getIPAddress(char* hostName, addrinfo* &result) {
addrinfo tempStruct = {0};
tempStruct.ai_family = AF_INET; // want IPv4
tempStruct.ai_socktype = SOCK_DGRAM; // set socket type to datagram
tempStruct.ai_flags = AI_PASSIVE; // fill in IP automatically
// get and validate IP address
return (getaddrinfo(hostName, &PortNo, &tempStruct, &result));
}
PortNo is defined as: const char PortNo = '0';

According to documentation icmp:
A user protocol may receive ICMP packets for all local sockets by opening a raw socket with the protocol IPPROTO_ICMP.
So, try creating your socket like that:
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
And, if you encounter EPERM error, then run your program as root.

Related

recvfrom returning errno 14 in debug mode with GDB

I have a code something like this.
where recvfrom works fine if i run the code normally. but when i run the code with GDB, recvfrom doesn't wait for 2 seconds and instantly throwing errno 14.
==
char buf[sizeof(FSME_START)] = { 0 };
/* open socket */
fsm_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fsm_fd < 0)
{
perror("socket");
exit(1);
}
const struct sockaddr_in remote_addr = { .sin_family = AF_INET };
//socklen_t addrlen = sizeof(struct sockaddr);
socklen_t addrlen = sizeof(client_addr);
struct timeval tv = { .tv_sec = 2,
.tv_usec = 0};
/* set initial 1s recv timeout */
int ret = setsockopt(fsm_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
if (ret < 0)
{
perror("setsockopt");
exit(1);
}
while (1)
{
const struct iovec iov = { .iov_base = (void*)FSME_START,
.iov_len = sizeof(FSME_START) };
// Send the START packet (once/sec) to the FSM-E until we get
// receive a START message back based on 1sec timeout set above.
fsm_dp_send(&iov,1,0);
ret = recvfrom(fsm_fd, (char *)buf, MAX_BUFSIZE,
MSG_WAITALL, (struct sockaddr *)&client_addr, &addrlen);
====
I tried passing client_addr and addrlen both parameters as NULL but no success. But strangely this code works if run without GDB.
Any suggestions
looks like there is an error with the size of msg i was passing with recvfrom but it was weird that one version of gdb and and even compiler was hiding this error. This error was visible only with older gdb version. Later on when i passed the correct size of the buffer, it was passing.

sendto() returning -1 in server

int main()
{
int servsocket,clientsocket;
struct sockaddr_in server,client;
FILE *file;
char filename[100];
char buf[1024];
servsocket=socket(AF_INET,SOCK_DGRAM,0);
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(6003);
server.sin_family=AF_INET;
bind(servsocket,(struct sockaddr *) &server,sizeof(server) );
while(1){
int clientsize=0;
printf("Waiting for file requests \n");
recvfrom(servsocket,filename,sizeof(filename),0,(struct sockaddr *)&client,&clientsize);
file=fopen(filename,"r");
int size=0;
do
{
size=fread(buf,1,sizeof(buf),file);
printf("%d bytes read \n",size);
int sentbytes= sendto(servsocket,(const char *)buf,size,0, (struct sockaddr *) &client,sizeof(client));
printf("%d bytes sent ",sentbytes);
}while(size==sizeof(buf));
}
}
I am trying to make a simple program for file transfer using UDP. The problem is that sendto() always returns -1. This is the code for server.
There are quite a few issues with your code. The one you're seeing is that you're not filling in the variable client properly: the clientsize parameter is used for both input and output by the recvfrom system call, so you need to initialise it to the size of the client structure:
int clientsize = sizeof(struct sockaddr_in);
Another issue is that you're not 0-terminating the filename string:
n = recvfrom(...);
filename[n] = '\0';
Finally, you're not testing for errors (bind, recvfrom, sendto, etc.). This will get you into trouble, I promise.

How to use getaddrinfo()?

Im trying to make a simple program that takes in a string like www.google.com and returns the ip address...
What i have so far:
char* hostname = new char[www.size()+1];
std::copy(www.begin(), www.end(), hostname);
hostname[www.size()] = '\0';
struct addrinfo new_addr, *res;
getaddrinfo(www.c_str(), SERVICE.c_str(), &new_addr, &res);
cout << new_addr.ai_addr;
What are the 3rd of 4th parameters supposed to do? Does the getaddrinfo function modify the new_addr structure or what? I dont really understand the msdn documentation. After the hostname is resolved I want to connect a socket to it.
What if i leave the third parameter nullified?
Heres the code i developed so far.
char* hostname = new char[www.size()+1];
copy(www.begin(), www.end(), hostname);
hostname[www.size()] = '\0';
struct addrinfo *res;
struct in_addr addr;
getaddrinfo(hostname, NULL, 0, &res);
addr.S_un = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.S_un;
server.sin_addr.s_addr = inet_addr(inet_ntoa(addr));
server.sin_port = htons(portno);
freeaddrinfo(res);
delete []hostname;
server.sin is declared elsewhere that i use to fill a socket in another method of my sockets class.
The MSDN documentation is very detailed and explains exactly what the various parameters are for. The third parameter lets you specify the type of socket that will be used with the results of the lookup. This allies the results to be optimized as needed. The fourth parameter returns the actual results. The documentation also contains a full example of how to use the function. So what example is unclear about what the documentation says?
Try this:
struct addrinfo hints = {0};
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC; // IPv4 and IPv6 allowed
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *res = NULL;
if (getaddrinfo(www.c_str(), SERVICE.c_str(), &hints, &res) == 0)
{
TCHAR szIPAddr[64];
DWORD szIPAddrLen;
SOCKET skt;
struct addrinfo *addr = res;
do
{
skt = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (skt == INVALID_SOCKET)
cout << "Unable to create socket, error " << WSAGetLastError() << endl;
else
{
szIPAddrLen = 64;
WSAAddressToString(addr->ai_addr, addr->ai_addrlen, NULL, szIPAddr, &szIPAddrLen);
cout << "Connecting to " << szIPAddr << " ..." << endl;
if (connect(skt, addr->ai_addr, addr->ai_addrlen) == 0)
{
cout << "Connected!" << endl;
break;
}
cout << "Unable to connect, error " << WSAGetLastError() << endl;
closesocket(skt);
skt = INVALID_SOCKET;
}
addr = addr->ai_next;
}
while (addr);
freeaddrinfo(res);
if (skt != INVALID_SOCKET)
{
// use skt as needed...
closesocket(skt);
}
}

why does my connect fail?

I am trying to do basic socket calls, and trying to connect to google.com but the connect call always fails and returns -1. Any reason why it must be failing
int main()
{
int sockfd;
struct addrinfo *ai;
char port[4];
if(sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
printf("socket return -1");
}
sprintf(port, "%d", 80);
if(getaddrinfo("www.google.com", port, NULL, &ai) < 0)
printf("-2\n");
if(connect(sockfd, ai->ai_addr, sizeof(*ai->ai_addr)) < 0)
printf("connect failed -1");
}
I believe the problem is with the parameter sizeof(*ai->ai_addr). ai->ai_addr returns a pointer to a sockaddr struct, and dereferencing brings you to the struct itself.
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
sizeof is returning the size of the entire struct, not the length of the address.
Try making the argument ai->ai_addrlen instead.

IPv6 raw socket programming with native C

I am working on IPv6 and need to craft an IPv6 packet from scratch and put it into a buffer. Unfortunately I do not have much experience with C. From a tutorial I have successfully done the same thing with IPv4 by defining
struct ipheader {
unsigned char iph_ihl:5, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
/* Structure of a TCP header */
struct tcpheader {
unsigned short int tcph_srcport;
unsigned short int tcph_destport;
unsigned int tcph_seqnum;
unsigned int tcph_acknum;
unsigned char tcph_reserved:4, tcph_offset:4;
// unsigned char tcph_flags;
unsigned int
tcp_res1:4, /*little-endian*/
tcph_hlen:4, /*length of tcp header in 32-bit words*/
tcph_fin:1, /*Finish flag "fin"*/
tcph_syn:1, /*Synchronize sequence numbers to start a connection*/
tcph_rst:1, /*Reset flag */
tcph_psh:1, /*Push, sends data to the application*/
tcph_ack:1, /*acknowledge*/
tcph_urg:1, /*urgent pointer*/
tcph_res2:2;
unsigned short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
and fill the packet content in like this:
// IP structure
ip->iph_ihl = 5;
ip->iph_ver = 6;
ip->iph_tos = 16;
ip->iph_len = sizeof (struct ipheader) + sizeof (struct tcpheader);
ip->iph_ident = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = 6; // TCP
ip->iph_chksum = 0; // Done by kernel
// Source IP, modify as needed, spoofed, we accept through command line argument
ip->iph_sourceip = inet_addr("1922.168.1.128");
// Destination IP, modify as needed, but here we accept through command line argument
ip->iph_destip = inet_addr(1922.168.1.1);
// The TCP structure. The source port, spoofed, we accept through the command line
tcp->tcph_srcport = htons(atoi("1024"));
// The destination port, we accept through command line
tcp->tcph_destport = htons(atoi("4201"));
tcp->tcph_seqnum = htons(1);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
// IP checksum calculation
ip->iph_chksum = csum((unsigned short *) buffer, (sizeof (struct ipheader) + sizeof (struct tcpheader)));
However for IPv6 I have not find a similar way. What I already found is this struct from IETF,
struct ip6_hdr {
union {
struct ip6_hdrctl {
uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, 20 bits
flow-ID */
uint16_t ip6_un1_plen; /* payload length */
uint8_t ip6_un1_nxt; /* next header */
uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits
tclass */
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
};
But I did not know how to fill in the information, for example, how to send a TCP/SYN from 2001:220:806:22:aacc:ff:fe00:1 port 1024 to 2001:220:806:21::4 port 1025?
Could anybody help me or is there any references?
Thank you vere much then.
this is what I have done so far, however there are mismatch between the code and the real packet captured by Wireshark (as discussed in comments below). I'm not sure it is possible to post a long code in comment section, so I just edit my question.
Anyone can help?
#define PCKT_LEN 2000
int main(void) {
unsigned char buffer[PCKT_LEN];
int s;
struct sockaddr_in6 din;
struct ipv6_header *ip = (struct ipv6_header *) buffer;
struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof (struct ipv6_header));
memset(buffer, 0, PCKT_LEN);
din.sin6_family = AF_INET6;
din.sin6_port = htons(0);
inet_pton(AF_INET6, "::1", &(din.sin6_addr)); // For routing
ip->version = 6;
ip->traffic_class = 0;
ip->flow_label = 0;
ip->length = 40;
ip->next_header = 6;
ip->hop_limit = 64;
inet_pton(AF_INET6, "::1", &(ip->dst)); // IPv6
inet_pton(AF_INET6, "::1", &(ip->src)); // IPv6
tcp->tcph_srcport = htons(atoi("11111"));
tcp->tcph_destport = htons(atoi("13"));
tcp->tcph_seqnum = htons(0);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32752);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
if (s < 0) {
perror("socket()");
return 1;
}
unsigned short int packet_len = sizeof (struct ipv6_header) + sizeof (struct tcpheader);
if (sendto(s, buffer, packet_len, 0, (struct sockaddr*) &din, sizeof (din)) == -1) {
perror("sendto()");
close(s);
return 1;
}
close(s);
return 0;
}
Maybe this article can help you getting started?
Edit:
Using the wikipedia article linked above I made this structure (without knowing what some of the fields means):
struct ipv6_header
{
unsigned int
version : 4,
traffic_class : 8,
flow_label : 20;
uint16_t length;
uint8_t next_header;
uint8_t hop_limit;
struct in6_addr src;
struct in6_addr dst;
};
It's no different than how the header-struct was made for IPv4 in your example. Just create a struct containing the fields, in the right order and in the right size, and fill it with the right values.
Just do the same for the TCP headers.
Unfortunately the ipv6 RFCs don't provide the same raw socket interface that you get with ipv4. From what i've seen to create ipv6 packets you have to go a level deeper and use an AF_PACKET socket to send an ethernet frame including your ipv6 packet.