Socket programming: sendto always fails with errno 22 (EINVAL) - c

I am always getting no bytes sent, with an errno of 22 (EINVAL, Invalid Argument) with this code. The destination_host is set elsewhere and known to be valid, so I really don't see what is going on. MAXMSGSIZE is 1000. No errors, or warnings. I am compiling with -Wall -Werror -pedantic
char *data_rec;
u_int data_len;
int sockfd;
uint16_t *ns;
struct sockaddr_in address;
struct sockaddr *addr;
char *ip;
int i;
int errno;
int bytes_sent;
data_len = MAXMSGSIZE;
data_rec = malloc(sizeof(char)*MAXMSGSIZE);
ns = malloc(MAXMSGSIZE*sizeof(uint16_t));
ip = malloc(MAXMSGSIZE*sizeof(char));
data_rec = "some random test stuff";
sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd<0) {
printf("socket() failed\n");
}
inet_ntop(AF_INET,destination_host->h_addr,ip,MAXMSGSIZE);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(theirPort);
address.sin_addr.s_addr = (unsigned long)ip;
addr = (struct sockaddr*)&address;
bind(sockfd,addr,sizeof(address));
/*Convert the message to uint16_t*/
for(i=0; i<MAXMSGSIZE; i++) {
ns[i] = htons(data_rec[i]);
}
/* send the message */
bytes_sent = sendto(sockfd, ns, data_len, MSG_DONTWAIT, addr, sizeof(addr));
if(bytes_sent == -1) {
printf("Error sending: %i\n",errno);
}

You're giving the wrong size for the address. addr is really a struct sockaddr_in, not a struct sockaddr.
Change the last parameter of sendto to sizeof(address)

inet_ntop probably isn't what you want - it converts from network (i.e. wire) format into presentation format (i.e. "1.2.3.4"). Try:
address.sin_addr.s_addr = *((unsigned long *)destination_host->h_addr);

You have:
bytes_sent = sendto(sockfd, ns, data_len, MSG_DONTWAIT, addr, sizeof(addr));
Because sizeof(addr) == 4 (or 8), use sizeof(*addr).

Related

Strange behaviour while sending broadcast message

I have two programs: client and server. They're trying to find themselves in local network using broadcast.
Client sends simple packet on broadcast with SERVER_PORT (known before) and server prints info about connection, but when i tried this solution I found some strange behavaiour, when I uncomment last two lines of server.c server prints (one custom struct)
Connection from: 0.0.0.0 on port: 0
after commenting those lines everything works properly, am I missing something?
server.c
int broadcast_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_addr.s_addr = INADDR_ANY;
broadcast_addr.sin_port = htons(SERVER_PORT);
broadcast_addr.sin_family = AF_INET;
if (bind(broadcast_socket, (struct sockaddr *)&broadcast_addr,
sizeof(broadcast_addr))) {
perror("bind");
}
struct sockaddr_in recv_addr;
char buf[MAX_PACKET_SIZE];
socklen_t len;
if (recvfrom(broadcast_socket, buf, MAX_PACKET_SIZE, 0,
(struct sockaddr *)&recv_addr, &len) < 0) {
perror("recvfrom");
}
printf("Connection from: %s on port: %d\nMessage: %s\n",
inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port), buf);
/* struct network_packet packet; */
/* struct sockaddr_in my_addr; */
client.c
int find_server(struct sockaddr_in *out) {
struct sockaddr_in broadcast;
struct network_packet packet;
int yes = 1;
socklen_t len;
broadcast.sin_addr.s_addr = INADDR_ANY;
broadcast.sin_port = htons(CLIENT_PORT);
broadcast.sin_family = AF_INET;
int socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bind(socket_fd, (struct sockaddr *)&broadcast, sizeof(broadcast))) {
perror("bind");
}
if (get_broadcast_addr(&broadcast.sin_addr)) {
return -1;
}
printf("Target address: %s\n", inet_ntoa(broadcast.sin_addr));
broadcast.sin_port = htons(SERVER_PORT);
broadcast.sin_family = AF_INET;
setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
char buf[10] = "test";
sendto(socket_fd, buf, strlen(buf), 0, (struct sockaddr *)&broadcast,
sizeof(broadcast));
if (recvfrom(socket_fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&broadcast, &len) < 0) {
perror("recvfrom");
}
struct sockaddr_in *sa = (struct sockaddr_in *)packet.data;
memcpy(out, sa, packet.header.packet_length);
return 0;
}
struct network_packet_header {
enum network_packet_type type;
int packet_length;
};
struct network_packet {
struct network_packet_header header;
unsigned char data[MAX_DATA_LENGTH];
};
You have to initialize the variable you pass as recvfrom's addrlen to the size of the address struct.

