Receive UDP broadcast datagram in C - sockets

I have the following issue.
I need to send broadcast UDP datagram packet and a device that is connected to my local network should reply with another broadcast UDP datagram packet.
So the communication should be like this:
me -> 192.168.0.255 (or 255.255.255.255) : "Who is out there?"
my_device > 192.168.0.255: "It's me... IP:..."
Here a very important condition is that I should use always port 30303 as source and at the same time as a destination port. The devices on the other side can use a random port above 4000 for source port and 30303 port for the Destination port.
The problem is that with my code, I can send UDP broadcast, I can see with Wireshark, that the device answers my call, but I cant manage to make my program to receive the broadcast UDP packet.
here is my source:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>
#include <fcntl.h>
#define DST_PORT 30303
#define SRC_PORT 30303
#define BUFLEN 84
#define IP "192.168.0.255"
int main(int argc, char *argv[]) {
struct sockaddr_in addr, srcaddr;
int fd;
unsigned char buf[BUFLEN];
unsigned char message[]={0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x3a, 0x20, 0x57, 0x68, 0x6f, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x3f, 0x00, 0x0a};
int broadcast=1;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(IP);
addr.sin_port = htons(DST_PORT);
memset(&srcaddr, 0, sizeof(srcaddr));
for(int i=0;i<BUFLEN;i++) buf[i]=0x00;
for(int i=0;i<BUFLEN;i++) printf("0x%x", buf[i]);
printf("\n\033[32mBUFFER CLEARED!\033[0m\n");
srcaddr.sin_family = AF_INET;
srcaddr.sin_addr.s_addr = htonl(INADDR_ANY);
srcaddr.sin_port = htons(SRC_PORT);
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
int slen = sizeof(addr);
if (bind(fd, (struct sockaddr *) &srcaddr, sizeof(srcaddr)) < 0) {
perror("bind");
exit(1);
}
/* connect(fd, (struct sockaddr *) &addr, sizeof(addr)); */
if (sendto(fd, message, strlen(message)+2 , 0 , (struct sockaddr *) &addr, sizeof(addr))==-1)
{
printf("\n\033[31mCouldnt send message!!!\033[0m\n");;
}
else printf("\n\033[32mDATAGRAM SENT!\033[0m\n");
puts("\nI am waiting for DGRAM\n");
slen=sizeof(rcvaddr);
//close(fd);
sleep(1);
//connect(fd, (struct sockaddr *) &addr, sizeof(addr));
recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *) &rcvaddr, &slen);
printf("Recieved!\n");
setlocale(LC_ALL, "");
char temp[4]="\0";
for (int i=0; i<BUFLEN;i++)
{
printf("0x%x ", buf[i]);
}
return 0;
}
What I'm trying to do is:
1. Create socket
2. Change source port to a fixed port number
3. Send UDP broadcast Datagram
4. Receive UDP broadcast Datagram
Unfortunately, I receive the datagram I have to send instead of the one, that my device sends.

Related

Why this program which use BPF and RAW SOCKET just hangs?

