2 user space programs over tun using multicast - c

I am still getting my hands-on with networking programming for linux and please feel free to clear my understanding if you feel its vague or incorrect.
Query:
I have baked a Linux image using yocto project which is similar to core-image-minimal. This part is irrelevant for the query. I boot this image using QEMU emulator and when QEMU is booted up it creates a sudo interface by the name tap0. The IP of the QEMU is 192.168.7.2 and tap0 i guess has IP 192.168.7.1.
Now I have another user space program written in simple C which tries to listen whatever the QEMU program(node) is sending. So, I use a fragment similar to this:
if ( (fd = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = TUNMODE;
strncpy(ifr.ifr_name, "w-tap%d", IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");
printf("Allocated interface %s. Configure and use it\n", ifr.ifr_name);
s = socket(PF_INET, SOCK_DGRAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(PORT);
if ( bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0) PERROR("bind");
fromlen = sizeof(from);
while(1) {
l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
//print the data etc
}
Now If I start this C code with say sudo ./tun_proxy 1534, I am able to listen the messages on this port sent by 192.168.7.2.
Further,
I Boot up QEMU with additional option -net socket,mcast=224.244.224.245:30490 since baked image has a small program in it to send some messages as broadcast on the multicast group and port. Also, I should be able to listen these message on the previous tun_proxy application. I even created a new thread in that which tries to listen on the multicast group but I get the error message as "already in use"
Where exactly is my understanding wrong? All I need is 2 user space programs, one of which is a QEMU to communication via multicast messages.

Your understanding is sound, there are just 2 problems you need to address:
If you bind on INADDR_ANY you are blocking the port for all other addresses (including multicast) unless you use REUSEADDR. Your INADDR_ANY bound socket would also be receiving the multicast it is blocking access to, except:
Some socket on a "host" needs to use IP_ADD_MEMBERSHIP where the membership request matches the traffic before any sockets will receive the multicast traffic.
Emulating your current example:
As an equivalent but rather bizarre example, shell1 is equivalent to your listener and shell2 shows that a seemingly unrelated socket's ip-add-membership (but for the correct address and all interfaces) causes it to receive traffic:
shell1$ socat UDP-RECVFROM:30490,bind=0.0.0.0 EXEC:date
shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
shell1$ (socat is still waiting for a packet)
shell2-add-membership$ socat UDP-RECVFROM:1044,reuseaddr,bind=127.0.0.1,ip-add-membership=224.244.224.245:0.0.0.0 EXEC:date&
[1] 16003
shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
Thu Sep 1 00:16:28 CEST 2016
shell1$ (socat now exits cleanly)
Fixing it for multicast:
So to run 2+ clients, the correct method would be:
shellclient1$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr,ip-add-membership=224.244.224.245:0.0.0.0 EXEC:date
shellclient2$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr EXEC:date
...
shellclientn$ socat UDP-RECVFROM:30490,bind=0.0.0.0,reuseaddr EXEC:date
shell2$ echo hi | socat UDP-DATAGRAM:224.244.224.245:30490 STDIO
Thu Sep 1 00:16:28 CEST 2016
...
Notice that all must use SO_REUSEADDR, but only one must add membership.
Qemu's socket network uses SO_REUSEADDR and does an membership. So the code blocking the socket is probably other code that needs to be modified to be like Qemu.

Related

3 sockets created for one libevent bind on Windows?

I'm writing a BitTorrent client to learn some more about networking, and I've got something that I'm struggling to Google for. As part of the BT spec, I need a server to listen for peer connections to my computer. In the win32 port, I have code like this to setup my server
struct sockaddr_in saServer;
struct hostent* localHost;
char* localIP;
// Get the local host information
localHost = gethostbyname("");
localIP = inet_ntoa(*(struct in_addr *)*localHost->h_addr_list);
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(localIP);
saServer.sin_port = htons(6881);
struct evconnlistener *listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (SOCKADDR*)&saServer, sizeof(saServer));
That seems to work, but if I look at netstat, I see the following,
BitTorrentClient.exe 6092 TCP hostname 50216 localhost 50217 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname 50217 localhost 50216 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname.home 6881 hostname 0 LISTENING
Why are there two other connections, one from port 50216->50217 and one looping back from 50217->50216? I was expected to have just one listening connection on port 6881. Is this a libevent quirk, or something more fundamental related to networking?
What can I search for to understand what the other two ports are used for?
This is most likely a result of libevent calling evutil_make_internal_pipe_ internally.
Libevent creates internal "pipes" for inter-thread communication and signal delivery using socketpair(2) on POSIX-compliant systems, whereas on Windows libevent has to resort to manually connecting two sockets together instead.

UDP client does not receive data without bind()

I refereed to the UDP client program from binarytides and I was able to send a UDP packet frompy PC to the UDP server which is My embedded device and this device echoes back a UDP message.
In this PC-UDP client code it is expected to get the echoed message ,but I'm not getting any echoes back.So I ran a UDP server in my PC which listens for the incoming data and prints it , I was able to see the echoed message from my Embedded device.
When I added these lines just before the while(1) loop in the code,and now I'm able to see the Echoed back message.
//setup address structure
memset((char *) &si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(PORT);
si_server.sin_addr.S_un.S_addr = INADDR_ANY;
if( bind(s ,(struct sockaddr *)&si_server , sizeof(si_server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
Any thoughts on what might be causing the issue?
Hi Finally I found the answer from EJP answer
It is only necessary to bind() a server, because the clients need a fixed port number to send to. A client needn't bind() at all: an automatic bind() will take place on the first send()/sendto()/recv()/recvfrom() using a system-assigned local port number.
With the help of wireshark I was able to see My PC was sending data from Port 53701 and on first sendto() this port got automatically bind'ed , so had to do a explicit binding.

Choose a local source port that is already in use

I want to connect to a remote server using a specific local port, not one assigned randomly by the kernel. I can do this by calling bind() to bind to the local port before calling connect() to the remote server.
My question is what happens if the local port I want to use is already in use by another application? I should be able to use it anyway, provided the destination or remote port are different (the same way a server can accept() multiple connections on port 80). But shouldn't my bind call fail in this case, and if so how can I set up the socket to use the local port that's already in use by another application?
The reason I want to do this is I am trying to write a local proxy that connects to a server application who checks the source port. If the source port is wrong the server won't allow the connection. The client side application connects to my proxy, and I want my proxy to use the same port to connect to the server - but if the proxy is on the same machine it won't work because the port is already in use by the application connecting to my proxy.
You can make an argument that you should be able to use it anyway, but TCP implementations don't let you unless the two binds are different. For example, you are probably able to bind to the same port with different IP addresses.
There are two problems with permitting overlapping binds:
What happens if both applications call accept? Do they fight over incoming connections?
What happens if both applications try to make an outbound connection to the same IP and port? How can those two connections be distinguished?
Now these problems could be solved. But I don't know of any implementations that bother. The argument is that the applications would have to cooperate or they would get surprising results. And if they're cooperating, they can share the bound socket.
So the answer is: If you aren't cooperating with the other application that has the port, then you have no right to share it. If you are cooperating with the other application, ask it to give you a copy of its socket using the method your platform supports.
> But shouldn't my bind call fail in this case,
Yes if the socket does not have SO_REUSEADDR option set.
> and if so how can I set up the socket to use the local port that's already in use by another application?
Both your application and another application must set SO_REUSEADDR option on the socket, which wants to bind to the local port.
The code below connects to the HTTP server, given as command-line argument, from port 1111:
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#define CLIENT_PORT 1111
#define SERVER_PORT 80
int main(int argc, char *argv[]) {
struct sockaddr_in client_name, server_name;
struct hostent *server_info;
if (argc != 2)
return printf("Exactly one argument is required: host to connect\n"), 1;
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
return perror("socket"), 1;
/* Without the next 4 lines, bind refuses to use the same port */
int reuseaddr = 1;
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(reuseaddr)) < 0)
return perror("setsockopt"), 1;
client_name.sin_family = AF_INET;
client_name.sin_port = htons(CLIENT_PORT);
client_name.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_fd, (struct sockaddr *) &client_name,
sizeof(struct sockaddr_in)) < 0)
return perror("bind"), 1;
server_name.sin_family = AF_INET;
server_name.sin_port = htons(SERVER_PORT);
if ((server_info = gethostbyname(argv[1])) == NULL)
return printf("Unknown host: %s\n", argv[1]), 1;
server_name.sin_addr = *(struct in_addr *) server_info->h_addr;
if (connect(sock_fd, (struct sockaddr *) &server_name,
sizeof(server_name)) < 0)
return perror("connect"), 1;
return 0;
}
> what happens if the local port I want to use is already in use by another application?
Without SO_REUSEADDR (try to comment out the 4 lines around setsockopt), bind fails:
$ ./client google.com
$ ./client stackoverflow.com
bind: Address already in use
With SO_REUSEADDR, you can connect to different remote servers:
$ ./client google.com
$ ./client stackoverflow.com
But then connect will not allow you to open two sockets with same source and destinations:
$ ./client google.com
$ ./client google.com
connect: Cannot assign requested address
bind knows just one endpoint.
Suppose that two sockets are bound to the same port. Which one the incoming packet shall be routed to?
accept on the other hand knows both peers.

why i am getting Remote ip address 0.0.0.0 from recvfrom()?

I have a server listening on a port
The request is sent from my local client to the server running on my local pc.
Following is my code snippet
remote_len = sizeof(remote_addr);
if ((bytes=recvfrom(sockfd, buf, MAXBUFLEN , 0,
(struct sockaddr *)&remote_addr, &remote_len)) <= 0) {
exit(1);
}
printf("remote ip = %s\n",inet_ntoa(remote_addr.sin_addr));
When i print the ip i get 0.0.0.0 ??
Is this not the remote IP adrress which i am trying to print?
Edit : Its a TCP socket and i recevied buffer successfully.
See TCP recvfrom() doesn't store 'from' - apparently it's not supported for TCP. All you're seeing is the zero bytes that were originally there. That's why remote_len returns 0 - because no address was set.
That link is to windows related docs; I don't see that behaviour in the Linux man page, which says only "may be used to receive data on a socket whether or not it is connection-oriented", but at http://www.beej.us/guide/bgnet/output/html/multipage/recvman.html it says that recvfrom is for UDP. It's not mentioned in Harbison + Steele, unfortunately, and I can't find a copy of Unix Network Programming.

bind() call in tcp client

I am trying to change the source ip address for a tcp packet. Code snippet as given bellow
bzero(&clientaddr,sizeof(clientaddr));
clientaddr.sin_family = AF_INET;
clientaddr.sin_addr.s_addr=inet_addr("172.16.2.10");
clientaddr.sin_port=htons(8080);
if (bind(sockfd, (struct sockaddr *) &clientaddr,
sizeof(clientaddr)) < 0)
{
perror("bind");
}
Binding a particular port is working fine,
but when i tried to bind with a diffrent ip adress, the bind is failing with error
bind: Cannot assign requested address
I also tried by setting the socket option as follows,]
setsockopt (sockfd, SOL_IP, IP_TRANSPARENT, &n1, sizeof(int));*
then also its failing with same error.
How could i change my source ip address for packet, originated from my PC.
Please help me, its for a proxy application.
OS :Linux 2.6.37-tproxy #1 SMP Wed Apr 3 23:34:00 IST 2013 x86_64 x86_64 x86_64 GNU/Linux
Thanks in advance.
You will need to use a raw socket and create the ip and tcp headers (where you will be able to set the desired IP Address (spoofing).
raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
You can check the linux manual page man 7 raw
You can only bind() to an IP address that is local to your computer, i.e. implemented by one of your network interfaces.

Resources