+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage.
+******************************************************************/
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ struct addrinfo *res = NULL;
+#if defined(HAVE_IPV6)
+ char addr[INET6_ADDRSTRLEN];
+ unsigned int scope_id = 0;
+
+ if (strchr_m(str, ':')) {
+ char *p = strchr_m(str, '%');
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
+ strlcpy(addr, str,
+ MIN(PTR_DIFF(p,str)+1,
+ sizeof(addr)));
+ str = addr;
+ }
+ }
+#endif
+
+ zero_addr(pss);
+
+ if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
+ return false;
+ }
+ if (!res) {
+ return false;
+ }
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6 && scope_id) {
+ struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss;
+ if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
+ ps6->sin6_scope_id == 0) {
+ ps6->sin6_scope_id = scope_id;
+ }
+ }
+#endif
+
+ freeaddrinfo(res);
+ return true;
+}
+
+/*******************************************************************
+ Set an address to INADDR_ANY.
+******************************************************************/
+
+void zero_addr(struct sockaddr_storage *pss)
+{
+ memset(pss, '\0', sizeof(*pss));
+ /* Ensure we're at least a valid sockaddr-storage. */
+ pss->ss_family = AF_INET;
+}
+
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+ uint16_t port = 0;
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ /* IPv6 */
+ const struct sockaddr_in6 *sa6 =
+ (const struct sockaddr_in6 *)pss;
+ port = ntohs(sa6->sin6_port);
+#endif
+ } else {
+ const struct sockaddr_in *sa =
+ (const struct sockaddr_in *)pss;
+ port = ntohs(sa->sin_port);
+ }
+ return port;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+static char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr *psa,
+ socklen_t psalen)
+{
+ if (destlen > 0) {
+ dest[0] = '\0';
+ }
+ (void)sys_getnameinfo(psa,
+ psalen,
+ dest, destlen,
+ NULL, 0,
+ NI_NUMERICHOST);
+ return dest;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa)
+{
+ return print_sockaddr_len(dest, destlen, (struct sockaddr *)psa,
+ sizeof(struct sockaddr_storage));
+}
+
+/****************************************************************************
+ Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ char *dest = NULL;
+ int ret;
+
+ /* Linux getnameinfo() man pages says port is unitialized if
+ service name is NULL. */
+
+ ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(struct sockaddr_storage),
+ addr, sizeof(addr),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ dest = talloc_asprintf(ctx, "[%s]", addr);
+#else
+ return NULL;
+#endif
+ } else {
+ dest = talloc_asprintf(ctx, "%s", addr);
+ }
+
+ return dest;
+}
+
+/****************************************************************************
+ Return the string of an IP address (IPv4 or IPv6).
+****************************************************************************/
+
+static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
+{
+ struct sockaddr_storage sa;
+ socklen_t length = sizeof(sa);
+
+ /* Ok, returning a hard coded IPv4 address
+ * is bogus, but it's just as bogus as a
+ * zero IPv6 address. No good choice here.
+ */
+
+ strlcpy(addr_buf, "0.0.0.0", addr_len);
+
+ if (fd == -1) {
+ return addr_buf;
+ }