Using socket in C how can I send message from IPv6 to IPv4? - sockets

I tried to convert the destination address to IPv6 format as ::ffff:IPv4. And use a socket of AF_INET6 type. It gives error: Network Unreachable. But using the same technique I am able to communicate from IPV4 to IPV6
Thanks for your help in advance.

IPv4 and IPv6 are separate protocols. They don't talk to each other.
On some operating systems you can use an IPv6 socket and accept incoming IPv4 connections on it. But that is just a software thing to make code development easier for server code. I have never seen that work for client code. You'll have to create the right socket type for that.
Usually you resolve a hostname using DNS, you'll get multiple answers (IPv4 and IPv6), you iterate over them creating the required socket type and try to connect. If it works you use that socket, if not you do the next iteration which creates a new socket etc.
If you code that is sensitive to delays you might want to implement the happy eyeballs algorithm.

On most systems, PF_INET6 sockets are able to communicate with IPv4 addresses by using addresses in the ::FFFF:0:0/96 range. However, this is only done at the level of the sockets library: the actual on-the-wire data are plain IPv4 packets (as though you had used an PF_INET socket), there is no protocol conversion in the network.
The error you receive indicates that you have no IPv4 route to the requested destination. This probably indicates that your host doesn't have an IPv4 default route. There is no solution to that — without IPv4 connectivity, there is nothing you can do to reach an IPv4 address.

Related

How to bind socket to a specific network interface and to any ports and any IP on that interface

I have a hardware attached to my RPI board running Linux distro. This hardware & its associated Host stack has created a network interface called wpan0 and assigned some IPV6 addresses to it (I am able to ping the IPV6 address from a remote device in the same network)
Now, I want to enable data communication to this interface to any IPV6 IP assigned to the interface. How do I create and bind a socket to this interface? Also, I want to listen to any ports on this interface. How to achieve this?
How you create a socket depends on the language you use (you didn't specify), but when you want to bind a socket to ANY interface the IPv4 way is to listen to IP 0.0.0.0, the IPv6 equivalent is ::/0, that means all zeros/0 bits CIDR mask.
Redirecting all ports to one is less of a code issue and requires some hands on with IPTables and Prerouting (you can write some code that appends that to your conf file though), here is an example:
https://serverfault.com/questions/616535/iptables-destination-ip-and-port

Why does grpc convert all ipv4 addresses into ipv6 to start a tcp server

According to native GRPC implementation, here: https://github.com/grpc/grpc/blob/master/src/core/lib/iomgr/tcp_server_custom.cc#L381
all ipv4 addresses are changed into ipv6 before the socket is opened here:
https://github.com/grpc/grpc/blob/master/src/core/lib/iomgr/tcp_uv.cc#L191
At least on CentOS this leads to grpc server being unable to start listening.
Can anyone please clarify why was this conversion made, why not just forward all ipv4 and ipv6 addresses straight into the socket and let them be managed by their original addresses?
Right now I am considering commenting this conversion out because I need this server on the environment without ipv6, but I am not sure if I am going to break anything by doing this...maybe there is some hidden dependency on the fact that we are always listening on ipv6 address?

UDP client/server: Mix IPv4 and IPv6?

Let's say you have a game server, UDP only, running on a server which has both IPv4 and IPv6 addresses. The server starts up, calls getaddrinfo() to loop through available addresses, and let's say it grabs the IPv6 address. So it creates it's socket on IPv6 and waits for packets from clients.
A client tries to connect, but this time it's using an IPv4 address entered by the user. It creates a IPv4 socket, and tries to connect to the server. Does the difference actually matter? Or does the difference between a IPv4 socket and a IPv6 socket stop at the local machine?
Likewise, if the client has already created, say, a IPv6 socket for use (because getaddrinfo() said it was valid), and then it calls getaddrinfo() to find a server's address, what if it only gets a IPv4 result? I know I can tell getaddrinfo() to only give IPv6 results, but what if the server doesn't have an IPv6 address? Are UDP clients supposed to close and recreate their sockets to match the server address format? Or am I guaranteed to get the address format I ask for?
(I welcome any documentation references that answer these questions. I've been researching for hours but haven't found clear answers to these points yet.)
By default, the IPv6 UDP socket will send and receive only IPv6 UDP packets, so your IPv4 client would be out of luck.
However, if you are running on a dual-stack machine (and you probably are), you can enable IPv4-mapped IPv6 addresses on the socket, and then you can use that socket to handle both IPv4 and IPv6 UDP traffic. IPv4 packets will show up as coming from a specially-formed IPv6 address (with a form like e.g. "::ffff:192.168.0.5") but otherwise they are handled the same way as any IPv6 UDP client would be.
You can enable IPv4-mapped IPv6 addresses on your socket like this:
int v6OnlyEnabled = 0; // we want v6-only mode disabled, which is to say we want v6-to-v4 compatibility
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled)) != 0) perror("setsockopt");
The other approach would be to create separate IPv4 and IPv6 sockets as necessary (on the client and/or server), but as long as you have a dual-stack networking stack available, the IPv4-mapped IPv6-addresses approach is much easier to work with.

Can I bind a client socket to an ip not belongs to any interfaces?