getaddrinfo: Address family for nodename not supported in MacOS

I keep getting this error getaddrinfo failed: Undefined error: 0. I am trying to compile my code on MacOS using the command gcc mac-client-2.c -o client. The program is compiling successfully, but when I run the executable, the error above shows up. I searched google and SO, the closest thing I could find to the problem was this link Undefined reference to getaddrinfo But, this link talks about the issue for windows, not for MacOS.
I am pasting my code as it is below. Could anyone please help.
EDIT: Got a more descriptive error saying getaddrinfo: Address family for nodename not supported
// Client side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h> //Provides declarations for udp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netdb.h>
#include <errno.h>
#define PORT 12345
#define MAXLINE 1024
//standard checksum function
unsigned short csum(unsigned short *ptr, int nbytes)
{
register long sum;
unsigned short oddbyte;
register short answer;
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_char *)&oddbyte) = *(u_char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
answer = (short)~sum;
return (answer);
}
// struct ip
// {
// unsigned char ihl;
// unsigned char version;
// unsigned char tos;
// unsigned short int tot_len;
// unsigned short int id;
// unsigned short int frag_off;
// unsigned char ttl;
// unsigned char protocol;
// unsigned short int check;
// unsigned int saddr;
// unsigned int daddr;
// };
//required for udp
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
// Driver code
int main()
{
int errno;
int sockfd, raw_sock;
char buffer[MAXLINE];
int port;
char *hello = "Client Hello";
char *done = "Client Done";
char source_ip[32];
struct sockaddr_in servaddr;
struct sockaddr_in local_address;
int addr_size = sizeof(local_address);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
if ((raw_sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) //PF_PACKET -- 0 can be replaced with IPPROTO_UDP (gives same outcome)
{
perror("Raw Socket creation failed");
exit(EXIT_FAILURE);
}
setuid(getuid());
//********** Part with getaddrinfo//*********
int stat;
struct addrinfo hints;
struct addrinfo *info, *ptr;
struct sockaddr_in *client_address;
char clientIPstr[16];
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; //put NULL in getaddrinfo
//AI_PASSIVE allows to assign address of local host
//No hardcoding needed
if ((stat = getaddrinfo(NULL, "0", &hints, &info) != 0))
{
perror("getaddrinfo failed");
exit(EXIT_FAILURE);
}
for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
{
if (ptr->ai_family == AF_INET)
{
client_address = (struct sockaddr_in *)ptr->ai_addr;
inet_ntop(AF_INET, &(client_address->sin_addr), clientIPstr, sizeof(clientIPstr));
printf("%s\n", clientIPstr);
int x = bind(sockfd, ptr->ai_addr, ptr->ai_addrlen);
//int y = bind(raw_sock, ptr->ai_addr, ptr->ai_addrlen);
//printf("Bind Status: %d, %d\n", x, y);
break;
}
}
///************///************////*****************
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET; //IPv4
servaddr.sin_port = htons(PORT); //8080
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
int len, n;
//send hello
sendto(sockfd, (const char *)hello, strlen(hello),
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
//fetch the port number and store in local address -- dont forget to convert using ntohs
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size);
port = ntohs(local_address.sin_port);
printf("My Port: %u\n", port);
//receive hello
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
/* ---------------------Packet spoofing code starts here----------------------- */
printf("Creating spoofed packet\n");
char spoof_packet[4096];
char *data, *pseudogram;
int one = 1;
const int *val = &one;
memset(spoof_packet, 0, 4096);
//strcpy(clientIPstr, "127.0.0.1");
struct ip *iph = (struct ip *)spoof_packet;
struct udphdr *udph = (struct udphdr *)(spoof_packet + sizeof(struct ip));
struct pseudo_header psh;
struct sockaddr_in my_sockaddress;
my_sockaddress.sin_addr.s_addr = inet_addr(clientIPstr); //just set this to htonl(INADDR_ANY); instead of 127.0.0.1
//struct sockaddr_in sin;
data = spoof_packet + sizeof(struct ip) + sizeof(struct udphdr);
strcpy(data, "SPOOFED CLIENT DONE");
strcpy(source_ip, clientIPstr);
//IP Header
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(struct ip) + sizeof(struct udphdr) + strlen(data);
iph->ip_id = htonl(54321); //Id of this packet
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_UDP;
iph->ip_sum = 0; //Set to 0 before calculating checksum
iph->ip_src = my_sockaddress.sin_addr; //Spoof the source ip address
iph->ip_dst = servaddr.sin_addr; //value should be of type in_addr
iph->ip_sum = csum((unsigned short *)spoof_packet, iph->ip_len); //ip checksum
//UDP header
udph->uh_sport = local_address.sin_port;
udph->uh_dport = htons(PORT);
udph->uh_ulen = htons(8 + strlen(data)); //header size
udph->uh_sum = 0; //leave checksum 0 now, filled later by pseudo header
/* Stackoverflow - The IPv4 layer generates an IP header when sending a packet unless the IP_HDRINCL socket
option is enabled on the socket. When it is enabled, the packet must contain an IP header.
For receiving the IP header is always included in the packet.*/
if (setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
//UDP checksum using the pseudo header
psh.source_address = inet_addr(source_ip);
psh.dest_address = servaddr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data));
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram, (char *)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), udph, sizeof(struct udphdr) + strlen(data));
udph->uh_sum = csum((unsigned short *)pseudogram, psize);
printf("%s\n", spoof_packet);
printf("Sending spoofed packet.......");
int k;
//send spoofed Done
k = sendto(raw_sock, spoof_packet, iph->ip_len,
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
if (k == -1)
{
printf("Error sending: %i\n", errno);
}
printf("%d\n", k);
fflush(stdout);
/*---------------------------------END------------------------------------------*/
//send Done
// sendto(sockfd, (const char *)done, strlen(done),
// 0, (const struct sockaddr *)&servaddr,
// sizeof(servaddr));
//receive done
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
//close(sockfd);
return 0;
}
/* get ip and port number:
char myIP[16];
struct sockaddr_in local_address;
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size); //get socket info
inet_ntop(AF_INET, &local_address.sin_addr, myIP, sizeof(myIP)); // get IP info
int myPort = ntohs(local_address.sin_port); //get port info
printf("Local ip address: %s\n", myIP);
printf("Local port : %u\n", myPort);
*/
Your struct addrinfo hints; is uninitialized, and has junk in the members you did not explicitly write to. Change it to struct addrinfo hints = { 0 }; or put all the hints in designated initializers rather than assignments after creation of an uninitialized object.
So, I forgot to post back here. I had figured out the solution. Its basically the same as the above post. Just added the line memset(&hints,0,sizeof(hints)) and everything worked perfectly.

