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

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.

Related

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);
}
}

UDP packets not delivered - recvfrom() never returns

I have setup a UDP receiver, as:
int rx_socket;
struct sockaddr_in my_addr;
struct sockaddr_in rem_addr;
socklen_t addrlen = sizeof(rem_addr);
rx_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(9900);
rc = bind(rx_socket, (struct sockaddr *) &(my_addr), sizeof(my_addr));
if (!rc) {
printf("BIND SUCCESSFULL\n");
}
char buf[250];
while(1) {
printf("WAITING\n");
recvfrom(rx_socket, buf, sizeof(buf), 0, (struct sockaddr *)&rem_addr, &addrlen);
printf("RECEIVED\n");
}
The recvfrom() never returns. I have done some Wireshark analysis, and it indicates the packets are there:
Summary:
User Datagram Protocol, Src Port: 57506 (57506), Dst Port: iua (9900)
Checksum: 0x14a2 [validation disabled]
Data (8 bytes)
Any help will be appreciated.
EDIT:
An interesting observation is that the source, which is a DSP fails to send packets, i.e., sendto() returns -1, until I ping to it, from destination. Right after the ping, the source can start transmitting packets.
EDIT 2:
Here is the sender's code:
int fd;
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(9900);
inet_aton("10.0.201.102", &(my_addr.sin_addr));
char buf[250];
for (;;) {
int bytesSent = sendto(fd, buf, 8, 0,
(struct sockaddr *) &(my_addr), sizeof(my_addr));
printf("sent: %d bytes\n", bytesSent);
sleep(1000);
}
So the problem turned out to be with virtualbox. My sender is on host, but receiver is on a virtual machine. If I run the receiver on the host as well, UDP packets are being received.

Why raw socket sends all packets to loopback?

I have a very simple code below. When i run it on Debian 7, this code always sends all packets via 127.0.0.1 interface. But i want it sends it via 192.168.0.103. Where am i wrong?
I searched the solution in Google until past 16 hours but didn't find the answer :(.
Sure, i can fix it via routing table. But ping and traceroute works perfect. Why my code doesn't work?
int rawSocket;
char buffer[PACKET_LENGTH];
struct IPHeader *ipHeader = (struct IPHeader *) buffer;
struct UDPHeader *udpHeader = (struct UDPHeader *) (buffer + sizeof(struct IPHeader));
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PACKET_LENGTH);
rawSocket = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if (rawSocket < 0) {
printf("socket() error");
exit(-1);
}
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
sin.sin_port = htons(atoi(srcPort));
din.sin_port = htons(atoi(dstPort));
sin.sin_addr.s_addr = inet_addr(realSrcIP);
din.sin_addr.s_addr = inet_addr(dstIP);
ipHeader->iph_ihl = 5;
ipHeader->iph_ver = 4;
ipHeader->iph_tos = 16; // Low delay
ipHeader->iph_len = sizeof(struct IPHeader) + sizeof(struct UDPHeader);
ipHeader->iph_ident = htons(54321);
ipHeader->iph_ttl = 64; // hops
ipHeader->iph_protocol = 17; // UDP
// spoof please lol =P
ipHeader->iph_sourceip = inet_addr(srcIP);
ipHeader->iph_destip = inet_addr(dstIP);
udpHeader->udph_srcport = htons(atoi(srcPort));
udpHeader->udph_destport = htons(atoi(dstPort));
udpHeader->udph_len = htons(sizeof(struct UDPHeader));
ipHeader->iph_chksum = csum((unsigned short *)buffer, sizeof(struct IPHeader) + sizeof(struct UDPHeader));
if(setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if (setsockopt(rawSocket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
printf("HUJ\n");
}
int errorCode = sendto(rawSocket, buffer, ipHeader->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin));
if(errorCode < 0)
{
perror("sendto() error");
exit(-1);
}
close(rawSocket);
I don't think you're setting ifr correctly.
You need to call ioctl(rawsocket, SIOCGIFINDEX, &ifr) to set the index of the device. The name is not enough.
Your index is left as zero which is the first device which happens to be loopback.
Here's a snippet of code from C Language Examples of IPv4 and IPv6 Raw Sockets for Linux:
// Use ioctl() to look up interface index which we will use to
// bind socket descriptor sd to specified interface with setsockopt() since
// none of the other arguments of sendto() specify which interface to use.
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl (sd, SIOCGIFINDEX, &ifr) < 0) {
perror ("ioctl() failed to find interface ");
return (EXIT_FAILURE);
}
There may be other problems (your code is too big) try running/modifying the examples in the link above. Hopefully they are not outdated.

Tracing a client-server transaction - sockets in c

