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.
Related
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.
I have a function which initiates the socket connection. I am trying to a server with a name let's say xp. Socket() is working fine. But when it comes to connect, I am getting an error. I tried to get the IP of that server, I got some random IP. I passed the parameters to the connect API. I print the results of these in a log file. I think error lies within the connect(). I am working on Linux Ubuntu. Here is my program for SocketInit(). I can't get the error with that.
I call the SocketInit function as
SocketInit(argv[2]); argv[2] has my server name.
short SocketInit(char *xp)
{
if ( (local_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("socket creation is unsuccessful check in SocketInit() \n");
sprintf(log_msg, "create socket descriptor error = %d", errno);
LogMsg('E', log_msg);
return(-1);
}
else
{
printf("socket connection is success\n");
}
pos_socket.sin_family = AF_INET;
pos_socket.sin_port = htons(port_no);
pos_socket.sin_addr.s_addr = inet_addr(xp);
if ( connect( local_socket, (struct sockaddr *) &pos_socket, sizeof(pos_socket) ) < 0 ) {
sprintf(log_msg, "connect on socket error=%d", errno);
printf("socket connect api is unsuccessful check in SocketInit() \n");
LogMsg('E', log_msg);
return(-1);
}
else{
printf("connect is successful\n");
return 0;
}
}
How can I connect to the server. How can I pass the address to the pos_socket.sin_addr.s_addr ? Sometimes I get connect error 110 and 111. But still I can't connect.
Use perror() to print the human-readable error string when connect() or most other unix-like system calls return an error. But since you told us the value of errno, I looked in errno.h for the meaning, and found:
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
(BTW, you cannot count on errno's being the same from one unix to another which is why you need to use these defines when checking for specific errors. Never hard-code numeric errno values into your code. It worked out for me this time, but it won't necessarily every time).
ECONNREFUSED means that there was a machine listening at the specified IP address, but that no process was listening for connections on the specified port number. Either the remote process is not running, it is not binding or accepting connection properly, or it potentially could be blocked by some sort of firewall.
In any case, this points to a problem with the server.
So, check to make sure your remote process is actually ready to accept the connection. You can use telnet or netcat as a test client to see if other client programs that are known to work are able to connect to your server.
Also, I notice that your variable port_no is not declared, so we have no way of knowing what port you are trying to connect to.. but make sure that this variable is of the correct type and has the correct value for the service you are trying to connect to. If port_no doesn't specify the correct port you will get the same type of error.
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.
I have a situation in which I intend to communicate with a service through a command interface made available via a UNIX-domain socket on the file system. I am able to successfully send it commands, but for a while sat perplexed as to why I could not receive any response to my queries.
As it turns out, the service did not have sufficient permissions to write to the address I (or the OS) provided for it. However, I realized that if I explicitly bind to an address on the file system then I could adjust the file permissions by leveraging chmod.
Something like:
int mySocket;
struct sockaddr_un local_addr;
mySocket = socket(AF_UNIX, SOCK_DGRAM, 0);
local_addr.sun_family = AF_UNIX;
snprintf(local_addr.sun_path, 108 "/path/to/mySocket");
bind(mySocket, (struct sockaddr *) &local_addr, sizeof(struct sockaddr_un));
chmod("/path/to/mySocket", 777);
That is to say, without the final chmod step, the service is unable to write to mySocket because it does not have the appropriate write permissions. Obviously, this is an even harder problem to spot if one does not explicitly bind to a specific address, since the underlying OS will implicitly generate this socket for the user - but it still exists and still will have the same access problems.
My question, then, is with respect to this final step. Is there a way to allow the OS to implicitly generate the socket for my endpoint (i.e. the address to which the service will respond) but request that it be given certain permissions?
The Explanation
The reason this issue is becoming a problem is due to the requirement that other portions of the program be executed as root. As such, when I, as root, attempt to connect/send to the background service, the OS will implicitly create an address to which replies will be directed. However, this leads to the problem that my socket-file, whether implicit or created with bind, will have permissions like srw- --- ---, so the other endpoint can only reply if they, too, elevate themselves.
Thus, the problem goes away if I first bind and then chmod the permissions as I showed above.
Is there a way to allow the OS to implicitly generate the socket for my endpoint (i.e. the address to which the service will respond) but request that it be given certain permissions?
I solved this very problem once using two calls to umask().
Pseudo code:
current_mask = umask(umask_to_be_used_on_afunix_socket_file_system_entry_creation);
bind afunix socket here
umask(current_umask);
[edited] My first guess would be to instead use a fifo, which lets you create file first and set its permissions. Also, if two users are to communicate through the fifo, it's best to use group-level read/write and have them in the same group.
$ mkfifo -m 660 fifo_name
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
As sherrellbc mentions, this is unrelated to unix sockets. If you are forced into using sockets, why not drop permissions before creating it? This seems like an important step when running suid anyway.
struct sockaddr_un to_addr;
memset(&to_addr, 0, sizeof(struct sockaddr_un));
strncpy(to_addr.sun_path, "/path/to/socket", sizeof(to_addr.sun_path) - 1);
to_addr.sun_family = AF_UNIX;
/* ------------ change user ------------ */
if(setgid(new_gid) || setuid(new_uid))
goto error;
handle_conn(&to_addr, sizeof(struct sockaddr_un));
int handle_conn(struct sockaddr *to_addr, socklen_t addrlen) {
int to_sock;
int ret;
pid_t pid;
if( (to_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
goto error;
}
if(connect(to_sock, to_addr, addrlen)) {
close(to_sock);
goto error;
}
...
close(to_sock);
}
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.