Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any purpose to `bind()` unix domain socket client processes?

When using AF_UNIX (unix domain sockets), is there any application to calling bind() in a process that never calls listen()?

In my systems programming lecture and lab, we are instructed to callbind() on a unix domain socket client processes. Is there any documented, undocumented, or practical application to calling bind on a client-only unix domain socket process? From my understanding bind() creates the special socket file, which is a responsibility a server process would undertake. Is this correct?

Here is an example code based off of what concepts discussed in class:

server.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

int main() {
    int s0, s1;
    struct sockaddr sa0 = {AF_UNIX, "a"};

    s0 = socket(AF_UNIX, SOCK_STREAM, 0);

    bind(s0, &sa0, sizeof(sa0) + sizeof("a"));
    listen(s0, 1);
    for (;;) {
        s1 = accept(s0, NULL, NULL);
        puts("connected!");
        for (;;) {
            char text[1];
            ssize_t n = read(s1, &text, sizeof(text));
            if (n < 1) {
                break;
            }
            putchar(text[0]);
        }
        close(s1);
    }
    close(s0);
    unlink("a");
    return 0;
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

int main() {
    int s0;
    struct sockaddr sa0 = {AF_UNIX, "b"};
    struct sockaddr sa1 = {AF_UNIX, "a"};
    socklen_t sa1_len;

    s0 = socket(AF_UNIX, SOCK_STREAM, 0);
    bind(s0, &sa0, sizeof(sa0) + sizeof("b")); // What does this do??
    connect(s0, &sa1, sizeof(sa1) + sizeof("b"));
    for (;;) {
        int c = fgetc(stdin);
        if (c == EOF) {
            break;
        }
        write(s0, &c, sizeof(c));
    }
    close(s0);
    unlink("b");
    return 0;
}
like image 748
Winny Avatar asked Dec 07 '17 20:12

Winny


People also ask

What are UNIX domain sockets used for?

Unix Domain Socket is a way for data communication to occur bi-directionally on the same system. Sockets including Unix Domain Sockets are an important part of Inter-process communication, a beneficial method in which different programs on the same system can communicate with each other.

When would you use a socket bind?

The bind() method of Python's socket class assigns an IP address and a port number to a socket instance. The bind() method is used when a socket needs to be made a server socket. As server programs listen on published ports, it is required that a port and the IP address to be assigned explicitly to a server socket.

How do you bind a socket in Unix?

After a UNIX domain socket is created, you must bind the socket to a unique file path by using the bind function. Unlike internet sockets in the AF_INET domain where the socket is bound to a unique IP address and port number, a UNIX domain socket is bound to a file path.

Is Unix domain socket secure?

More than other sockets and pipes, a Unix® domain socket is secure. Domain sockets will not allow a non-trusted network to listen to the data stream, and remote computers cannot connect to the stream without access.


1 Answers

The call to bind() is only required if you need to receive a connection with SOCK_STREAM type socket, but bind() behavior depends on the domain of the SOCKET. There is a manual page dedicated to this.

Useful information:

Address format

A UNIX domain socket address is represented in the following structure:

#define UNIX_PATH_MAX    108

struct sockaddr_un {
    sa_family_t sun_family;               /* AF_UNIX */
    char        sun_path[UNIX_PATH_MAX];  /* pathname */
};

Three types of address are distinguished in this structure:

  • pathname: a UNIX domain socket can be bound to a null-terminated file system pathname using bind(2). When the address of the socket is returned by getsockname(2), getpeername(2), and accept(2), its length is offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1, and sun_path contains the null-terminated pathname.

  • unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name. Likewise, the two sockets created by socketpair(2) are unnamed. When the address of an unnamed socket is returned by getsockname(2), getpeername(2), and accept(2), its length is sizeof(sa_family_t), and sun_path should not be inspected.

  • abstract: an abstract socket address is distinguished by the fact that sun_path[0] is a null byte ('\0'). The socket's address in this namespace is given by the additional bytes in sun_path that are covered by the specified length of the address structure. (Null bytes in the name have no special significance.) The name has no connection with file system pathnames. When the address of an abstract socket is returned by getsockname(2), getpeername(2), and accept(2), the returned addrlen is greater than sizeof(sa_family_t) (i.e., greater than 2), and the name of the socket is contained in the first (addrlen

  • sizeof(sa_family_t)) bytes of sun_path. The abstract socket namespace is a nonportable Linux extension.

Binding to a socket with a filename creates a socket in the file system that must be deleted by the caller when it is no longer needed (using unlink(2)). The usual UNIX close-behind semantics apply; the socket can be unlinked at any time and will be finally removed from the file system when the last reference to it is closed.


So:

  • bind() is not necessary in a client.
  • bind() in your context give a name to yours sockets "a" and "b"
  • bind(s0, &sa0, sizeof(sa0) + sizeof("b")); and similar line in yours code are undefined behavior; it gives a wrong size to bind() that exceeds the bound of &sa0. The correct code is bind(s0, &sa0, sizeof sa0);
  • bind() in this context (Linux, AF_UNIX) does create a special socket file; if you want to remove it, you must call unlink() or remove().
like image 134
Stargateur Avatar answered Sep 21 '22 11:09

Stargateur