Error: Bad address when using sendto() in raw sockets

I'm writing a simple network application and I need to craft a UDP packet and send it to a specific host.
int main(void){
// Message to be sent.
char message[] = "This is something";
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if(sockfd < 0){
perror("Error creating socket");
exit(1);
}
struct sockaddr_in this, other;
this.sin_family = AF_INET;
other.sin_family = AF_INET;
this.sin_port = htons(8080);
other.sin_port = htons(8000);
this.sin_addr.s_addr = INADDR_ANY;
other.sin_addr.s_addr = inet_addr("10.11.4.99");
if(bind(sockfd, (struct sockaddr *)&this, sizeof(this)) < 0){
printf("Bind failed\n");
exit(1);
}
char packet[64] = {0};
struct udphdr *udph = (struct udphdr *) packet;
strcpy(packet + sizeof(struct udphdr), message);
udph->uh_sport = htons(8080);
udph->uh_dport = htons(8000);
udph->uh_ulen = htons(sizeof(struct udphdr) + sizeof(message));
udph->uh_sum = 0;
if(sendto(sockfd, packet, udph->uh_ulen, 0, (struct sockaddr *) &other, sizeof(other)) < 0)
perror("Error");
else
printf("Packet sent successfully\n");
close(sockfd);
return 0;
}
Everything is working fine till the call to sendto(). The sendto() is giving "Bad address". can anyone point me where I'm going wrong? Is there any problem with binding a port to a raw socket?
The code transform the length of the messag (udph->uh_len) to network byte order (htons). This is not needed, as the parameter type of size_t. Only port number (in sockaddr structures) need the htons conversion.
udph->uh_ulen = sizeof(struct udphdr) + sizeof(message);
Current code produce large number (>8000) in uh_ulen, causing the send to fail.

