C Programming Using a specific Host IP to connect to server - c

I am looking at a machine with multiple IP address (ex ethernet and wireless) and need my client to connect to a server using a specific Client IP address. I can perform this easy in Java (done doing the Socket() with 4 args), but the only reference to use a specific host IP address that I can see is with using bind() but as far as I know that only is used for servers.
Synopsis:
Client has 2 IP address (ethernet and wireless) trying to connect to a server.. but using a specific IP (don't need to worry about "finding" the IP addresses as they will be in a config file or DEFINE
Not a windows only answer but a C programing that is portable (I use mac osx/linux usually but also windows)

I've never done this before but I think you can bind a socket to an ip address and then use connect with that socket. The pertinent section from here http://pubs.opengroup.org/onlinepubs/009695399/functions/connect.html states:
If the socket has not already been bound to a local address, connect()
shall bind it to an address which, unless the socket's address family
is AF_UNIX, is an unused local address.
Which implies that bind can be used before connect.

Your reference is correct. If you use bind(), then that address will be used to bind the client socket to the interface you want to use. bind() is not only used for server sockets.

https://beej.us/guide/bgnet/html/multi/syscalls.html#bind
By using the AI_PASSIVE flag, I'm telling the program to bind to the
IP of the host it's running on. If you want to bind to a specific
local IP address, drop the AI_PASSIVE and put an IP address in for the
first argument to getaddrinfo().

Related

Which function tells me what address the kernel bound the local socket to?

As a client I do a socket(), it gives me a number I store in sktnum. I then do a connect() with sktnum and the remote address. Hey presto, it succeeds, and I am told the kernel has selected a local IP address and port number (so as the server will know where to send back to). What function (linux C/C++) do I call to find out what port and IP address the kernel selected. (And please don't be one of those people who say "why do you want to know")
I'm not sure if I understand your question correctly. I understood it the following way:
Computer "A" uses socket() and connect() to establish a TCP connection to computer "B" which is using socket(), bind(), listen() and access().
The IP address and the TCP port on computer "B" is well known (of course - you connect to a certain TCP port on a certain computer).
But how is it possible to find out the IP address and the TCP port on computer "A" belonging to this connection?
The function which will do that on computer "A" is getsockname().
On computer "B" getpeername() will return that information.
If computer "B" has multiple IP addresses (e.g. multiple network cards) computer "B" may also use getsockname() to get its own IP address.
Before calling connect() the socket has no port number and no IP address, yet. So calling getsockname() before calling connect() makes no sense.
The reason for this is simple: If a computer has multiple network cards with different IP addresses the IP address on computer "A" side cannot be known before it is known which of the network cards must be used. (Note that localhost is seen as separate "network card" with the IP address 127.0.0.1 by the OS!)
EDIT
But I think you might only get ... 192.168. ... It doesn't give you the ... IP address you are alloted on the internet.
Your problem can be explained the following way:
The original idea of the internet was that every computer has its own global IP address (this is what you call: "addresses you are allocated on the internet").
There was never a change in this idea: Nearly any PC software (including the OS) is written for computers having a global IP address.
Because your provider can only give you one IP address your router is "fooling" your computers by "simulating" an internet where the local computers have global addresses (e.g. in the range 192.168.).
Because of this "simulation" the computer can behave exactly like 192.168.x.y is its global IP address in the internet. The computer does not even have any information about the fact that this is not a global IP address!
So it's clear that these functions return 192.168.x.y because the operating system "thinks" that this is the global address on the internet!
The only device that has information about the real global address (and about the real TCP port!!!) is the router!
Many providers use CGNAT which means that even multiple internet connections share one IP address. In this case the only device having that information is the provider's router.
If you need the real IP address and the real TCP port (as seen from the internet) you'll get that information from the router. Depending on the router model it will not be possible to get the information about the real addres.
I doubt that there is any router on the market which allows you to read out the real TCP port.
This was one reason why IPv6 was developed: With IPv6 any computer can have its own IP address again...

Prevent from getpeername() to return 127.0.0.1

I have a Server (A) and a client (B), written in C, running on the same Linux machine.
The server binds a port to INADDR_ANY, and the client binds another port to INADDR_ANY.
When another client (C), which is running on another Linux machine, connects to the server, I want the server to get the IP address of client B and send it to client C.
When I'm using getpeername() from the server, it returns "127.0.0.1" which is correct, but I can't send this address to client C- it won't be able to connect to client B with that address.
Is there any smart way to get the actual IP of client B?
If it is somewhat easier, I can make each client send it's IP to the server.
Thanks!
Use getifaddrs() to get the interface IP address, there's an example in the man page. Note that you can send the IP address of any interface since the server is bound using INADDR_ANY so it listens on all interfaces. From man ip(7)
When INADDR_ANY is specified in the bind call, the socket will be
bound to all local interfaces.
If you want the public IP address then refer to this question:
Get public/external IP address?
What you actually want to know is the IP address of the interface, which would be used to route towards client C.
With the Linux command line, you can do this (assuming C is 10.0.0.1):
# ip route show match 10.0.0.1
default via 20.0.0.2 dev eth0
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00
inet addr:20.0.0.3 Bcast:20.0.0.255 Mask:255.255.255.0
In this case, you'll want to use 20.0.0.3.
The question remains how to get all this in C.
One way would be to connect to some service on C, and run getsockname on the resulting socket.

Clarity on bind() socket function

While I was reading how to make a TCP client/server connection in C, I had a doubt about the bind() function.
I read that you need this function to "bind" a socket you've created to a local IPEndPoint, because the client/server connection takes a socket pair, made by LocalIP:LocalPort, RemoteIP:RemotePort. Thus my questions are:
What happens and what does the kernel do when a client doesn't call bind(), but calls connect() immediately after creating a socket (this is a common thing; I do it too in a client program, but I don't understand why I needn't to bind)?
... and above all ...
Why does a server program call bind(), specifying INADDR_ANY as the LocalIP address? I read that this constant is useful to specify a generic IP address, that is the server accepts data from anywhere on the Internet. But... is this a specification of a local IP address, or does it indicates where the clients can reach the server? I'm getting very confused...
1) You usually only need to call Bind if you want to create a server socket. There are some cases where it is required to establish a client socket, but more often than not, it is not necessary for for a client sockets. If you want to wait for incoming connections on a certain port, you have to bind to it. If you want to connect out to some IP and Port, there's no need to bind. The server socket's bind takes exclusive access to the TCP port. Nothing else can come online and bind to that port until your application closes or the socket is closed by you.
2) You are specifying which IP on the local computer to bind to. A single computer can have many IP addresses. Your computer may have a wired and wireless connection. Each has its own IP on the local network. You can specifically bind to one of those IPs and not the other. You could even have one application bound to port 473 (for example) on one IP and an entirely different application bound to port 473 on the other IP. If you specify INADDR_ANY, you are binding to all valid IPs the machine has. So it doesn't matter what IP the client used to get to you, it will work.
What happens and what does the kernel do when a client doesn't call bind(), but calls connect() immediately after creating a socket (this is a common thing; I do it too in a client program, but I don't understand why I needn't to bind)?
When you make an outbound connection without first binding the socket to an IP/port, the kernel will pick a source IP and port automatically, based on routing tables and what ports are available.
Why does a server program call bind(), specifying INADDR_ANY as the LocalIP address? I read that this constant is useful to specify a generic IP address, that is the server accepts data from anywhere on the Internet. But... is this a specification of a local IP address, or does it indicates where the clients can reach the server? I'm getting very confused...
What you've read is inaccurate -- the IP address in the sockaddr passed to bind() doesn't indicate where the server will accept connections from. It indicates what local IP addresses the socket should be attached to. INADDR_ANY indicates that you want to listen for connections on the specified port on any and all IP addresses attached to the machine. On servers with multiple IP addresses, it's often useful to specify one IP address to bind() to, so that other sockets can be bound to the same port on other IPs. It's also often useful to bind to a port on localhost only.