I am very new to socket programming, I want to simulate a client-server transaction. So for my client sent packet, I declare a sock = socket(AF_INET, SOCK_STREAM, 0), a SOCKADDR_IN sin, I bind them through bind(sock, (SOCKADDR*) &sin, sizeof(sin)), then, after declaring a classic struct ip header, and hydrating a allocating some memory to struct iphdr * ip, I finally send the packet via ip
sent_packet = sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct tcphdr),
0, (struct sockaddr *) sin, sizeof(struct sockaddr));//sent_packet is an int, I use also a TCP header struct, packet is the pointer that stores the ip and tcp data
This seems to work. But now, I want to trace the sent packet, so I use a server side file to declare again a sock, I declare a SOCKADDR_IN client_sin I accept the connection of the client via accept(sock, (SOCKADDR*)&client_sin, &recsize);, but it seems that my packet is not received ? I use for that recv(sock, buffer, 32, 0) != SOCKET_ERROR to catch the packets, (of course I launched the server program before the client one). Am going completely wrong ?
Edit on the client side (to shorten, I didn't mention the included libraries, the `struct` `iphdr`, `tcphdr`, the `in_chksum function`, as well I didn't hydrate the tcp header, for now I just want to test)
#define PORT 23
int sendmeifyoucan(SOCKET sock, SOCKADDR_IN * sin , int size ){
struct iphdr * ip = (struct iphdr *)malloc(sizeof(struct iphdr *));
struct tcphdr * tcp;
char * packet;
int psize=0, status = 1;
printf("%d I am lost in the web ",status);
packet = malloc(sizeof(struct iphdr)+ sizeof(struct tcphdr));
memset(packet, 0, sizeof(struct iphdr) + sizeof(struct tcphdr));
sin->sin_addr.s_addr = inet_addr("127.0.0.1");
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + psize);
ip->ihl = 5;
ip->version = 4;
ip->ttl = 255;
ip->tos = 0;
ip->frag_off = 0;
ip->protocol = IPPROTO_ICMP;
ip->saddr = sin->sin_addr.s_addr;
ip->daddr = sin->sin_addr.s_addr;
ip->check = in_chksum((u_short *)ip, sizeof(struct iphdr));
status = sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct tcphdr),
0, (struct sockaddr *) sin, sizeof(struct sockaddr));
free(packet);
return 0;
}
int main(void)
{
int erreur = 0;
SOCKADDR_IN sin;
SOCKET sock;
SOCKADDR_IN csin;
SOCKET csock;
int sock_err;
if(!erreur)
{
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock != INVALID_SOCKET)
{
printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);
int size = 0;
/* Configuration */
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
/* Listage du port */
sendmeifyoucan(sock, &sin,size);
printf("Fermeture de la socket client\n");
closesocket(csock);
printf("Fermeture de la socket serveur\n");
closesocket(sock);
printf("Fermeture du serveur terminée\n");
}
else
perror("socket");
}
return EXIT_SUCCESS;
}
Edit on the server side
#define PORT 23
int main(void)
{
int erreur = 0;
SOCKET sock;
SOCKADDR_IN sin;
socklen_t recsize = sizeof(sin);
SOCKADDR_IN csin;
char buffer[32] = "";
int sock_err;
if(!erreur)
{
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock != INVALID_SOCKET)
{
printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);
/* Configuration */
csin.sin_addr.s_addr = inet_addr("127.0.0.1");
csin.sin_family = AF_INET;
csin.sin_port = htons(PORT);
sock_err = bind(sock, (SOCKADDR*) &csin, sizeof(csin));
if(sock_err != SOCKET_ERROR)
{
sock_err = listen(sock, 5);
printf("Listage du port %d...\n", PORT);
}
if(sock_err != SOCKET_ERROR)
{
/* Attente pendant laquelle le client se connecte */
printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);
sock = accept(sock, (SOCKADDR*)&sin, &recsize);
}
if(recv(sock, buffer, 32, 0) != SOCKET_ERROR)
{
printf("Recu : %s\n", buffer);
}
else
{
printf("Impossible de se connecter\n");
}
closesocket(sock);
}
else
perror("socket");
}
return EXIT_SUCCESS;
}
You can't use sendto with a SOCK_STREAM socket. Use connect and either send or write instead.
Also, you usually don't use struct iphdr and struct tcphdr in normal socket programming, those are only used with raw ip packets (which sockets aren't).

UDP Socket in C - Setting it up wrong?

I'm working on a project that involves sending various requests to a server through UDP. However, I seem to be setting up the socket entirely wrong, as the server does not respond to any of my requests. We were provided with a server binary to test against, and the code below ellicits no response. Am I setting up the UDP socket correctly? If so, am I somehow using sendto wrong? I have confirmed that I am sending the correct number of bits.
The input for the program is: ./client [URL] [port] [username], and I always test with ./client localhost 8080 user. Here is the struct I am sending and the code.
struct request_login {
int req_type; /* = REQ_LOGIN */
char req_username[32];
} packed;
Code:
struct sockaddr_in sa;
int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd == -1){
printf("Could not create socket.");
exit(EXIT_FAILURE);
}
// Prepare the socket address
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(argv[1]);
// Convert to network order
sa.sin_port = htonl(atoi(argv[2]));
// Assemble and send login request
struct request_login * reqlogin = (struct request_login *) malloc(sizeof(struct request_login));
reqlogin->req_type = REQ_LOGIN;
strcpy(reqlogin->req_username, argv[3]);
int res = sendto(sockfd, reqlogin, sizeof (struct request_login), 0, (struct sockaddr*)&sa, sizeof sa);
free(reqlogin)
Huh?
This:
sa.sin_addr.s_addr = inet_addr(argv[1]);
certainly won't do the right thing if, as you say, argv[1] is typically "localhost". You need to look up the host name, so that you get an IP address. You can only use inet_addr() if the input is a dotted IP address, not a host name.
Look at getaddrinfo().
After re-reading your code a couple of times, I think I know what one cause of the error may be:
sa.sin_port = htonl(atoi(argv[2]));
The port number is a short so you should use htons instead. It's very small and easy to miss.
try this instead:
struct addrinfo hint;
memset(&chk,0,sizeof(chk));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = IPPROTO_UDP;
struct addrinfo* servAddr = NULL;
int ret = getaddrinfo(argv[1],atoi(argv[2]),&hint,&servAddr);
if (-1 == ret)
{
perror("getaddrinfo failed");
exit(EXIT_FAILURE);
}
int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd == -1){
printf("Could not create socket.");
exit(EXIT_FAILURE);
}
// Assemble and send login request
struct request_login reqlogin;
reqlogin.req_type = REQ_LOGIN;
strcpy(reqlogin.req_username, argv[3]);
int res = sendto(sockfd, &reqlogin, sizeof (struct request_login), 0, servAddr->ai_addr, servAddr->ai_addrlen);

Resources