Post

Overcoming 'Too Long for Unix Domain Socket' Errors in SSH Git Cloning

Summary

This article will go through why we may will run into ... too long for Unix domain socket issue when git clone with SSH after they configure the ControlMaster and ControlPath to accelerate the SSH connection.

Scenario

When using SSH, people may want to speed up the SSH connection establishment with configuration of ControlMaster and ControlPath. According to the ssh_config man page:

1
2
3
4
5
ControlMaster
Enables the sharing of multiple sessions over a single network connection...

ControlPath
Specify the path to the control socket used for connection sharing as described in the ControlMaster section above or the string ''none'' to disable connection sharing...

This means that with multiple SSH session with the control socket to speed up the SSH connection establishment.

Issue

When we try to pull git repo from CodeCoommit, we may run into the following error:

1
2
3
4
5
6
$ git clone ssh://git-codecommit.xxx.amazonaws.com/v1/repos/xxx
Cloning into 'xxx'...
unix_listener: "/Users/xxxxxxxxxx/.ssh/master-xxx@git-codecommit.xxx:22" too long for Unix domain socket
Cloning into 'xxx'...
unix_listener: "/Users/xxxxxxxxxx/.ssh/master-xxx@git-codecommit.xxx:22" too long for Unix domain socket
fatal: Could not read from remote repository.

And from the ~/.ssh/config, we can see the following configuration:

1
2
3
host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

Explanation

Unix socket path length

The messages unix_listener: ... too long for Unix domain socket is from the function to create socket (source code):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int
unix_listener(const char *path, int backlog, int unlink_first)
{
	struct sockaddr_un sunaddr;
	int saved_errno, sock;

	memset(&sunaddr, 0, sizeof(sunaddr));
	sunaddr.sun_family = AF_UNIX;
	if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
		error("%s: \"%s\" too long for Unix domain socket", __func__,
		    path);
		errno = ENAMETOOLONG;
		return -1;
	}

We can see that if the socket path is longer then sizeof(sunaddr.sun_path), and then we will get the error message unix_listener: ... too long for Unix domain socket. In unix socket man page, it describes that the length of sun_path is 108 char (source code):

1
2
3
4
5
6
#define UNIX_PATH_MAX    108

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

SSH config for ControlPath

Why the socket path in the use case is longer than 108 char? When configuring the ControlPath parameter as ~/.ssh/master-%r@%h:%p, according to the ssh_config man page, this means the following, :

1
2
3
host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

Explanation

The messages unix_listener: ... too long for Unix domain socket is from the function to create socket (source code):

1
2
3
4
5
6
7
8
9
10
11
12
13
int
unix_listener(const char *path, int backlog, int unlink_first)
{
 struct sockaddr_un sunaddr;
 int saved_errno, sock;
 memset(&sunaddr, 0, sizeof(sunaddr));
 sunaddr.sun_family = AF_UNIX;
 if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
 error("%s: \"%s\" too long for Unix domain socket", __func__,
     path);
 errno = ENAMETOOLONG;
 return -1;
 }

We can see that if the socket path is longer then sizeof(sunaddr.sun_path), then we will get the error messages unix_listener: ... too long for Unix domain socket. In unix socket man page, it describes that the length of sun_path is 108 (source code):

1
2
3
4
5
#define UNIX_PATH_MAX    108
struct sockaddr_un {
    sa_family_t sun_family;               /* AF_UNIX */
    char        sun_path[UNIX_PATH_MAX];  /* pathname */
};

And why the socket path in the use case is longer than 108? When the configuration of the ControlPath as ~/.ssh/master-%r@%h:%p, which means the following, according to the ssh_config man page:

  • ‘%h’: target host name
  • ‘%p’: the port
  • ‘%r’: the remote login username

With AWS CodeCommit, the remote login user name is the SSH key ID, the host name is the CodeCommit endpoint1. Due to this combination, it may be longer than the 108 char and cause the error message unix_listener: ... too long for Unix domain socket:

1
2
$ echo "/Users/xxxxxxxxxx/.ssh/master-xxx@git-codecommit.xxx:22" | wc -m
115

Solution

To solve the long ControlPath issue, we can replace the parameter with %C which is Hash of %l%h%p%r2 and decrease the chance for ControlPath to be longer than 108 char:

1
2
3
host *
ControlMaster auto
ControlPath ~/.ssh/master-%C

We can see the length of the socket path is much less then the length limit and we can avoid the socket length issue with ControlPath:

1
2
3
4
$ ls ~/.ssh | grep master
master-e7f58eb55da9db1a90b39dba271ef9c92838e09a
$ echo "/home/shihtiy/.ssh/master-e7f58eb55da9db1a90b39dba271ef9c92838e09a" | wc -m
67

References

With CodeCommit, the remote login user name is the SSH key ID, the host name is the CodeCommit endpoint. Due to this combination, it may be longer than the 108 char and cause the error messages unix_listener: ... too long for Unix domain socket:

1
2
$ echo "/Users/xxxxxxxxxx/.ssh/master-xxx@git-codecommit.xxx:22" | wc -m
115

Solution

To solve the long ControlPath issue, we can replace the parameter with %C which is Hash of %l%h%p%r2 and decrease the chance for ControlPath to be longer than 108 characters:

1
2
3
host *
ControlMaster auto
ControlPath ~/.ssh/master-%C

We can see the length of the socket path is much less then the length limit and we can avoid the socket length issue with ControlPath:

1
2
3
4
$ ls ~/.ssh | grep master
master-e7f58eb55da9db1a90b39dba271ef9c92838e09a
$ echo "/home/shihtiy/.ssh/master-e7f58eb55da9db1a90b39dba271ef9c92838e09a" | wc -m
67

References

This post is licensed under CC BY 4.0 by the author.