Socket programming: bind()-invalid argument - c

I am trying to bind my local IPv6 address to a socket. But always get "invalid argument". The reason I want to bind the specific IP address to socket is that if I don't bind the error "No route to host" came up. When I tried to ping an IPv6 address with command below it does not work.
ping6 fe80::7ed1:c3ff:fe86
I have to point out from which interface I want to send the packet.
ping6 -I en1 fe80::7ed1:c3ff:fe86
And this works fine. So I think if I bind the socket to the interface then I can send the packet successfully.
Anyone can tell me how to send an IPv6 address without specify the interface or how to solve this problem of binding?
Here are the codes.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#define LOCALADDR "fe80::7ed1:c3ff:fe86:ddae"
int main(void)
{
int sock,status;
struct addrinfo local_addr;
struct addrinfo *servinfo;
char buffer[1024];
/* create a DGRAM (UDP) socket in the INET6 (IPv6) protocol */
sock = socket(PF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
perror("creating socket");
exit(1);
}
/*Binding specific interface to socket*/
memset(&local_addr, 0, sizeof(local_addr));
local_addr.ai_family = AF_INET6;
local_addr.ai_socktype = SOCK_DGRAM;
local_addr.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(NULL, "3535", &local_addr, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
if (bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
error("ERROR on binding");
I have also tried to replace "NULL" in the "getaddrinfo" to be "LOCALADDR".
if ((status = getaddrinfo(LOCALADDR, "3535", &local_addr, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
And I still get the same problem.
I can successfully binding the socket with "in6addr_any",but then I get the error "No route to host".

That is a link-local IPv6 address, not a routable IPv6 address. The link-local addresses are specific to a link, and each link can have the same addresses as the other links. For instance if you have three different interfaces, you can assign the same link-local address to each of the interfaces. To use a link-local address, you need to specify the interface so that the OS knows which link to use. All the interfaces will have a link-local address in the same network: fe80::/10.
If you use a routable IPv6 address, you will not need to specify an interface.

You are creating the socket incorrectly. The 'domain' (first argument) should be AF_INET6, not PF_INET6. I am uncertain whether these in fact expand to different values in your environment, but the AF_* macros are the ones designated for this purpose.
Otherwise, for a socket that accepts connections, you should get an address much the way you first present. In particular, the docs for getaddrinfo() say
If the AI_PASSIVE flag is specified in hints.ai_flags, and node is NULL, then the returned socket addresses will be suitable for bind(2)ing a socket that will accept(2) connections. The returned socket address will contain the "wildcard address" (INADDR_ANY for IPv4 addresses, IN6ADDR_ANY_INIT for IPv6 address). The wildcard address is used by applications (typically servers) that intend to accept connections on any of the hosts’s network addresses. If node is not NULL, then the AI_PASSIVE flag is ignored.
Thus, you certainly could and probably should specify a NULL first argument.
Note, however, that getaddrinfo() returns a linked list of addresses, and under some circumstances it is necessary to choose a different one than the first. I think the first ought to be fine in this particular case, though.
Do also be aware that a "no route to host" message from a client trying to connect does not necessarily indicate that the server is not listening. It could well be that the client is using the wrong address (c.f. #RonMaupin's answer) or, just as it says, that there is no (known) route through the network from the client to the server. That could arise because of router or firewall configuration, for example.

Related

recvfrom in socket programming with C

So I was trying to understand socket programming in C when I came across this code:
/* Sample UDP client */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
char sendline[] = "Hello UDP server! This is UDP client";
char recvline[1000];
if (argc != 2)
{
printf("usage: ./%s <IP address>\n",argv[0]);
return -1;
}
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
servaddr.sin_port=htons(32000);
sendto(sockfd,sendline,strlen(sendline),0,(struct sockaddr *)&servaddr,sizeof(servaddr));
n=recvfrom(sockfd,recvline,10000,0,NULL,NULL);
recvline[n]=0;
printf("Received: %s\n",recvline);
return 0;
}
It seems that the recvfrom() call does not need an ip address to send the message. A look at the man pages revealed the following lines:
If src_addr is not NULL, and the underlying protocol provides the
source address, this source address is filled in. When src_addr is
NULL, nothing is filled in; in this case, addrlen is not used,
and should also be NULL.
So I think that the underlying protocol provides the source IP address. My problem is, how does it really figure out the address to receive the message from ? Is it that, once you send a message to an address, you cannot use the same socket to send messages to other addresses ? So that it keeps on using the same address ?
Please help. Couldn't find an answer anywhere in Google or any lecture note.
Thank you in advance.
You have a misconception that recvfrom pulls data from a particular source address.
recvfrom is generally used for connectionless protocols like UDP. When an UDP packet is received, it could be from any source address. src_addr returns this address for the application usage.
If you are expecting messages only from a particular address, there are 2 ways. (1) Either you can ignore the packets received from other addresses by comparing the address returned in src_addr, or (2) use connect to specify a particular remote address from where you are expecting messages and the lower socket layer takes care of ignoring packets from other sources. After connect, you could also use recv instead of recvfrom.
Sending messages are done through sendto. You seem to be confusing the 2 calls. Using sendto it is possible to send messages to difference addresses on the same socket.

When is the UDP source port set?

I'm writing a very small C UDP client. I know that a random port is chosen as source port when you send data to the server. I also know that you can use bind to specify yourself the port you want a response.
However, I don't know when is the port randomly chosen? For example, I would like to rely on the sender address to keep track of users. It currently works only if the client does not shutdown, the port is still the same then a simple memcmp is enough to detect the same client.
This small code will use the same source port until it exits:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
int main(void)
{
int s, error, ch;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((error = getaddrinfo("localhost", "9988", &hints, &res)))
errx(1, "%s", gai_strerror(error));
if ((s = socket(res->ai_family, res->ai_socktype, 0)) < 0)
err(1, "socket");
while ((ch = fgetc(stdin)) != EOF)
sendto(s, &ch, 1, 0, res->ai_addr, res->ai_addrlen);
}
And running something like : dmesg | ./client will use the same address until the program exits. However, when you run it again, the port is different.
So is it the socket function that choose a port? Or the system? Is it sure that the port will still be the same during the client lifetime?
If the socket is not explicitly bound, then the OS will bind it (with a random port) when you send the first packet. This binding will be active as long as the socket is open, once it's closed the socket is (of course) unbound.
And due to the connectionless nature of UDP sockets, the "server" (if done correctly) should not keep the address of all "clients" that send to it indefinitely. Instead it should use the source address as received in the recvfrom call, and use that for a reply. The only reason to store the source address for more than just a simple request/response, is if you have a more advanced protocol on top of UDP with your own "connection" handling.

Binding Sockets to IPv6 Addresses

I am trying to write a web server that listens on both IPv4 and IPv6 addresses. However, the code that I originally wrote did not work. Then I found out that the IPv6 structures work for both IPv4 and IPv6. So now I use the IPv6 structures however, only the IPv4 addresses work. This post, why can't i bind ipv6 socket to a linklocal address, which said to add server.sin6_scope_id = 5; so I did that but it still does not accept IPv6 telnet connections. Any help would be greatly appreciated because I am thoroughly stumped.
Thanks!
My code is below:
void initialize_server(int port, int connections, char* address)
{
struct sockaddr_in6 socket_struct;
/*Creates the socket*/
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}/*Ends the socket creation*/
/*Populates the socket address structure*/
socket_struct.sin6_family = AF_INET6;
if(address == NULL)
socket_struct.sin6_addr=in6addr_any;
else
{
inet_pton(AF_INET6, "fe80::216:3eff:fec3:3c22", (void *)&socket_struct.sin6_addr.s6_addr);
}
socket_struct.sin6_port =htons(port);
socket_struct.sin6_scope_id = 0;
if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the binding.
if (listen(sock_fd, connections) <0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the listening function
}//ends the initialize server function.
Saying "server.sin6_scope_id = 5;" is arbitrary. I fought with this awhile myself and discovered you need to use the actual scope of the actual interface you want to bind on. It can be found with an obsure but useful little function.
#include <net/if.h>
server.sin6_scope_id=if_nametoindex("eth0");
Of course, hardcoding it to one particular adapter is bad, shortsighted coding. A more complete solution is to loop through all of them and match on the ip address you're binding. The following is not perfect in that it doesn't account for quirks like having non-canonical addresses and two adapters with the same ip, etc. But besoverall, this sample function works great and should get you started.
#include <string.h> // strcmp
#include <net/if.h> // if_nametoindex()
#include <ifaddrs.h> // getifaddrs()
#include <netdb.h> // NI_ constants
// returns 0 on error
unsigned getScopeForIp(const char *ip){
struct ifaddrs *addrs;
char ipAddress[NI_MAXHOST];
unsigned scope=0;
// walk over the list of all interface addresses
getifaddrs(&addrs);
for(ifaddrs *addr=addrs;addr;addr=addr->ifa_next){
if (addr->ifa_addr && addr->ifa_addr->sa_family==AF_INET6){ // only interested in ipv6 ones
getnameinfo(addr->ifa_addr,sizeof(struct sockaddr_in6),ipAddress,sizeof(ipAddress),NULL,0,NI_NUMERICHOST);
// result actually contains the interface name, so strip it
for(int i=0;ipAddress[i];i++){
if(ipAddress[i]=='%'){
ipAddress[i]='\0';
break;
}
}
// if the ip matches, convert the interface name to a scope index
if(strcmp(ipAddress,ip)==0){
scope=if_nametoindex(addr->ifa_name);
break;
}
}
}
freeifaddrs(addrs);
return scope;
}
You're creating a socket in the AF_INET family, but then trying to bind it to an address in the AF_INET6 family. Switch to using AF_INET6 in your call to socket().

getsockname always returning 0.0.0.0?

Here is the code. It is the same as the code from this similar question: http://monkey.org/freebsd/archive/freebsd-stable/200401/msg00032.html. When I run it I always get the output:
listening on 0.0.0.0:54493 or something. Obviously the port changes, but I have no idea why I keep getting an IP address of 0.0.0.0. Am I missing something?
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sock;
int len = sizeof(struct sockaddr);
struct sockaddr_in addr, foo;
if((sock=socket(AF_INET, SOCK_STREAM, 0))<0)
{
exit(0);
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(0);
if(bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))<0)
{
perror("bind");
exit(0);
}
if(listen(sock, 5)<0)
{
perror("listen");
exit(0);
}
getsockname(sock, (struct sockaddr *) &foo, &len);
fprintf(stderr, "listening on %s:%d\n", inet_ntoa(foo.sin_addr),
ntohs(foo.sin_port));
return 0;
}
You specify INADDR_ANY rather than a specific IP address, so it binds to the wildcard (all interfaces) 0.0.0.0. So, when you call getsockname() that's what you get back.
If you specified 0.0.0.0 as the IP address rather than INADDR_ANY you would get the same behavior; you will bind to all network interfaces on the machine.
For example, lets say you only have one network interface with the IP 192.168.1.12 assigned to it. You also have the loopback by default - 127.0.0.1
Using 0.0.0.0 or INADDR_ANY means you'll be bound to both those addresses, rather than a specific one. You will be able to connect to to your process via either IP.
If you were to bind to a specific IP rather than INADDR_ANY, your process would only listen on that IP and you'd get back that specific IP with getsockname().
Yes, if you bind it to a LOOPBACK , u have to specify INADDR_LOOPBACK.
Otherwise it attaches itself to 0.0.0.0 which represents all the network interfaces available. I was facing the same problem, while issuing getnameinfo() call.
As mentioned in the other answers, 0.0.0.0 is returned because INADDR_ANY was specified as the host address for the listening socket. This makes sense if you think that, in a multi-homed host, client connections could come in on any of those interfaces (so which should be reported?)
Expanding on those answers; if the actual IP address of a client connection is required, use the SOCKET returned from accept() with getsockname(). This will provide the interface address on the server to which the client connected.

C, Linux: Receiving data from multiple multicast address on same port - how to distinguish them? [duplicate]

I have an application that is receiving data from multiple multicast sources on the same port. I am able to receive the data. However, I am trying to account for statistics of each group (i.e. msgs received, bytes received) and all the data is getting mixed up. Does anyone know how to solved this problem? If I try to look at the sender's address, it is not the multicast address, but rather the IP of the sending machine.
I am using the following socket options:
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
and also:
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
After some years facing this linux strange behaviour, and using the bind workaround describe in previous answers, I realize that the ip(7) manpage describe a possible solution :
IP_MULTICAST_ALL (since Linux 2.6.31)
This option can be used to modify the delivery policy of
multicast messages to sockets bound to the wildcard INADDR_ANY
address. The argument is a boolean integer (defaults to 1).
If set to 1, the socket will receive messages from all the
groups that have been joined globally on the whole system.
Otherwise, it will deliver messages only from the groups that
have been explicitly joined (for example via the
IP_ADD_MEMBERSHIP option) on this particular socket.
Then you can activate the filter to receive messages of joined groups using :
int mc_all = 0;
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
perror("setsockopt() failed");
}
This problem and the way to solve it enabling IP_MULTICAST_ALL is discussed in Redhat Bug 231899, this discussion contains test programs to reproduce the problem and to solve it.
[Edited to clarify that bind() may in fact include a multicast address.]
So the application is joining several multicast groups, and receiving messages sent to any of them, to the same port. SO_REUSEPORT allows you to bind several sockets to the same port. Besides the port, bind() needs an IP address. INADDR_ANY is a catch-all address, but an IP address may also be used, including a multicast one. In that case, only packets sent to that IP will be delivered to the socket. I.e. you can create several sockets, one for each multicast group. bind() each socket to the (group_addr, port), AND join group_addr. Then data addressed to different groups will show up on different sockets, and you'll be able to distinguish it that way.
I tested that the following works on FreeBSD:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
const char *group = argv[1];
int s = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "setsockopt: %d\n", errno);
return 1;
}
/* construct a multicast address structure */
struct sockaddr_in mc_addr;
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(group);
mc_addr.sin_port = htons(19283);
if (bind(s, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1) {
fprintf(stderr, "bind: %d\n", errno);
return 1;
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
char buf[1024];
int n = 0;
while ((n = read(s, buf, 1024)) > 0) {
printf("group %s fd %d len %d: %.*s\n", group, s, n, n, buf);
}
}
If you run several such processes, for different multicast addresses, and send a message to one of the addresses, only the relevant process will receive it. Of course, in your case, you probably will want to have all the sockets in one process, and you'll have to use select or poll or equivalent to read them all.
Use setsockopt() and IP_PKTINFO or IP_RECVDSTADDR depending on your platform, assuming IPv4. This combined with recvmsg() or WSARecvMsg() allows you to find the source and destination address of every packet.
Unix/Linux, note FreeBSD uses IP_RECVDSTADDR whilst both support IP6_PKTINFO for IPv6.
http://www.kernel.org/doc/man-pages/online/pages/man7/ip.7.html
Windows, also has IP_ORIGINAL_ARRIVAL_IF
http://msdn.microsoft.com/en-us/library/ms741645(v=VS.85).aspx
Replace
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
with
mc_addr.sin_addr.s_addr = inet_addr (mc_addr_str);
it's help for me (linux), for each application i receive separate mcast stream from separate mcast group on one port.
Also you can look into VLC player source, it show many mcast iptv channel from different mcast group on one port, but i dont know, how it separetes channel.
I have had to use multiple sockets each looking at different multicast group addresses, and then count statistics on each socket individually.
If there is a way to see the "receiver's address" as mentioned in the answer above, I can't figure it out.
One important point that also took me awhile - when I bound each of my individual sockets to a blank address like most python examples do:
sock[i].bind(('', MC_PORT[i])
I got all the multicast packets (from all multicast groups) on each socket, which didn't help. To fix this, I bound each socket to it's own multicast group
sock[i].bind((MC_GROUP[i], MC_PORT[i]))
And it then worked.
IIRC recvfrom() gives you a different read address/port for each sender.
You can also put a header in each packet identifying the source sender.
The Multicast address will be the receiver's address not sender's address in the packet. Look at the receiver's IP address.
You can separate the multicast streams by looking at the destination IP addresses of the received packets (which will always be the multicast addresses). It is somewhat involved to do this:
Bind to INADDR_ANY and set the IP_PKTINFO socket option. You then have to use recvmsg() to receive your multicast UDP packets and to scan for the IP_PKTINFO control message. This gives you some side band information of the received UDP packet:
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination address */
};
Look at ipi_addr: This will be the multicast address of the UDP packet you just received. You can now handle the received packets specific for each multicast stream (multicast address) you are receiving.

Resources