Pass an address-family-appropriate socket length to connect().

Some UN*Xes (4.4-lite-derived, such as the obscure, little-known macOS,
FreeBSD, NetBSD, OpenBSD, and DragonFly BSD) have a length field in the
socket address structure.

That was originally done for OSI address support; unlike most transport
addresses, such as IPv4 (and IPv6) addresses, where the size of the
address is fixed, the size of an OSI transport layer address is *not*
fixed, so it cannot be inferred from the address type.

With the dropping of OSI support, that field is no longer necessary in
userland.  System calls that take a socket address argument also take an
address length argument; in newer (all?) versions of the {macOS,
FreeBSD, NetBSD, OpenBSD, DragonFly BSD} kernel, the system call code
sets the length field in the kernel's copy of the address to the address
length field value.

However, that means that you have to pass in the appropriate length; if
you have a sockaddr_storage that might contain an IPv4 address or an
IPv6 address, connect() (and bind()) calls should use the IPv4 address
size for IPv4 addresses and the IPv6 address size for IPv6 addresses,
otherwise, at least on macOS, the call fails.

In cap_open_socket(), report socket() and connect() errors separately,
to make it easier to determine where TCP@ captures fail, if they do
fail.  (That's how I got here in the first place.)


(cherry picked from commit e3047d9b38)
This commit is contained in:
Guy Harris 2020-11-15 06:51:58 +00:00
parent cd6afd7c9b
commit f79f407cae
1 changed files with 22 additions and 5 deletions

View File

@ -1316,6 +1316,7 @@ static int
cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, size_t errmsgl)
{
struct sockaddr_storage sa;
socklen_t sa_len;
int fd;
/* Skip the initial "TCP@" in the pipename. */
@ -1327,10 +1328,27 @@ cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, size_t errm
return -1;
}
if ((fd = (int)socket(sa.ss_family, SOCK_STREAM, 0)) < 0 ||
connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
if ((fd = (int)socket(sa.ss_family, SOCK_STREAM, 0)) < 0) {
g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated due to the socket error: \n"
"The capture session could not be initiated because"
" the socket couldn't be created due to the socket error: \n"
#ifdef _WIN32
" %s", win32strerror(WSAGetLastError()));
#else
" %d: %s", errno, g_strerror(errno));
#endif
pcap_src->cap_pipe_err = PIPERR;
return -1;
}
if (sa.ss_family == AF_INET6)
sa_len = sizeof(struct sockaddr_in6);
else
sa_len = sizeof(struct sockaddr_in);
if (connect(fd, (struct sockaddr *)&sa, sa_len) < 0) {
g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated because"
" the socket couldn't be connected due to the socket error: \n"
#ifdef _WIN32
" %s", win32strerror(WSAGetLastError()));
#else
@ -1338,8 +1356,7 @@ cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, size_t errm
#endif
pcap_src->cap_pipe_err = PIPERR;
if (fd >= 0)
cap_pipe_close(fd, TRUE);
cap_pipe_close(fd, TRUE);
return -1;
}