示例#1
0
 bool ParseIPv4(char *str, uint32_t *out_addr, char **next /*NULL*/)
 {
   return ParseIPv4(const_cast<const char *>(str),
                    out_addr,
                    const_cast<const char **>(next)
                    );
 }
示例#2
0
bool sockAddrBase::FromString(const char *str)
{
  // This is called from the constructor, so it must work with an uninitialized
  // structure.
  init(Addr::Invalid);
  // First determine if it is IPv4 or IPv6
  str = SkipWhite(str);
  const char *firstColon = strchr(str, ':');
  const char *firstDot = strchr(str, '.');
  const char *firstPercent = strchr(str, '%');

  if (!firstDot && !firstColon)
    return false;
  if (!firstColon
      || (firstDot && firstDot < firstColon))
  {
    // IPv4
    uint16_t port;
    uint32_t addr;

    if (firstPercent)
      return false;

    if (!firstColon)
    {
      if (!ParseIPv4(str, &addr, &str))
        return false;
      str = SkipWhite(str);
      if (*str != '\0')
        return false;
      init(Addr::IPv4);
      getIPv4Storage()->sin_addr.s_addr = addr;
      return true;
    }
    // Has dots and a colon, presumably its an IPv4 with port
    if (!m_allowPort)
      return false;

    if (!ParseIPv4Port(str, &addr, &port))
      return false;
    init(Addr::IPv4);
    getIPv4Storage()->sin_addr.s_addr = addr;
    SetPort(port);
    return true;
  }

  // Not IPv4
  if (!firstColon || (firstPercent && (firstPercent < firstColon)))
    return false;
  else
  {
    // IPv6
    sockaddr_in6 tmp = sockaddr_in6();

    if (firstPercent || *str == '[')
    {
      char addrStr[INET6_ADDRSTRLEN];
      const char *last, *lastBrace = NULL;

      if (*str == '[')
      {
        ++str;
        last = lastBrace = strchr(str,  ']');
        if (!lastBrace)
          return false;
      }
      if (firstPercent)
      {
        if (lastBrace && lastBrace < firstPercent + 2)
          return false;
        last = firstPercent;
      }

      if (last == str || size_t(last - str) >= sizeof(addrStr))
        return false;
      memcpy(addrStr, str, last - str);
      addrStr[last - str] = '\0';
      if (1 != inet_pton(AF_INET6, addrStr, &tmp.sin6_addr))
        return false;
      if (firstPercent)
      {
        // ONLY allow interface (scope) for link local addresses (for now)
        // Otherwise address comparison breaks for regular addresses, one of which has a
        // scope.
        if (!IN6_IS_ADDR_LINKLOCAL(&tmp.sin6_addr))
          return false;

        if (lastBrace)
        {
          // already checked that (lastBrace-firstPercent >= 2)
          memcpy(addrStr, firstPercent + 1, lastBrace - (firstPercent + 1));
          addrStr[lastBrace - (firstPercent + 1)] = '\0';
          last = addrStr;
        }
        else
          last = firstPercent + 1;

        unsigned int index = if_nametoindex(last);
        if (index == 0 || index > UINT32_MAX)
          return false;
        tmp.sin6_scope_id = uint32_t(index);
      }

      if (lastBrace)
      {
        last = lastBrace + 1;
        if (*last != ':')
        {
          last = SkipWhite(last);
          if (*last != '\0')
            return false;
        }
        else
        {
          // We have a port
          uint64_t val;

          if (!m_allowPort)
            return false;
          ++last;
          if (!StringToInt(last, val))
            return false;
          if (val > UINT16_MAX)
            return false;
          tmp.sin6_port = htons(uint16_t(val));
        }
      }
    }
    else
    {
      // no [] and no % so the string can be parsed directly
      if (1 != inet_pton(AF_INET6, str, &tmp.sin6_addr))
        return false;
    }

    // Set the actual value
    init(Addr::IPv6);
    sockaddr_in6 *storage = getIPv6Storage();
    storage->sin6_addr = tmp.sin6_addr;
    storage->sin6_port = tmp.sin6_port;
    storage->sin6_scope_id = tmp.sin6_scope_id;
    return true;
  }
}