GOAL: write a simple packet filter using BPF. The packet filter should allow you to choose the interface.
PROBLEM: if I uncomment the third to last instruction in the code (where there is a call to recvfrom, the execution just hangs and I can't see no output (neither "buffer zeroed" which I should be able to see in the stdout).
QUESTIONS: 1) how can I fix it? 2) why the programs hangs during the execution and doesn't show the first printf output? 3) how can I receive from ANY interface?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/if.h>
#define DEFAULT_IF "wlan0"
/* definisco programma bpf */
/* tcpdump -i lo icmp -dd */
struct sock_filter bpfcode[] = {
{ 0x28, 0, 0, 0x0000000c }, /* (000) ldh [12] */
{ 0x15, 0, 3, 0x00000800 }, /* (001) jeq #0x800 jt 2 jf 5 */
{ 0x30, 0, 0, 0x00000017 }, /* (002) ldb [23] */
{ 0x15, 0, 1, 0x00000001 }, /* (003) jeq #0x1 jt 4 jf 5 */
{ 0x6, 0, 0, 0x00040000 }, /* (004) ret #262144 */
{ 0x6, 0, 0, 0x00000000 }, /* (005) ret #0 */
};
int main(int argc, char *argv[])
{
struct sock_fprog bpf = {
sizeof(bpfcode) / sizeof(struct sock_filter),
bpfcode
};
socklen_t saddr_len = sizeof(struct sockaddr_ll);
struct sockaddr_ll addr;
unsigned char *buffer;
char ifname[IFNAMSIZ];
int ret, sfd, rval;
buffer = calloc(1, 65536);
if (!buffer) {
perror("calloc");
return -1;
}
// prendi nome interfaccia
if (argc > 1)
strcpy(ifname, argv[1]);
else
strcpy(ifname, DEFAULT_IF);
// creazione raw socket
sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sfd < 0) {
perror("socket");
return -1;
}
// attacco filtro alla socket
ret = setsockopt(sfd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
if (ret < 0) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// quando si usa packet socket bisogna settare sll_protocol e
// sll_ifindex se si vuol fare il bind ad una specifica interfaccia
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_ifindex = if_nametoindex(ifname);
printf("index %d", addr.sll_ifindex);
// viene assegnato un indirizzo al socket
if (bind(sfd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_ll)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// ricevo traffico
if (!buffer[0])
printf("buffer zeroed");
// rval = recvfrom(sfd, buffer, 65536, 0, (struct sockaddr *)&addr,
// &saddr_len);
if (buffer[0])
printf("something was written in the buffer");
return 0;
}
How do I fix it?
What do you want to fix exactly? See below.
Why the programs hangs during the execution and doesn't show the first printf output?
Both printf() do work, except you're not printing any line breaks ('\n') at the end of your messages, so the system does not flush your message to the console. Just end your messages with line breaks and you will see your messages as expected.
As for the hang, this is simply because recvfrom() waits until a packet arrives. Well, not just any packet in your case, since you are filtering on ICMP. Ping your interface from the outside, and the program should resume. Alternatively, for debugging your C program, just keep { 0x6, 0, 0, 0x00040000 } (return non-zero) in your BPF program, and any received packet should do.
How can I receive from ANY interface?
How to bind a socket to multiple interfaces

Epoll events(EPOLLLT) only triggered once on udp socket

From online resource, they said that if epoll listening on file descriptors using default mode(level trigger), when the fd(file descriptor) is ready to read and the buffer data associated with fd not fully consumed, epoll will continue to trigger until all data is consumed, however, when I test with epoll(LT mode) listening on udp socket, when multiple characters comes epoll only trigger once.
the process like below:
step 1: create epoll, udp socket fd, then make epoll listening on socket for write event.
step 2: send multiple characters("abc") to the udp socket
step 3: each time epoll triggered, then read 1 character from the udp socket.
I am expecting that epoll trigger three times as udp socket receive 3 characters, but the result is epoll only trigger once.
here is my code:
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BUFFER_SIZE 512
#define log(fmt, arg...) printf(""fmt, ##arg)
void main(){
int fd1,efd, fds, i, fd;
int ret, addr_len;
struct epoll_event g_event;
struct epoll_event *epoll_events_ptr;
char buffer[BUFFER_SIZE] = {0};
struct sockaddr_in addr1;
fd1 = socket(AF_INET, SOCK_DGRAM, 0);
if (fd1 == -1) {
log("create socket fail \r\n");
return ;
}
addr1.sin_family = AF_INET;
addr1.sin_addr.s_addr = INADDR_ANY;
addr1.sin_port = htons(3500);
addr_len = sizeof(struct sockaddr_in);
if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) {
log("bind local listening addr fail,errno : %d \r\n", errno);
goto err;
}
efd = epoll_create1(0);
if (efd == -1) {
log("create epoll fail \r\n");
goto err;
}
log("create epoll instance success \r\n");
epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
if (epoll_events_ptr == NULL) {
log("calloc fail \r\n");
goto err;
}
g_event.data.fd = fd1;
g_event.events = EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);
while(1) {
fds = epoll_wait(efd, epoll_events_ptr, 2, -1);
for (i = 0; i<fds; i++)
{
if (epoll_events_ptr[i].events & EPOLLIN)
{
ret = recv(fd1, buffer, 1, MSG_DONTWAIT);
if(ret != -1)
log("recv msg : %s \n", buffer);
}
memset(buffer, 0, BUFFER_SIZE);
}
}
err:
close(fd1);
if(epoll_events_ptr)
free(epoll_events_ptr);
return ;
}
enter image description here
You are treating UDP as though it was a streaming protocol, i.e. TCP. It isn't. It is a datagram protocol. If you read a UDP datagram into a buffer that is too small to receive it, the remainder of the datagram is discarded. Not left in the buffer for next time.
Reading one character at a time is therefore pointless in UDP, not to mention extremely inefficient in any protocol.
NB You don't need the memset(), and this:
log("recv msg : %s \n", buffer);
is invalid. It should be:
log("recv msg : %.*s \n", ret, buffer);
You can't assume the received data is null-terminated.

