⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
     This file is part of GNUnet.
     (C) 2007, 2008 Christian Grothoff (and other contributing authors)

     GNUnet is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published
     by the Free Software Foundation; either version 2, or (at your
     option) any later version.

     GNUnet is distributed in the hope that it will be useful, but
     WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with GNUnet; see the file COPYING.  If not, write to the
     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     Boston, MA 02111-1307, USA.
*/

/**
 * @file util/network/dns.c
 * @brief code to do DNS resolution
 * @author Christian Grothoff
 */

#include <stdlib.h>
#include "platform.h"
#include "gnunet_util_network.h"

#if HAVE_ADNS
#include <adns.h>
#endif


struct IPCache
{
  struct IPCache *next;
  char *addr;
  struct sockaddr *sa;
  GNUNET_CronTime last_refresh;
  GNUNET_CronTime last_request;
  unsigned int salen;
#if HAVE_ADNS
  int posted;
  adns_query query;
#endif
};

static struct IPCache *head;

static struct GNUNET_Mutex *lock;

#if HAVE_ADNS
static int a_init;

static adns_state a_state;
#endif

#if HAVE_ADNS
static void
adns_resolve (struct IPCache *cache)
{
  adns_answer *answer;
  adns_status ret;
  struct IPCache *rec;
  int reti;

  if (a_init == 0)
    {
      a_init = 1;
      adns_init (&a_state, adns_if_noerrprint, NULL);
    }
  if (cache->posted == GNUNET_NO)
    {
      ret = adns_submit_reverse (a_state, cache->sa, adns_r_ptr,
#ifdef adns_qf_none
                                 adns_qf_none,
#else
                                 0,
#endif
                                 cache, &cache->query);
      if (adns_s_ok == ret)
        cache->posted = GNUNET_YES;
    }
  adns_processany (a_state);
  answer = NULL;
  reti = adns_check (a_state, &cache->query, &answer, (void **) &rec);
  if (reti == 0)
    {
      if (answer != NULL)
        {
          if ((answer->rrs.str != NULL) && (*(answer->rrs.str) != NULL))
            cache->addr = GNUNET_strdup (*(answer->rrs.str));
          free (answer);
        }
      cache->posted = GNUNET_NO;
    }
}
#endif

#if HAVE_GETNAMEINFO
static void
getnameinfo_resolve (struct IPCache *cache)
{
  char hostname[256];

  if (0 == getnameinfo (cache->sa, cache->salen, hostname, 255, NULL, 0, 0))
    cache->addr = GNUNET_strdup (hostname);
}
#endif

#if HAVE_GETHOSTBYADDR
static void
gethostbyaddr_resolve (struct IPCache *cache)
{
  struct hostent *ent;

  switch (cache->sa->sa_family)
    {
    case AF_INET:
      ent = gethostbyaddr (&((struct sockaddr_in *) cache->sa)->sin_addr,
                           sizeof (struct in_addr), AF_INET);
      break;
    case AF_INET6:
      ent = gethostbyaddr (&((struct sockaddr_in6 *) cache->sa)->sin6_addr,
                           sizeof (struct in6_addr), AF_INET6);
      break;
    default:
      ent = NULL;
    }
  if (ent != NULL)
    cache->addr = GNUNET_strdup (ent->h_name);
}
#endif

static void
cache_resolve (struct IPCache *cache)
{
#if HAVE_ADNS
  if (cache->sa->sa_family == AF_INET)
    {
      adns_resolve (cache);
      return;
    }
#endif
#if HAVE_GETNAMEINFO
  if (cache->addr == NULL)
    getnameinfo_resolve (cache);
#endif
#if HAVE_GETHOSTBYADDR
  if (cache->addr == NULL)
    gethostbyaddr_resolve (cache);
#endif
}

