debug: Restore the s3-style check in check_log_size()
[samba.git] / lib / util / util_net.c
index 228393a2bbf8cf760b87c6ff4bb17584504b8e21..9c8f5c6d47970ba5c702b2c10485c33a821c0a7e 100644 (file)
@@ -3,10 +3,11 @@
    Samba utility functions
    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
    Copyright (C) Andrew Tridgell 1992-1998
-   Copyright (C) Jeremy Allison 2001-2007
+   Copyright (C) Jeremy Allison  1992-2007
    Copyright (C) Simo Sorce 2001
    Copyright (C) Jim McDonough (jmcd@us.ibm.com)  2003.
    Copyright (C) James J Myers 2003
+   Copyright (C) Tim Potter      2000-2001
     
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "system/network.h"
 #include "system/locale.h"
 #include "system/filesys.h"
+#include "lib/util/util_net.h"
 #undef strcasecmp
 
+/*******************************************************************
+ Set an address to INADDR_ANY.
+******************************************************************/
+
+void zero_sockaddr(struct sockaddr_storage *pss)
+{
+       ZERO_STRUCTP(pss);
+       /* Ensure we're at least a valid sockaddr-storage. */
+       pss->ss_family = AF_INET;
+}
+
 /**
  * Wrap getaddrinfo...
  */
@@ -37,13 +50,14 @@ bool interpret_string_addr_internal(struct addrinfo **ppres,
        int ret;
        struct addrinfo hints;
 
-       memset(&hints, '\0', sizeof(hints));
+       ZERO_STRUCT(hints);
+
        /* By default make sure it supports TCP. */
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = flags;
 
-       /* Linux man page on getaddinfo() says port will be
-          uninitialized when service string in NULL */
+       /* Linux man page on getaddrinfo() says port will be
+          uninitialized when service string is NULL */
 
        ret = getaddrinfo(str, NULL,
                        &hints,
@@ -59,6 +73,110 @@ bool interpret_string_addr_internal(struct addrinfo **ppres,
        return true;
 }
 
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Takes a flag which allows it to
+ prefer an IPv4 address (needed for DC's).
+******************************************************************/
+
+static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
+               const char *str,
+               int flags,
+               bool prefer_ipv4)
+{
+       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_sockaddr(pss);
+
+       if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
+               return false;
+       }
+       if (!res) {
+               return false;
+       }
+
+       if (prefer_ipv4) {
+               struct addrinfo *p;
+
+               for (p = res; p; p = p->ai_next) {
+                       if (p->ai_family == AF_INET) {
+                               memcpy(pss, p->ai_addr, p->ai_addrlen);
+                               break;
+                       }
+               }
+               if (p == NULL) {
+                       /* Copy the first sockaddr. */
+                       memcpy(pss, res->ai_addr, res->ai_addrlen);
+               }
+       } else {
+               /* 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;
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Address agnostic version.
+******************************************************************/
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+               const char *str,
+               int flags)
+{
+       return interpret_string_addr_pref(pss,
+                                       str,
+                                       flags,
+                                       false);
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Version that prefers IPv4.
+******************************************************************/
+
+bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
+               const char *str,
+               int flags)
+{
+       return interpret_string_addr_pref(pss,
+                                       str,
+                                       flags,
+                                       true);
+}
+
 /**
  * Interpret an internet address or name into an IP address in 4 byte form.
  * RETURNS IN NETWORK BYTE ORDER (big endian).
@@ -266,16 +384,16 @@ bool is_loopback_addr(const struct sockaddr *pss)
 /**
  * Check if a struct sockaddr has an unspecified address.
  */
-bool is_zero_addr(const struct sockaddr *pss)
+bool is_zero_addr(const struct sockaddr_storage *pss)
 {
 #if defined(HAVE_IPV6)
-       if (pss->sa_family == AF_INET6) {
+       if (pss->ss_family == AF_INET6) {
                const struct in6_addr *pin6 =
                        &((const struct sockaddr_in6 *)pss)->sin6_addr;
                return IN6_IS_ADDR_UNSPECIFIED(pin6);
        }
 #endif
-       if (pss->sa_family == AF_INET) {
+       if (pss->ss_family == AF_INET) {
                const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
                return is_zero_ip_v4(*pin);
        }
@@ -360,7 +478,7 @@ bool same_net(const struct sockaddr *ip1,
  * Are two sockaddr 's the same family and address ? Ignore port etc.
  */
 
-bool addr_equal(const struct sockaddr *ip1,
+bool sockaddr_equal(const struct sockaddr *ip1,
                const struct sockaddr *ip2)
 {
        if (ip1->sa_family != ip2->sa_family) {