Does the bind() function in linux can modify its argument ? I ask this because a sin_port of 0 means that the OS will choose the port, and I would like to get this port after this call.
No, it does not modify the argument. Instead you use getsockname after binding to find out what port you got.
You can also use getsockname after connect to get both the local port assignment and the local address (if you have more than one address) correspomnding to the route to the remote host. This works even with UDP where connect doesn't actually send any packets and only logically binds addresses.
Related
In C, I can bind a client socket to a specific local address and a system-selected port. What would happen if any of the following happened?
The local address of the machine is changed
The program is moved to a host with a different local address
And what would happen if I attempt to bind after calling connect()?
Well, in general, a TCP socket connection is really identified by the source IP, source port, destination ip, destination port tuple. If say the source IP is not valid any more then neither end can recover from it and the destination host will not probably notice until after a timeout.
If on the other hand you're trying to bind to an address that is not local at that time, the bind system call should return an error (EADDRNOTAVAIL).
Finally, rebinding a connected TCP socket should result in an error because it doesn't make any sense.
Note: the question was edited.
I have few questions on Berkeley Socket Programming:
Is it possible to change a socket address after binding? If so- What are the C commands to do so?
2.According to https://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html, when a socket is bind to INADDR_ANY, it receives packets from all interfaces, but when a packet is sent,(using sent command) it sends through a single NIC with the default IP.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y. This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
Is it true? And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs(and not the previous NIC)? Can we do so if the NICs have the default IP address?
Can we send packets through one NIC, and set the IP destination to another NIC? (I.e, NIC1 will only send packets, and NIC2 will only receive packets )
Is it possible to change a socket address after created?
Sockets don't have an IP address to change when created. They get one when bound.
If so- What are the C commands to do so?
The Berkeley Sockets API functions to do so are bind() and connect().
When a socket is bind to INADDR_ANY, it receives packets from all interfaces, but sends through a single NIC with the default IP.
No. It sends packets via whichever NIC is necessary to reach the target in each case.
Your cited source draws a distinction without a difference. A socket bound to INADDR_ANY receives packets from any interface. There is no difference between 'any' and 'all' as far as INADDR_ANY is concerned. It is far easier to understand as 'any'.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y
No. It sends the packet with the same source address the client originally connected to. That's part of what defines the connection.
This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
No. The destination in the packet is the client's IP address. Otherwise it wouldn't even get there. This is just nonsense. If you mean the source IP, see above.
Is it true?
No.
And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
No. INADDR_ANY means exactly what it says. Any IP address: any NIC.
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs (and not the previous NIC)?
No, but you can alter the IP routing tables.
Can we do so if the NICs have the default IP address?
Only one of them can have the default IP address. The question doesn't make sense.
Can we send packets through one NIC, and set the destination to another NIC?
Only if you're sending to yourself. Otherwise the question doesn't make sense.
(from your citation) When sending, a socket bound with INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface
I hope this refers to whatever simulator is being described. If it is meant to be a description of how TCP works it is wrong.
I was seeing EADDRNOTAVAIL errors in connect() calls. I dig deeper found that naming of sockets were being done of over zero ip addresses . See following where both calls were sucessful:-
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&y, sizeof(y)); /* y is int with value 1 */
bind(s, (struct sockaddr *)lockaddr, sizeof(rtinetaddr_tp));
where
lockaddr={.sin_family=2, .sin_port=0, .sin_addr={.s_addr=0}, .sin_zero=""}
This, I found in RH site and also I have the same kernel.
My question is what if I remove doing any bind() at client side of the application? Will that be a quick cure OR will lead to any disaster?
Other way I have running sample programs without bind at client. But the app I am talking about that establishes hundreds of connections. So what may happen in worst case?
Binding to a zero address is the same as binding to INADDR_ANY (which is defined as zero). This means you can make a connection on any local IP address (server side) or use the egress interface IP address (client side). This is quite normal.
If you are not interessed in using any particular address:port on the client side, the calls to bind() aren't necessary.
The Kernel will chose the suitable interface and a random port to establish the outgoing connection initiated by the client's call to connect().
When I create a socket, and bind it to a port, it will tell me that the socket is listening on the assigned port. For example,
Create socket.
Bind to port 7006
However, when I connect to another location, the port number appears to change from the outside only. As in, everything works as it should, it just looks like the port is different, and I want to know why.
A server program that took a connection from this socket, bound to 7006, said the address was
localhost:42566
A SOCK_DGRAM socket I made and bound to port 7008 read this address from recvfrom
localhost:a3fs-fileserver
I figure the a3fs-fileserver is just interpreted that way because it happened to have the port typically associated with a3fs-fileserver and getnameinfo tries to get and english service name when possible.
But why does it look different outside my program than inside? Note: This behavior works the same way between machines as well, I just happened to be testing on one for convenience.
I'm following Beej's guide on NP.
I did a few modifications and am trying to obtain the IP of my server program through getaddrinfo().
(original can be found here http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#simpleserver)
Below is the parts I've changed/added.
if ((rv = getaddrinfo(NULL, "0", &hints, &servinfo)) != 0) { //0 for random port?
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
//... some code emitted ...
//freeaddrinfo(servinfo); //I still need it!
printf("ip: %s\nport: %d\n",
inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, ip4, INET_ADDRSTRLEN),
ntohs(((struct sockaddr_in *)p->ai_addr)->sin_port)
);
The problem is that I get results
ip: 0.0.0.0
port: 0
Q1:I've read from a couple of websites saying that setting "0" for the port tells the OS that you want the next available port, not actually 0. Is this true?
Q2:I've also read that gethostbyname(gethostname(...)) can give you the machine's ip, but Beej said that these are superseded by getaddrinfo(). So, am I supposed to use getaddrinfo? Or gethostbyname?
Q3:Is there anything else I'm doing wrong?
It's returning exactly what you would expect it to.
From man getaddrinfo:
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 wild‐card 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.
The code you link to sets hints.ai_flags to AI_PASSIVE and you're passing NULL for node. The wildcard address is 0.0.0.0. Working as specified. Binding to that address means you're binding to every IP address on your machine.
As for the port ... you're specifying "0" which ... is exactly what you're getting back. You need to set it an actual port you wish to listen on as the example code you link to does.
Q1:I've read from a couple of websites saying that setting "0" for the port tells the OS that you want the next available port, not actually 0. Is this true?
Yes, but only after you have used bind() to attach the address to a real socket. At that point, use getsockname() to get the bound address from the socket; the port will be part of that.
Q2:I've also read that gethostbyname(gethostname(...)) can give you the machine's ip, but Beej said that these are superseded by getaddrinfo(). So, am I supposed to use getaddrinfo? Or gethostbyname?
Use getaddrinfo(); it does all that gethostbyname() did and more, and the interface sucks a lot less. (For example, it's typically thread-safe.)
Q3:Is there anything else I'm doing wrong?
There's no good defined concept of the server's IP address. Servers can have many due to things like multiple network cards (much more common for servers than desktop systems), and the one that the outside world knows it by might not be one of them (thanks to NAT firewalls). Occasionally, you can know exactly where the messages are coming from before the client connects — the most common option is to know that the client will be on localhost — which is part of the information you set during bind() but that's rare. You can find the address of the client once the connection has happened by using getpeername() but NAT might still make that functionally useless. Such addresses are typically set in the app's config file during deployment.
If you only need the info for logging purposes, go right ahead. But beware of using it for anything else, as it doesn't actually tell you that much.