Linux/Unix Socket Self-Connection

Linux/Unix Socket Self-connection

We can simple reproduce this phenomenon with the following python program

import socket
for i in range(65536):
try:
s = socket.create_connection(('127.0.0.1', 50000))
print 'connected to {0}'.format(s.getpeername())
except Exception as e:
pass

when we try to connect some socket in the same host. if we don't bind your client to a specific port, operating system will provide ephemeral port for you. if it's happened to be the one you want to connect to. it causes self connection. Make sure the port you are trying to connect is in /proc/sys/net/ipv4/ip_local_port_range

Can one reliably connect a TCP socket to itself?

The most straightforward approach would be to bind to the loopback adapter. Just listen to 127.0.0.1 on some arbitrary port and the connect to that.

The problem with this approach is that the port is global on the machine, so that means other programs can connect to it too, and if you have multiple programs you might run into conflicts or conceivably exhaust all the possible ports.

Another approach is to use Unix domain sockets, but this is not supported on Windows.

TCP simultaneous open and self connect prevention

For server you need to bind() socket to port. Once addr:port pair had socket bound, it will no longer be used for implicit binding in connect().

No problem, no trouble.

Identify program that connects to a Unix Domain Socket

Yes, this is possible on Linux, but it won't be very portable. It's achieved using what is called "ancillary data" with sendmsg / recvmsg.

  • Use SO_PASSCRED with setsockopt
  • Use SCM_CREDENTIALS and the struct ucred structure

This structure is defined in Linux:

struct ucred {
pid_t pid; /* process ID of the sending process */
uid_t uid; /* user ID of the sending process */
gid_t gid; /* group ID of the sending process */
};

Note you have to fill these in your msghdr.control, and the kernel will check if they're correct.

The main portability hindrance is that this structure differs on other Unixes - for example on FreeBSD it's:

struct cmsgcred {
pid_t cmcred_pid; /* PID of sending process */
uid_t cmcred_uid; /* real UID of sending process */
uid_t cmcred_euid; /* effective UID of sending process */
gid_t cmcred_gid; /* real GID of sending process */
short cmcred_ngroups; /* number or groups */
gid_t cmcred_groups[CMGROUP_MAX]; /* groups */
};

unix socket creation then fork(), messaging gets mixed up

I did some additional research and there is another way to do this, I learned about pthread_atfork() which sets up functions to be called by the parent and the child upon fork.. i actually used this mechanism to stop and start the network functionality on the child, and it worked!

https://linux.die.net/man/3/pthread_atfork

Calling open() on a Unix domain socket failed with error No such device or address

The /tmp/pipe1 is not a pipe file. It's a socket file. That's what the leading s means in srwxr-xr-x.

And Bash's redirection like > does not support socket files. You need to use socket API to open the file.


With strace (e.g. strace bash -c 'echo > /tmp/sockfile') we can see:

...
openat(AT_FDCWD, "/tmp/sockfile", ...) = -1 ENXIO (No such device or address)
...

So the error code is ENXIO whose corresponding error message is No such device or address. Bash is just calling standard C API (like strerror) to print the error.


Exampe code for client side:

int
sock_connect(char * sockpath)
{
int sock_fd;
struct sockaddr_un srv_addr = { 0 };

sock_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (sock_fd < 0) {
return -1;
}

srv_addr.sun_family = AF_LOCAL;
snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s", sockpath);
if (connect(sock_fd, (struct sockaddr *) & srv_addr, sizeof(srv_addr)) < 0) {
return -1;
}

return sock_fd;
}

HTTP over AF_UNIX: HTTP connection to unix socket

So long as your socket is a stream socket (SOCK_STREAM rather than SOCK_DGRAM) then it's technically possible. There's nothing in HTTP that requires TCP/IP, it just requires a reliable bidirectional stream.

However I've never seen an HTTP client that knows how to connect to such a socket. There's no URL format that I know of that would work, should you actually need to use a URL to talk to the server.

Also note that some things that normal web servers depend on (such as getpeername(), to identify the client) make no sense when you're not using TCP/IP.

EDIT I just saw your edit about mapping localhost to the UNIX socket. This is perfectly feasible, you just need to ensure that the client knows how to find the path of the UNIX socket that should be used instead of connecting to 127.0.0.1:xxx



Related Topics



Leave a reply



Submit