static struct IPCache *
resolve (const struct sockaddr *sa, unsigned int salen)
{
  struct IPCache *ret;

  ret = GNUNET_malloc (sizeof (struct IPCache));
#if HAVE_ADNS
  ret->posted = GNUNET_NO;
#endif
  ret->next = head;
  ret->salen = salen;
  ret->sa = salen == 0 ? NULL : GNUNET_malloc (salen);
  memcpy (ret->sa, sa, salen);
  ret->last_request = GNUNET_get_time ();
  ret->last_refresh = GNUNET_get_time ();
  ret->addr = NULL;
  cache_resolve (ret);
  head = ret;
  return ret;
}

static char *
no_resolve (const struct sockaddr *sa, unsigned int salen)
{
  char *ret;
  char inet4[INET_ADDRSTRLEN];
  char inet6[INET6_ADDRSTRLEN];

  if (salen < sizeof (struct sockaddr))
    return NULL;
  switch (sa->sa_family)
    {
    case AF_INET:
      if (salen != sizeof (struct sockaddr_in))
        return NULL;
      inet_ntop (AF_INET,
                 &((struct sockaddr_in *) sa)->sin_addr,
                 inet4, INET_ADDRSTRLEN);
      ret = GNUNET_strdup (inet4);
      break;
#ifdef AF_INET6
    case AF_INET6:
      if (salen != sizeof (struct sockaddr_in6))
        return NULL;
      inet_ntop (AF_INET6,
                 &((struct sockaddr_in6 *) sa)->sin6_addr,
                 inet6, INET6_ADDRSTRLEN);
      ret = GNUNET_strdup (inet6);
      break;
#endif
    default:
      ret = NULL;
      break;
    }
  return ret;
}

/**
 * Get an IP address as a string (works for both IPv4 and IPv6).  Note
 * that the resolution happens asynchronously and that the first call
 * may not immediately result in the FQN (but instead in a
 * human-readable IP address).
 *
 * @param sa should be of type "struct sockaddr*"
 */
char *
GNUNET_get_ip_as_string (const void *sav, unsigned int salen, int do_resolve)
{
  const struct sockaddr *sa = sav;
  char *ret;
  struct IPCache *cache;
  struct IPCache *prev;
  GNUNET_CronTime now;

  if (salen < sizeof (struct sockaddr))
    return NULL;
  now = GNUNET_get_time ();
  GNUNET_mutex_lock (lock);
  cache = head;
  prev = NULL;
  while ((cache != NULL) &&
         ((cache->salen != salen) || (0 != memcmp (cache->sa, sa, salen))))
    {
      if (cache->last_request + 60 * GNUNET_CRON_MINUTES < now)
        {
#if HAVE_ADNS
          if (cache->posted == GNUNET_YES)
            {
              adns_cancel (cache->query);
              cache->posted = GNUNET_NO;
            }
#endif
          if (prev != NULL)
            {
              prev->next = cache->next;
              GNUNET_free_non_null (cache->addr);
              GNUNET_free (cache->sa);
              GNUNET_free (cache);
              cache = prev->next;
            }
          else
            {
              head = cache->next;
              GNUNET_free_non_null (cache->addr);
              GNUNET_free (cache->sa);
              GNUNET_free (cache);
              cache = head;
            }
          continue;
        }
      prev = cache;
      cache = cache->next;
    }
  if (cache != NULL)
    {
      cache->last_request = now;
      if (cache->last_refresh + 12 * GNUNET_CRON_HOURS < now)
        {
          GNUNET_free_non_null (cache->addr);
          cache->addr = NULL;
          cache->salen = 0;
          cache_resolve (cache);
        }
#if HAVE_ADNS
      if (cache->posted == GNUNET_YES)
        {
          cache_resolve (cache);
        }
#endif
    }
  else if (do_resolve == GNUNET_NO)
    {
      GNUNET_mutex_unlock (lock);
      return no_resolve (sav, salen);
    }
  else
    cache = resolve (sa, salen);
  ret = (cache->addr == NULL) ? NULL : GNUNET_strdup (cache->addr);
  if (ret == NULL)
    ret = no_resolve (sa, salen);
  GNUNET_mutex_unlock (lock);
  return ret;
}


#if HAVE_GETADDRINFO
int

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -