In linux, how can I transmit an UDP packet using 0.0.0.0 as source address.
Here is what I have tried so far.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
int main(int argc, const char *argv[])
{
struct sockaddr_in dst, src;
struct ifreq ifr;
int sock, tmp;
char payload[128];
memset(payload, 0, 128);
memset(&dst, 0, sizeof(dst));
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = inet_addr("255.255.255.255");
dst.sin_port = htons(67);
memset(&src,0,sizeof(src));
src.sin_family = AF_INET;
src.sin_addr.s_addr = inet_addr("0.0.0.0");
src.sin_port = htons(68);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
perror("Failed to create socket");
tmp = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &tmp, sizeof(tmp)) < 0)
perror("SO_BROADCAST failed");
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) < 0)
perror("SO_REUSEADDR failed");
if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &tmp, sizeof(tmp)) < 0)
perror("IP_FREEBIND failed");
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0)
perror("SO_BINDTODEVICE failed");
if (bind(sock, (const struct sockaddr*)&src, sizeof(struct sockaddr_in)) < 0)
perror("bind failed");
if (connect(sock, (const struct sockaddr*)&dst, sizeof(struct sockaddr_in)) < 0)
perror("bind failed");
if (write(sock, payload, 128) < 0 )
perror("Write failed");
close(sock);
return 0;
}
The problem is the the source address is only set to 0.0.0.0 if no interfaces has an IPv4 address. If just one interface has an IPv4 address, this address is used as source address.
I have looked at the source code of some of the existing DHCP clients, and found that they are using RAW sockets and building the IP and UDP header manually. This is possibility, but I would like to avoid doing this manually.
You should use RAW SOCKET and construct packet with your own efforts.
As an example you can take this: https://github.com/fycth/DHCP-server-scanner/blob/master/src/dhcpd-detector.c
This is my educational project. It is small and you can look how exactly this task is solved there.
I think if it was possible to do it via UDP sockets, they would do it instead of building one manually. So I'd suppose it doesn't work at all...
Related
Have to make it server & client as bidirectional where I should able to send & receive data in console.
I can able to send data from server to client but not able to receive any data from client.Stuck in this for long time could not know how to resolve it.
I just started working on networking any lead on this really helpful.
Here is my code.
Server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
struct in_addr localInterface;
struct sockaddr_in groupSock, rcv_addr;
int sd;
char databuf[1024];
int datalen = sizeof(databuf);
int main(int argc, char *argv[])
{
/* Create a datagram socket on which to send. */
socklen_t rcv_addr_size = sizeof(struct sockaddr_in);
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK.\n");
memset((char*) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(4321);
localInterface.s_addr = inet_addr("127.0.0.1");
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char*) &localInterface,
sizeof(localInterface)) < 0) {
perror("Setting local interface error");
exit(1);
} else
printf("Setting the local interface...OK\n");
int read_size;
while (1) {
memset(databuf, 0x00, sizeof(databuf));
scanf("%s", databuf);
datalen = strlen(databuf) + 1;
if (sendto(sd, databuf, datalen, 0, (struct sockaddr*) &groupSock,
sizeof(groupSock)) < 0)
datalen = 1024;
memset(databuf, 0x00, sizeof(databuf));
read_size = recvfrom(sd, databuf, datalen, 0,
(struct sockaddr*) &rcv_addr, &rcv_addr_size);
printf("The message from multicast ckient is: \"%s\"\n", databuf);
}
return 0;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
struct sockaddr_in localSock, rcv_addr;
struct ip_mreq group;
int sd;
int datalen;
char databuf[1024];
int main(int argc, char *argv[]) {
/* Create a datagram socket on which to receive. */
socklen_t rcv_addr_size = sizeof(struct sockaddr_in);
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0) {
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening datagram socket....OK.\n");
{
int reuse = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse,
sizeof(reuse)) < 0) {
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
} else
printf("Setting SO_REUSEADDR...OK.\n");
}
memset((char*) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(4321);
localSock.sin_addr.s_addr = INADDR_ANY;
if (bind(sd, (struct sockaddr*) &localSock, sizeof(localSock))) {
perror("Binding datagram socket error");
close(sd);
exit(1);
} else
printf("Binding datagram socket...OK.\n");
group.imr_multiaddr.s_addr = inet_addr("226.1.1.1");
group.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &group,
sizeof(group)) < 0) {
perror("Adding multicast group error");
close(sd);
exit(1);
} else
printf("Adding multicast group...OK.\n");
int read_size;
while (1) {
datalen = 1024;
memset(databuf, 0x00, sizeof(databuf));
read_size = recvfrom(sd, databuf, datalen, 0,
(struct sockaddr*) &rcv_addr, &rcv_addr_size);
printf("The message from multicast server is: \"%s\"\n", databuf);
memset(databuf, 0x00, sizeof(databuf));
scanf("%s", databuf);
datalen = strlen(databuf) + 1;
if (sendto(sd, databuf, datalen, 0, (struct sockaddr*) &localSock,
sizeof(localSock)) < 0)
break;
}
return 0;
}
Your server is sending to the wrong address.
The server is using localSock as the destination address for sendto:
if(sendto(sd, databuf, datalen, 0, (struct sockaddr*)&localSock, sizeof(localSock)) < 0)
But you have that address set to 0:
localSock.sin_family = AF_INET;
localSock.sin_port = htons(4321);
localSock.sin_addr.s_addr = INADDR_ANY;
You want to instead use rcv_addr, which was populated as the source address from recvfrom. Using this address as the destination will send the response back where it came from:
if(sendto(sd, databuf, datalen, 0, (struct sockaddr*)&rcv_addr, sizeof(rcv_addr)) < 0)
Multicast connection is like broadcast communication, you send the packet to a forum of receivers, awaiting to read it, and they consume it (if it arrives). This normally means that you have to arrange for bidirectional connection in a way that allows all people skeaking in a room and selecting yourself the responses, as everybody is talking to everybody in a multicast channel. Imagine you are chatting in a IRC channel, and you have to arrange with somebody how to direct messages only to that person, but with the anarchy of anybody being able to respond to such messages in the way they want. You have always to think that what you say, you say to everybody susbscribed in that multicast channel, so normally you will receive several response packets, from which you will have to select...
Multicast between 2 applications on same host(macOS). The example is based on launching 2 applications Appli_A who join the same multicast group and are listening of an incoming datagram packet which is beeing send by the application Appli_B but there is only one of the 2 applications Appli_A receiving the packet and not both.
Since the implementation is platform dependent and I'm using macOS I had to change some commands that's why I use SO_REUSEPORT instead of SO_REUSEADDRES
But it still won't work. Here's a small example:
Appli_A
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct sockaddr_in localSock;
struct ip_mreq group;
int sd;
int datalen;
char databuf[1024];
void sigint_routine_handler(int param){
if(close(sd) == 0)
printf("hSocket closed\n");
else
printf("Error closing hSocket\n");
}
int main(int argc, char *argv[])
{
if(signal(SIGINT, sigint_routine_handler) == SIG_ERR)
printf("ERROR: Installing suspend handler SIGINT\n");
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
/* Enable SO_REUSEPORT to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char *)&reuse, sizeof(reuse)) < 0)
{
close(sd);
exit(1);
}
/* Since I'm using htonl(INADDR_ANY) I'm Binding the socket to all available interfaces */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(54011);
localSock.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
close(sd);
exit(1);
}
/* Join the multicast group 235.73.158.23 */
group.imr_multiaddr.s_addr = inet_addr("235.73.158.23");
group.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
close(sd);
exit(1);
}
/* Read from the socket. */
datalen = sizeof(databuf);
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", databuf);
}
if(close(sd) < 0)
printf("Error close socket descriptio\n");
return 0;
}
Appli_B
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct in_addr localInterface;
struct sockaddr_in groupSock;
int sd;
char databuf[50] = "Multicast test message$";
int datalen = sizeof(databuf);
int main(int argc, char *argv[])
{
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK.\n");
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
/* README Normally here should I specifiy the Multicast-adress of the group for the outgoing
Datagrampacket, but it won't work if I specify this Multicast-adress "235.73.158.23"*/
groupSock.sin_addr.s_addr = htonl(INADDR_ANY);
groupSock.sin_port = htons(54011);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface -> I have checked the interface, it is Multicast capable */
localInterface.s_addr = inet_addr("192.168.1.5");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("Setting local interface error");
exit(1);
}
else
printf("Setting the local interface...OK\n");
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
int datalen = 50;
if(sendto(sd, databuf, datalen, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0){
perror("Sending datagram message error");
}
else
printf("Sending datagram message...OK\n");
return 0;
}
UPDATE
I have tried it on ubuntu linux 16.04, there everything works fine.
I changed SO_REUSEPORT to SO_REUSEADDR and the Multicast-address of the outgoing Datagrampacket of Appli_B to the Multicastgroup specified in Appli_A, if I do this on MACOS none of the 2 Appli_A applications receives the datagram packet, in case that the interface might not have a multicast address I followed this blog but it still won't work under MacOS.
I'm trying to receive multicast data from an embedded device connected to the same switch as my desktop and am unable to receive multicast messages on my recv app below.
When I do a tcpdump or run Wireshark against the interface connected to the switch, I see the packets show up but for some reason they don't in my app.
I'm using INADDR_ANY for the interface address.
Could someone shed some light on why the messages would be on Wireshark/Tcpdump but not received by the application?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define UDP_PORT 5403
#define UDP_GROUP "225.0.0.1"
#define MAX_BUFFER_SIZE 256
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes;
socklen_t addrlen;
struct ip_mreq mreq;
char msgbuf[MAX_BUFFER_SIZE];
u_int reuse_port = 1;
// Create a socket
fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd < 0)
{
perror("create socket failed");
return -1;
}
// allow multiple sockets to use the same PORT number
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_port, sizeof(reuse_port)) < 0)
{
perror("Reusing port number failed");
return -1;
}
// set up destination address
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(UDP_PORT);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
// Set the recvfrom timeout after 1 s
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
perror("Error setting recvfrom timeout\n");
return -1;
}
// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(UDP_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return -1;
}
addrlen = sizeof(addr);
printf("Begin recvfrom(...) infinite loop\n");
while (true)
{
nbytes = recvfrom(fd, msgbuf, MAX_BUFFER_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
if (nbytes < 0)
{
printf("recvfrom timeout\n");
}
else
{
printf("message received: %s\n", msgbuf);
}
}
return 1;
}
I have looked for a similar question, but I could not find one that would work for me. I am doing a simple project for one of my subjects, but I never had experience with sockets, so I need some help with the implementation of one feature.
Basically, there are several units interconnected by a communication network (physical ETHERNET 1Gbps, TCP / IP protocol), and I have to be able to communicate with all the boards. I can implement all other features I need on one specific board, but I don't know how to manipulate all the boards simultaneously.
So, the question is: how to get a list of all boards connected and how to select which board should receive/send a message?
Big thanks to anyone who would help.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
#define MY_PORT 55555
#define BUFLEN 512
int main(int argc, char *argv[])
{
int sockfd;
char buffer[BUFLEN];
struct sockaddr_in peeraddr;
// SET UP A NETWORK SOCKET
if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
int broadcast = 1;
if (setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, & broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
struct sockaddr_in bindaddr;
memset(&bindaddr, 0, sizeof(bindaddr));
bindaddr.sin_family = AF_INET;
bindaddr.sin_port = htons(MY_PORT);
bindaddr.sin_addr.s_addr = INADDR_ANY;
int yes=1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) == -1) {
perror("setsockopt (SO_REUSEADDR)");
exit(1);
}
if (bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1) {
perror("bind");
exit(1);
}
broadcast = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
struct sockaddr_in braddr;
memset(&braddr, 0, sizeof(braddr));
braddr.sin_family = AF_INET;
braddr.sin_port = htons(MY_PORT );
braddr.sin_addr.s_addr = INADDR_BROADCAST;
strncpy(buffer, "Hello world", sizeof(buffer));
char* ipString = inet_ntoa(bindaddr.sin_addr);
while(1){
printf("%s", ipString);
if (sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&braddr, sizeof(braddr)) == -1){
perror("sendto");
exit(1);
}
peeraddr_len = sizeof(peeraddr);
}
return 0;
}
I'm trying to bind the server socket so I can receive and listen for incoming messages from other clients. But I can't bind, it returns error - EINVAL (Invalid Argument). I have gone through the previously asked questions related to this error and Linux manual page says 'The socket is already bound to an address, and the protocol does not support binding to a new address; or the socket has been shut down.'
Here is the problematic server code in c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#define LISTEN_BACKLOG 5
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)
int main(int argc, char* argv[])
{
int sockfd, cfd;
struct sockaddr_in myaddr, cl_addr;
socklen_t cl_len;
int quit = 0, reuse = 1;
if (argc < 2)
{
fprintf(stderr, "ERROR, no port provided\n");
exit(1);
}
if ((sockfd = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
handle_error("socket");
printf("socket created.\n");
#ifdef SO_REUSEADDR
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
perror("setsockopt(SO_REUSEADDR) failed");
#endif
#ifdef SO_REUSEPORT
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
perror("setsockopt(SO_REUSEPORT) failed");
#endif
memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(atoi(argv[1]));
printf("portno: %d\n", atoi(argv[1]));
if (bind(sockfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0)
handle_error("bind");
printf("bind successful\n");
close(sockfd);
unlink((const char *) &myaddr);
return 0;
}
When I try to start the server, I get error EINVAL as shown below:
$ ./server 8032
socket created.
portno: 8032
bind: Invalid argument
Will be grateful to receive any inputs on this, thanks!
Problem is with the way you are creating socket.
if ((sockfd = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
Here you are creating socket for PF_LOCAL rather you want to create for AF_INET family.