For a client socket, I can use bind() to bind it to a specific source Ip address to select a specific interface. Or I can use connect() directly then it will pick the source ip based on routing table.
I wonder can I bind a client socket to an ip not belongs to any interfaces ? E.g.: I have two interfaces:
eth0 : ip0
eth1 : ip1
(1) If I bind the client socket to ip2. Is this feasible ?
(2) If (1) is feasible, assuming client socket sent packets thru eth0. Then I configure the iptables in this client host, to forward all incoming packets to ip0 (eth0). In this case, if there are packets sent back from server side with destination ip address is ip2 (assuming this packet will reach my client host). Will my client socket receive the packet ?
Thanks in advance.
I don't really understand your question, but here goes:
For client sockets, you typically want the the OS and its routing table to pick the best interface for you using any available port. In which case, you bind to INADDR_ANY (0) and port 0. Or don't explicitly call bind at at all. Just call connect() and it will do the right thing.
If you need the client connection to occur through a specific interface, then bind the socket to a specific IP address. And then the OS will attempt to use that interface for the subsequent connect call and all traffic after that.
Attempting to bind the socket to an IP that doesn't belong to a local interface is surely going to result in an error.
Not sure what you mean about the iptables stuff. Sounds dicey.
Please have a look at:
https://www.rsyslog.com/doc/v8-stable/configuration/modules/omfwd.html#ipfreebind
MAN:
https://man7.org/linux/man-pages/man7/ip.7.html
IP_FREEBIND (since Linux 2.4)
If enabled, this boolean option allows binding to an IP
address that is nonlocal or does not (yet) exist. This
permits listening on a socket, without requiring the
underlying network interface or the specified dynamic IP
address to be up at the time that the application is
trying to bind to it. This option is the per-socket
equivalent of the ip_nonlocal_bind /proc interface
described below.

Obtaining the source IP and port of an INADDR_ANY client socket before the TCP three-way handshake?

I'm on Windows 7, using bind before connect with SO_REUSEADDR, and setting the local address structure to IP address INADDR _ANY and port 0 (zero), in order to let the operating system select the source details for a client socket.
Firstly, I've read that it's not possible to get the source IP before connecting to the server, since it's being chosen at this point and several addresses can be valid. But the port is selected before the connection, so is there a way to get it? (getsockname() looks like to not work).
Secondly, about the source IP, is there a way to get it before a packet is sent to the server? I need the specific time between the moment the OS selected the source IP and the moment it starts the three-way handshake. The connect() function dominates the both.
I'm on Windows 7, using bind before connect with SO_REUSEADDR
Why are you using SO_REUSEADDR in this situation? You don't need it, and it makes no sense for what you are attempting. SO_REUSEADDR should typically only be used for a listening socket, not a connecting socket.
setting the local address structure to IP address INADDR _ANY and port 0 (zero), in order to let the operating system select the source details for a client socket.
It is meaningless to bind() a client socket to INADDR_ANY:0. You can (and should) omit such a bind() completely and leave the socket unbound until connect() is called. The only time you should ever bind() a client socket is if you want to bind it to a specific local IP and/or Port. But you are not doing that in this situation, so get rid of it.
Firstly, I've read that it's not possible to get the source IP before connecting to the server, since it's being chosen at this point and several addresses can be valid.
Correct, unless you bind() to a specific source IP.
But the port is selected before the connection
Both source IP and source port are selected by connect() if the socket is unbound, or bound to source IP INADDR_ANY and/or source port 0. So you have no opportunity to query either value before connect() has selected them.
so is there a way to get it? (getsockname() looks like to not work).
getsockname() is exactly what you need. Just make sure you are not calling it until connect() has successfully connected to the server first. This is stated in the getsockname() documentation:
This call is especially useful when a connect call has been made without doing a bind first; the getsockname function provides the only way to determine the local association that has been set by the system.
...
The getsockname function does not always return information about the host address when the socket has been bound to an unspecified address, unless the socket has been connected with connect or accept (for example, using ADDR_ANY). A Windows Sockets application must not assume that the address will be specified unless the socket is connected. The address that will be used for the socket is unknown unless the socket is connected when used in a multihomed host. If the socket is using a connectionless protocol, the address may not be available until I/O occurs on the socket.
Secondly, about the source IP, is there a way to get it before a packet is sent to the server?
For TCP, you can retrieve the selected source IP using getsockname() immediately after connect() has successfully connected to the server. Not before.
I need the specific time between the moment the OS selected the source IP and the moment it starts the three-way handshake.
It is not possible to determine that detail. No socket application should ever need that detail. Why do you need it?
I'm on Windows 7, using bind before connect with SO_REUSEADDR, and setting the local address structure to IP address INADDR _ANY and port 0 (zero), in order to let the operating system select the source details for a client socket.
Why? That's exactly what happens if you don't call bind() at all, during connect(). Binding a client socket to INADDR_ANY isn't correct in any case. Setting SO_REUSEADDR doesn't make sense either without specifying a non-zero port number. Just remove all this.
Firstly, I've read that it's not possible to get the source IP before connecting to the server, since it's being chosen at this point and several addresses can be valid.
Correct.
But the port is selected before the connection, so is there a way to get it?
Yes. getsockname().
(getsockname() looks like to not work)
Doesn't work how?
Secondly, about the source IP, is there a way to get it before a packet is sent to the server?
You can get it with getsockname() as soon as connect() has succeeded, but this involves sending packets to the server.
I need the specific time between the moment the OS selected the source IP and the moment it starts the three-way handshake. The connect() function dominates the both.
Bad luck.