Not able to make connection to a server process located on different network using in C

I am trying to send messages between two system located on different network using C socket programming.
But when connect() system call initiated it is returning -1 so I am not able to connect to the server.
How can I get connect to a remote server located on different network or different machine. Same program is working when I am using client and server on local machine.
**Client code ----->**
int main(int argc, char *argv[]){
int sockfd,portno,n;
char buffer[256];
struct sockaddr_in serv_addr;
struct hostent *server;
if (argc<3)
error("error port number not provided");
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
error("error while creating socket ");
server =(struct hostent *)gethostbyname(argv[1]);
if(server == NULL){
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
//bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port=htons(portno);
if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
error("error while connecting..");
while(strncpy(buffer,"bye",3)!=0){
bzero(buffer,256);
printf("\nYou:");
fgets(buffer,255,stdin);
//n= write(sockfd,buffer,strlen(buffer));
n=send(sockfd,(char*)&buffer,strlen(buffer),0);
if(n<0)
printf("message not delivered\n");
bzero(buffer,256);
//n= read(sockfd,buffer,255);
n= recv(sockfd,buffer,255,0);
printf("\nfrd:%s",buffer);
}
close(sockfd);
}
**Server code -->**
int main(int argc, char *argv[]){
int sockfd,listenfd,portno,clilen,n;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
if (argc<2)
error("error port number not provided");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
error("error while creating socket ");
bzero((char*) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof serv_addr)<0)
error("error while binding socket");
listen(sockfd`enter code here`,5);
clilen = sizeof(cli_addr);
if ((listenfd = accept(sockfd, (struct sockaddr*)&cli_addr,&clilen))<0)
error("error while initializing listening");
printf("listening for connections..");
while(strncmp(buffer,"bye",3)!=0){
bzero(buffer,256);
//n= read(listenfd,buffer,255);
n= recv(listenfd,buffer,255,0);
if(n<0)
error("no message");
printf("\nfrd:%s",buffer);
printf("\nyou:");
fgets(buffer,255,stdin);
//n= write(listenfd,buffer,sizeof buffer);
n=send(listenfd,(char*)&buffer,strlen(buffer),0);
if(n<0)
printf("message not sent");
}
close(sockfd);
}
All of client code is the same as that in the server.
server =(struct hostent *)gethostbyname(argv[1]);
if(server == NULL){
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
argv1 contains the name of a host on the Internet, e.g. hsembedded.blogspot.in ;)
The function:
struct hostent *gethostbyname(char *name)
Takes such a name as an argument and returns a pointer to a hostent containing information about that host. The field char *h_addr contains the IP address. If this structure is NULL, the system could not locate a host with this name.
The mechanism by which this function works is complex, often involves querying large databases all around the country.
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
This code sets the fields in serv_addr. Much of it is the same as in the server. However, because the field server->h_addr is a character string, we use the function:
void bcopy(char *s1, char *s2, int length)
which copies length bytes from s1 to s2.
the error is actually due to absence of #include<netdb.h> in client code.

