This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
lynxis lazus gerrit-no-reply at lists.osmocom.orglynxis lazus has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/19140 ) Change subject: osmo_sock_init2: improve support for AF_UNSPEC ...................................................................... osmo_sock_init2: improve support for AF_UNSPEC osmo_sock_init2 abstract two calls of getaddrinfo into one. While there aren't problems with AF_INET or AF_INET6. When using AF_UNSPEC there are corner cases when this fails. E.g. calling local_host with "" and remote_host with an IPv6 only address results in setting up a local socket with AF_INET while trying to connect from there towards AF_INET6 will most likely fail. To prevent such cases with AF_UNSPEC, search prio calling any syscalls if local and remote site supports AF_INET or AF_INET6. In case both supported, prefer AF_INET6 Change-Id: I397c633931fd00d4f083955a3c49a40fb002d766 --- M src/socket.c M tests/socket/socket_test.c M tests/socket/socket_test.ok 3 files changed, 99 insertions(+), 14 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/40/19140/1 diff --git a/src/socket.c b/src/socket.c index 503ceaf..359e24d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -260,22 +260,81 @@ const char *local_host, uint16_t local_port, const char *remote_host, uint16_t remote_port, unsigned int flags) { - struct addrinfo *result, *rp; + struct addrinfo *local = NULL, *remote = NULL, *rp; int sfd = -1, rc, on = 1; + bool local_ipv4 = false, local_ipv6 = false; + bool remote_ipv4 = false, remote_ipv6 = false; + if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == 0) { LOGP(DLGLOBAL, LOGL_ERROR, "invalid: you have to specify either " "BIND or CONNECT flags\n"); return -EINVAL; } + /* figure out local address infos */ + if (flags & OSMO_SOCK_F_BIND) { + local = addrinfo_helper(family, type, proto, local_host, local_port, true); + if (!local) + return -EINVAL; + } + + /* figure out remote address infos */ + if (flags & OSMO_SOCK_F_CONNECT) { + remote = addrinfo_helper(family, type, proto, remote_host, remote_port, false); + if (!remote) { + if (local) + freeaddrinfo(local); + + return -EINVAL; + } + } + + /* It must do a full run to ensure AF_UNSPEC does not fail. + * In case first local valid entry is IPv4 and only remote valid entry + * is IPv6 or vice versa */ + if (family == AF_UNSPEC) { + for (rp = local; rp != NULL; rp = rp->ai_next) { + switch (rp->ai_family) { + case AF_INET: + local_ipv4 = true; + break; + case AF_INET6: + local_ipv6 = true; + break; + } + } + + for (rp = remote; rp != NULL; rp = rp->ai_next) { + switch (rp->ai_family) { + case AF_INET: + remote_ipv4 = true; + break; + case AF_INET6: + remote_ipv6 = true; + break; + } + } + + /* priotize ipv6 as per RFC */ + if (local_ipv6 && remote_ipv6) + family = AF_INET6; + else if (local_ipv4 && remote_ipv4) + family = AF_INET; + else { + LOGP(DLGLOBAL, LOGL_ERROR, "Unable to find a common protocol (IPv4 or IPv6) for local host: %s and remote host: %s.\n", + local_host, remote_host); + return -ENODEV; + } + } + /* figure out local side of socket */ if (flags & OSMO_SOCK_F_BIND) { - result = addrinfo_helper(family, type, proto, local_host, local_port, true); - if (!result) - return -EINVAL; + for (rp = local; rp != NULL; rp = rp->ai_next) { + /* When called with AF_UNSPEC, family will set to IPv4 or IPv6 */ + if (rp->ai_family != family) + continue; - for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket_helper(rp, flags); if (sfd < 0) continue; @@ -302,8 +361,11 @@ } break; } - freeaddrinfo(result); + + freeaddrinfo(local); if (rp == NULL) { + if (remote) + freeaddrinfo(remote); LOGP(DLGLOBAL, LOGL_ERROR, "no suitable local addr found for: %s:%u\n", local_host, local_port); return -ENODEV; @@ -316,14 +378,11 @@ /* figure out remote side of socket */ if (flags & OSMO_SOCK_F_CONNECT) { - result = addrinfo_helper(family, type, proto, remote_host, remote_port, false); - if (!result) { - if (sfd >= 0) - close(sfd); - return -EINVAL; - } + for (rp = remote; rp != NULL; rp = rp->ai_next) { + /* When called with AF_UNSPEC, family will set to IPv4 or IPv6 */ + if (rp->ai_family != family) + continue; - for (rp = result; rp != NULL; rp = rp->ai_next) { if (sfd < 0) { sfd = socket_helper(rp, flags); if (sfd < 0) @@ -343,7 +402,8 @@ } break; } - freeaddrinfo(result); + + freeaddrinfo(remote); if (rp == NULL) { LOGP(DLGLOBAL, LOGL_ERROR, "no suitable remote addr found for: %s:%u\n", remote_host, remote_port); diff --git a/tests/socket/socket_test.c b/tests/socket/socket_test.c index 37e0281..e68243c 100644 --- a/tests/socket/socket_test.c +++ b/tests/socket/socket_test.c @@ -120,6 +120,27 @@ * FreeBSD 10 or 11 VM at home */ OSMO_ASSERT(!strncmp(name, "(r=127.0.0.1:53<->l=127.0.0.1", 29)); #endif + + printf("Checking osmo_sock_init2(AF_UNSPEC) must fail on mixed IPv4 & IPv6\n"); + fd = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "127.0.0.1", 0, "::1", 53, + OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT); + OSMO_ASSERT(fd < 0); + + printf("Checking osmo_sock_init2(AF_UNSPEC) must fail on mixed IPv6 & IPv4\n"); + fd = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "::1", 0, "127.0.0.1", 53, + OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT); + OSMO_ASSERT(fd < 0); + + printf("Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv4\n"); + fd = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "127.0.0.1", 0, "127.0.0.1", 53, + OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT); + OSMO_ASSERT(fd >= 0); + + printf("Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv6\n"); + fd = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "::1", 0, "::1", 53, + OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT); + OSMO_ASSERT(fd >= 0); + talloc_free(name); return 0; diff --git a/tests/socket/socket_test.ok b/tests/socket/socket_test.ok index 4b24fbc..4265be8 100644 --- a/tests/socket/socket_test.ok +++ b/tests/socket/socket_test.ok @@ -5,3 +5,7 @@ Checking osmo_sock_init2() for OSMO_SOCK_F_NONBLOCK Checking osmo_sock_init2() for invalid flags Checking osmo_sock_init2() for combined BIND + CONNECT +Checking osmo_sock_init2(AF_UNSPEC) must fail on mixed IPv4 & IPv6 +Checking osmo_sock_init2(AF_UNSPEC) must fail on mixed IPv6 & IPv4 +Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv4 +Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv6 -- To view, visit https://gerrit.osmocom.org/c/libosmocore/+/19140 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Change-Id: I397c633931fd00d4f083955a3c49a40fb002d766 Gerrit-Change-Number: 19140 Gerrit-PatchSet: 1 Gerrit-Owner: lynxis lazus <lynxis at fe80.eu> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200705/5699f79c/attachment.htm>