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%r
2 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%r
2 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