Cannot receive the message of udp broadcast

I wrote a simple UDP broadcast sample. When I write the IP address to the struct sockaddr_in with inet_addr("192.168.152.128"), I cannot receive the message from another UDP broadcast program with the broadcast 192.168.152.255. But when I write htonl(INADDR_ANY), it can receive the message. Why could that be?
This the code:
#include"myhead.h"
char rbuf[50];
char wbuf[50];
int main()
{
int udp, size, len, opt = 1;
struct sockaddr_in laddr;
struct sockaddr_in raddr;
laddr.sin_family = AF_INET;
laddr.sin_port = htons(8888);
laddr.sin_addr.s_addr = htonl(INADDR_ANY);
//when i write inet_addr("192.168.152.128")
//it cannot receive the message.
size = sizeof(struct sockaddr_in);
udp = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(udp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
bind(udp, (struct sockaddr*)&laddr, size);
len = sizeof(struct sockaddr);
while (1)
{
recvfrom(udp, rbuf, 50, 0, (struct sockaddr*)&raddr, &len);
printf("%s\n", rbuf);
bzero(rbuf, 50);
}
}

Simple messaging application...getting errno 14: bad address

I am writing a simple messaging application in C using sockets. When I use function recvfrom, it returns -1 and sets errno = 14 which is Bad address (which I am printing at the end).
The strange thing is that it still reads from the socket and gets the correct message. That is, the application is working perfectly and as expected except for that error.
My question is this: Why do you think I am getting this error? I cannot think of any reason. I was using inet_pton to set peer->sin_addr but I was getting the same error.
// socket file descriptor to send data through
int recv_sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
// fill in the peer's address, loopback in this case
struct sockaddr_in *peer = malloc(sizeof(struct sockaddr_in));
peer->sin_family = AF_INET;
peer->sin_port = htons(11110);
char *new = &(peer->sin_addr);
new[0] = 127;
new[1] = 0;
new[2] = 0;
new[3] = 1;
for (int i = 0; i < 8; i++) {
peer->sin_zero[i] = NULL;
}
bind(recv_sock_fd, peer, sizeof(struct sockaddr_in));
// check to see if the socket has any data...code removed
char buff[32] = {0};
errno = 0;
int bytes_received = recvfrom(recv_sock_fd, buff, sizeof(buff), NULL, (struct sockaddr *)peer, sizeof(struct sockaddr_in));
printf("Bytes recieved: %d: %d : %s\n", bytes_received, errno, strerror(errno));
Look at the signature of recvfrom(2):
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
Last argument is an address, while you are giving it a plain integer.
Then you're building of the IP address is wrong. Do use inet_pton(3), that's what it's for. Also check the return value of the bind(2), it's surely failing now.

Resources