text: // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "net/dns/dns_util.h"
  
  #include <errno.h>
  #include <limits.h>
  
  #include <cstring>
  
  #include "build/build_config.h"
  
  #if defined(OS_POSIX)
  #include <netinet/in.h>
  #if !defined(OS_NACL)
  #include <net/if.h>
  #if !defined(OS_ANDROID)
  #include <ifaddrs.h>
  #endif  // !defined(OS_ANDROID)
  #endif  // !defined(OS_NACL)
  #endif  // defined(OS_POSIX)
  
  #if defined(OS_ANDROID)
  #include "net/android/network_library.h"
  #endif
  
  namespace net {
  
  // Based on DJB's public domain code.
  bool DNSDomainFromDot(const base::StringPiece& dotted, std::string* out) {
    const char* buf = dotted.data();
    unsigned n = dotted.size();
    char label[63];
    size_t labellen = 0; /* <= sizeof label */
    char name[255];
    size_t namelen = 0; /* <= sizeof name */
    char ch;
  
    for (;;) {
      if (!n)
        break;
      ch = *buf++;
      --n;
      if (ch == '.') {
        // Don't allow empty labels per http://crbug.com/456391.
        if (!labellen)
          return false;
        if (namelen + labellen + 1 > sizeof name)
          return false;
        name[namelen++] = static_cast<char>(labellen);
        memcpy(name + namelen, label, labellen);
        namelen += labellen;
        labellen = 0;
        continue;
      }
      if (labellen >= sizeof label)
        return false;
      label[labellen++] = ch;
    }
  
    // Allow empty label at end of name to disable suffix search.
    if (labellen) {
      if (namelen + labellen + 1 > sizeof name)
        return false;
      name[namelen++] = static_cast<char>(labellen);
      memcpy(name + namelen, label, labellen);
      namelen += labellen;
      labellen = 0;
    }
  
    if (namelen + 1 > sizeof name)
      return false;
    if (namelen == 0) // Empty names e.g. "", "." are not valid.
      return false;
    name[namelen++] = 0;  // This is the root label (of length 0).
  
    *out = std::string(name, namelen);
    return true;
  }
  
  std::string DNSDomainToString(const base::StringPiece& domain) {
    std::string ret;
  
    for (unsigned i = 0; i < domain.size() && domain[i]; i += domain[i] + 1) {
  #if CHAR_MIN < 0
      if (domain[i] < 0)
        return std::string();
  #endif
      if (domain[i] > 63)
        return std::string();
  
      if (i)
        ret += ".";
  
      if (static_cast<unsigned>(domain[i]) + i + 1 > domain.size())
        return std::string();
  
      domain.substr(i + 1, domain[i]).AppendToString(&ret);
    }
    return ret;
  }
  
  bool HaveOnlyLoopbackAddresses() {
  #if defined(OS_ANDROID)
    return android::HaveOnlyLoopbackAddresses();
  #elif defined(OS_NACL)
    NOTIMPLEMENTED();
    return false;
  #elif defined(OS_POSIX)
    struct ifaddrs* interface_addr = NULL;
    int rv = getifaddrs(&interface_addr);
    if (rv != 0) {
      DVLOG(1) << "getifaddrs() failed with errno = " << errno;
      return false;
    }
  
    bool result = true;
    for (struct ifaddrs* interface = interface_addr;
         interface != NULL;
         interface = interface->ifa_next) {
      if (!(IFF_UP & interface->ifa_flags))
        continue;
      if (IFF_LOOPBACK & interface->ifa_flags)
        continue;
      const struct sockaddr* addr = interface->ifa_addr;
      if (!addr)
        continue;
      if (addr->sa_family == AF_INET6) {
        // Safe cast since this is AF_INET6.
        const struct sockaddr_in6* addr_in6 =
            reinterpret_cast<const struct sockaddr_in6*>(addr);
        const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
        if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr))
          continue;
      }
      if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET)
        continue;
  
      result = false;
      break;
    }
    freeifaddrs(interface_addr);
    return result;
  #elif defined(OS_WIN)
    // TODO(wtc): implement with the GetAdaptersAddresses function.
    NOTIMPLEMENTED();
    return false;
  #else
    NOTIMPLEMENTED();
    return false;
  #endif  // defined(various platforms)
  }
  
  }  // namespace net
  