Verify TCP connection is from same machine by MAC address

Please don't criticise the solution. It's not my design and yes, it sucks.
On a computer running Linux, and using C, we need to verify that a TCP connection made to a process is from the same machine. Doing it by IP address is problematic since the OS is generating two IP addresses and the process only knows one. Anyway, verifying by IP address is a bit poor.
We want to do the verification by comparing the "remote" MAC address to the local MAC address. We already get the local MAC address. All I need to know is how to get the "remote" MAC address. It's in the packet that gets sent when forming the connection (and in all subsequent ones too). How do we drag it out of the ethernet layer?
Before anyone says this again, I KNOW you cannot get the MAC address of the remote host if it's not on the same subnet/LAN. That's fine. Presumably we'll get something like 00:00:00:00:00:00 and since that is different to the local MAC address it will be different - just what we want.
--
So, to summarise, we have a TCP connection socket fd, we've received a data packet, how do we then find the MAC address of the remote host, the MAC address that was in the packet's header?
If I understand correctly, you are not trying to tell remote machines apart, but to use the idea that the source and destination MAC would match on traffic sent from a machine to itself in order to allow only local traffic.
This seems rather roundabout, and has been pointed out, insecure.
A somewhat better idea might be to have the TCP client listen only on the loopback interface (127.0.0.1) and not on INADDR_ANY. Or go a step further and use a unix-domain socket instead of a TCP one (a common method used by X servers today to prevent the possibility of remote connections)
The MAC address of a live same-subnet TCP connection will almost certainly be in the ARP cache.
On Linux, you could examine the ARP cache by looking in /proc/net/arp. Here is what it looks like on my Ubuntu box:
aix#aix:~$ cat /proc/net/arp
IP address HW type Flags HW address Mask Device
10.0.0.32 0x1 0x2 00:1e:4f:f5:be:dc * eth0
10.10.10.1 0x1 0x2 00:1f:6c:3e:02:e3 * eth0
There's probably some callable API that you could use to get to the same data if you're averse to parsing the pseudo-file.
How about configuring a firewall (internal or external) to block or MAC-filter external traffic on the port in question?
A loopback connection (whether it's over the loopback interface or some other interface) it not routed over any ethernet device and therefore does not have a MAC address associated with it.
I suggest you just use getsockname and getpeername to get the local and remote IP address and compare that they are equal. That will work without any a priori knowledge of the configured IP addresses of your system.
Further, if you want to be IPv4/v6 agnostic, you could use getnameinfo with the NI_NUMERIC flag to convert both addresses to numeric string representations and strcmp them.

How to set local IP when originating TCP/IP connections?

Using Linux and glibc, when originating a TCP/IP connection (calling connect() on a socket), how can I choose explicitly from which of my IP local adresses I want to originate that connection, providing I have more than one interface (with different IPs) from where I can reach the remote host?
Is it possible to do so, or it is always up to the operating system IP stack to chose the route automatically?
Bind to a specific address instead of 0.0.0.0 or ::.

Resources