Calling setsockopt many times

I have application which uses sockets to transfer data between two clients. It uses a single socket to communicate control and data traffic (over UDP).
Qos and tos fields of IP header can be changed using
setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, toslen);
setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, coslen);
But how many calls to setsockopt (to the same socket) is too many?
For example, lets assume it will be called every 1ms.
To narrow question scope, I am asking about modern linux system (generic explanation is more than welcomed).
Here is an example to demonstrate it (this is the sending-only part of the application):
#include <stdlib.h>
#include <memory.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define NPACK 10000
#define PORT 44444
#define BUFLEN 128
void diep(char *s) {
perror(s);
exit(1);
}
#define SRV_IP "12.34.56.78"
int main(void) {
struct sockaddr_in si_other, si_me;
int s, i, slen = sizeof(si_other);
int toss[2] = { 56, 160 }, coss[] = { 1, 3 };
char buf[BUFLEN];
//Create UDP socket
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
diep("socket");
//Create remote socket
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &si_other.sin_addr) == 0) {
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
//Create local socket and bind to it.
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, &si_me, sizeof(si_me)) == -1)
diep("bind");
//Loop on number of packets
for (i = 0; i < NPACK; i++) {
sprintf(buf, "This is packet %d, %d\n", i, toss[i % 2]);
printf("Sending packet %d. %s", i, buf);
//Change tos and cos. odd packets high priority , even packets low priority.
setsockopt(s, IPPROTO_IP, IP_TOS, &toss[i % 2], sizeof(int));
setsockopt(s, SOL_SOCKET, SO_PRIORITY, &coss[i % 2], sizeof(int));
//Send!
if (sendto(s, buf, strlen(buf), 0, &si_other, slen) == -1)
diep("sendto()");
}
close(s);
return 0;
}
NOTES:
Both control and data should share the same socket (same UDP source port).
Multiple threads will use the same socket (so some locking mechanism needed between setsockopt and sendto; but this is outside the scope of the question).
SO_PRIORITY is linux only.

'sendto()' function won't send data to an application on another computer

i wrote a client application in c using the posix sockets api on linux that sends information to a server, which then gets printed to the servers terminal window. If the server is on the same machine as the client and the client sends to the loopback or to its own IP address then all is good. However, if the server is running on another machine, then sendto returns an "invalid argument" error.
Here is the code for the client application:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "utils.h" // for 'errexit()'
#define PEER_PORT 54321
#define BUFFSIZE 100
#define local_net_ip "192.168.0.10"
int main( int argc, char *argv[] )
{
int clientfd;
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
if( clientfd == -1 )
errexit( "socket()" );
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons( PEER_PORT );
if( inet_pton( AF_INET, local_net_ip, (void *) &(servaddr.sin_addr) ) == -1 )
errexit( "inet_pton()" );
char addrStr[ INET_ADDRSTRLEN ];
inet_ntop( servaddr.sin_family, &(servaddr.sin_addr), addrStr, INET_ADDRSTRLEN );
printf("Server IPv4 addr: [ %s ]\n", addrStr);
char buff[ BUFFSIZE ];
int writebytes;
for( ;; ) {
printf( "Enter text: ");
fgets( buff, BUFFSIZE, stdin );
writebytes = sendto( clientfd, buff, BUFFSIZE, 0, (struct sockaddr *) &servaddr, sizeof( struct sockaddr_in ) );
if( writebytes == -1 )
errexit( "sendto()" );
}
exit( EXIT_SUCCESS );
}
I would greatly appreciate any information as to why the application won't send to another computer! Thanks in advance!!
clientfd = socket( AF_INET, SOCK_DGRAM, 0 );
You are creating a socket with protocol 0, e.g. IP. But later you use and IP:Port as a target. You probably wanted to use an UDP socket here (proto 17).