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

📄 sresolv.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE sresolv.c * @brief Sofia Asynchronous DNS Resolver implementation. *  * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Teemu Jalava <Teemu.Jalava@nokia.com> * @author Mikko Haataja <ext-Mikko.A.Haataja@nokia.com> * * @todo The resolver should allow handling arbitrary records. */#include "config.h"#include <stdlib.h>#include <stdarg.h>#include <stddef.h>#include <string.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <time.h>#include <limits.h>#include <assert.h>#if 0 && !HAVE_SOFIA_SU#include <sys/socket.h>#include <sys/time.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#endif#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_strlst.h>#include <sofia-sip/su.h>#if HAVE_SU_WAIT_H#define SU_TIMER_ARG_T  struct sres_sofia_s#define SU_WAKEUP_ARG_T struct sres_sofia_s#include <sofia-sip/su_wait.h>#include <sofia-sip/su_types.h>#include <sofia-sip/su_time.h>#define SU_LOG sresolv_log#include <sofia-sip/su_debug.h>/**@var SRESOLV_DEBUG * * Environment variable determining the debug log level for @b sresolv * module. * * The SRESOLV_DEBUG environment variable is used to determine the debug * logging level for @b sresolv module. The default level is 3. *  * @sa <su_debug.h>, sresolv_log, SOFIA_DEBUG */extern char const SRESOLV_DEBUG[];/**Debug log for @b sresolv module.  *  * The sresolv_log is the log object used by @b sresolv module. The level of * #sresolv_log is set using #SRESOLV_DEBUG environment variable. */su_log_t sresolv_log[] = { SU_LOG_INIT("sresolv", "SRESOLV_DEBUG", 3) };#else#define su_close(s) close(s)#define su_strerror(s) strerror(s)#define su_errno() errno#define su_seterrno(x) ((errno = (x)), -1)#define SU_DEBUG_0(x) printf x#define SU_DEBUG_1(x) printf x#define SU_DEBUG_3(x) printf x#define SU_DEBUG_5(x) printf x#define SU_DEBUG_7(x) printf x#define SU_DEBUG_9(x) printf x#endif#define sres_resolver_create public_sres_resolver_create#include "sofia-sip/sresolv.h"#undef sres_resolver_create#include "sofia-sip/htable.h"/** Cache cleanup interval in seconds. */#define SRES_CACHE_TIMER_INTERVAL (30)/** Sofia timer interval in milliseconds. */#define SRES_RETRANSMIT_INTERVAL  (500)/** Maximum number of retries sent. */#define SRES_MAX_RETRY_COUNT (6)/** Maximum number of search domains. */#define SRES_MAX_SEARCH (6)/** Maximum length of domain name. */#define SRES_MAXDNAME (1025)/** Internal errors */enum {  SRES_EDNS0_ERR = 255		/**< Server did not support EDNS. */};typedef struct sres_rr_hash_entry_s sres_rr_hash_entry_t;typedef struct sres_message_s       sres_message_t;#define SRES_HENTRY_HASH(e) ((e)->rr_hash_key)HTABLE_DECLARE(sres_htable, ht, sres_rr_hash_entry_t);HTABLE_DECLARE(sres_qtable, qt, sres_query_t);typedef struct sres_server_s {      char const             *dns_name;     /**< Server name */  struct sockaddr_storage dns_addr[1];  /**< Server node address */  ssize_t                 dns_addrlen;  /**< Size of addres */  unsigned                dns_edns;	/**< Server supports edns */  /** ICMP error received, zero when successful. */  time_t                  dns_icmp_error; } sres_server_t;struct sres_resolver_s {  su_home_t           res_home[1];  unsigned            res_refcount;  void               *res_userdata;  int               (*res_lock)(void *mutex);  int               (*res_unlock)(void *mutex);  void               *res_mutex;  time_t              res_now;  uint16_t            res_id;  sres_qtable_t       res_queries[1];   /**< Table of active queries */  time_t              res_cache_cleaned;  sres_htable_t       res_cache[1];  char const         *res_config;    /**< Configuration file name */  uint16_t            res_port;	     /**< Server port to use */  short               res_n_servers; /**< Number of servers */  short               res_i_server;  /**< Current server to try 					(when doing round-robin) */  sres_server_t      *res_servers;  char const         *res_search[1 + SRES_MAX_SEARCH];};struct sres_rr_hash_entry_s {  unsigned int   rr_hash_key;  time_t         rr_received;  sres_record_t *rr;};struct sres_query_s {  hash_value_t    q_hash;  sres_resolver_t*q_res;  sres_answer_f  *q_callback;  sres_context_t *q_context;  char           *q_name;  time_t          q_timestamp;  int             q_socket;  uint16_t        q_type;  uint16_t        q_class;  uint16_t        q_id;			/**< If nonzero, not answered */  uint16_t        q_retry_count;  short           q_i_server;  uint8_t         q_edns;  uint8_t         q_n_subs;  sres_query_t   *q_subqueries[1 + SRES_MAX_SEARCH];  sres_record_t **q_subanswers[1 + SRES_MAX_SEARCH];};struct sres_message_s {  uint16_t m_offset;  uint16_t m_size;  char const *m_error;  union {    struct {      /* Header defined in RFC 1035 section 4.1.1 (page 26) */      uint16_t mh_id;		/* Query ID */      uint16_t mh_flags;	/* Flags */      uint16_t mh_qdcount;	/* Question record count */      uint16_t mh_ancount;	/* Answer record count */      uint16_t mh_nscount;	/* Authority records count */      uint16_t mh_arcount;	/* Additional records count */    } mp_header;    uint8_t mp_data[1500 - 40];	/**< IPv6 datagram */  } m_packet;#define m_id      m_packet.mp_header.mh_id#define m_flags   m_packet.mp_header.mh_flags#define m_qdcount m_packet.mp_header.mh_qdcount#define m_ancount m_packet.mp_header.mh_ancount#define m_nscount m_packet.mp_header.mh_nscount#define m_arcount m_packet.mp_header.mh_arcount #define m_data    m_packet.mp_data};#define sr_refcount sr_record->r_refcount#define sr_name     sr_record->r_name#define sr_status   sr_record->r_status#define sr_size     sr_record->r_size#define sr_type     sr_record->r_type#define sr_class    sr_record->r_class#define sr_ttl      sr_record->r_ttl#define sr_rdlen    sr_record->r_rdlen#define sr_rdata    sr_generic->g_dataenum {  SRES_HDR_QR = (1 << 15),  SRES_HDR_QUERY = (0 << 11),  SRES_HDR_IQUERY = (1 << 11),  SRES_HDR_STATUS = (2 << 11),  SRES_HDR_OPCODE = (15 << 11),	/* mask */  SRES_HDR_AA = (1 << 10),  SRES_HDR_TC = (1 << 9),  SRES_HDR_RD = (1 << 8),  SRES_HDR_RA = (1 << 7),  SRES_HDR_RCODE = (15 << 0)	/* mask of return code */};HTABLE_PROTOS(sres_htable, ht, sres_rr_hash_entry_t);HTABLE_PROTOS(sres_qtable, qt, sres_query_t);/** Get address from sockaddr storage. */#if SU_HAVE_IN6#define SS_ADDR(ss) \  ((ss)->ss_family == AF_INET ? \   (void *)&((struct sockaddr_in *)ss)->sin_addr : \  ((ss)->ss_family == AF_INET6 ? \   (void *)&((struct sockaddr_in6 *)ss)->sin6_addr : \   (void *)&((struct sockaddr *)ss)->sa_data))#else#define SS_ADDR(ss) \  ((ss)->ss_family == AF_INET ? \   (void *)&((struct sockaddr_in *)ss)->sin_addr : \   (void *)&((struct sockaddr *)ss)->sa_data)#endif/** Generate new 16-bit identifier for DNS query. */uint16_tsres_new_id(sres_resolver_t *res){  return res->res_id ? res->res_id++ : (res->res_id += 2);}/** Return true if we have a search list or a local domain name. */static int sres_has_search_domain(sres_resolver_t *res) {  return res->res_search[0] || res->res_search[1];}static sres_query_t * sres_query_alloc(sres_resolver_t *res,				       sres_answer_f *callback,				       sres_context_t *context,				       int socket,				       uint16_t type,				       char const * domain);static void sres_free_query(sres_resolver_t *res, sres_query_t *q);static void sres_store(sres_resolver_t *res, sres_record_t *rr);static unsigned int sres_hash_key(const char *string);static int sres_record_compare(sres_record_t const *a, sres_record_t const *b);static int sres_sockaddr2string(char name[], size_t namelen, struct sockaddr const *);static int sres_parse_resolv_conf(sres_resolver_t *, const char *filename);staticint sres_send_dns_query(sres_resolver_t *res, sres_query_t *q);static void sres_answer_subquery(sres_context_t *context, 			  sres_query_t *query,			  sres_record_t **answers);staticvoid sres_query_report_error(sres_resolver_t *res, sres_query_t *q,			     sres_record_t **answers);voidsres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout);static sres_server_t *sres_server_by_sockaddr(sres_resolver_t const *res, 			void const *from, int fromlen);staticint sres_resolver_report_error(sres_resolver_t *res, 			       int socket,			       int errcode,			       struct sockaddr_storage *remote,			       socklen_t remotelen, 			       char const *info);static inline void _sres_free_answer(sres_resolver_t *, sres_record_t *);static inline void _sres_free_answers(sres_resolver_t *, sres_record_t **);staticvoid sres_log_response(sres_resolver_t const *res, 		       sres_message_t const *m,		       struct sockaddr_storage const *from,		       sres_query_t const *query,		       sres_record_t * const *reply);static int sres_decode_msg(sres_resolver_t *res, 			   sres_message_t *m,			   sres_query_t **,			   sres_record_t ***aanswers);static char const *sres_toplevel(char buf[SRES_MAXDNAME], char const *domain);static sres_record_t *sres_create_record(sres_resolver_t *, sres_message_t *m);static void sres_init_rr_soa(sres_resolver_t *res, sres_soa_record_t *rr,			     sres_message_t *m);static void sres_init_rr_a(sres_resolver_t *res, sres_a_record_t *rr,			   sres_message_t *m);#if SU_HAVE_IN6static void sres_init_rr_a6(sres_resolver_t *res, sres_a6_record_t *rr,			    sres_message_t *m);static void sres_init_rr_aaaa(sres_resolver_t *res, sres_aaaa_record_t *rr,			      sres_message_t *m);#endifstatic void sres_init_rr_cname(sres_resolver_t *res, sres_cname_record_t *rr,			       sres_message_t *m);static void sres_init_rr_ptr(sres_resolver_t *res, sres_ptr_record_t *rr,			     sres_message_t *m);static void sres_init_rr_srv(sres_resolver_t *res, sres_srv_record_t *rr,			     sres_message_t *m);static void sres_init_rr_naptr(sres_resolver_t *res, sres_naptr_record_t *rr,			       sres_message_t *m);static sres_record_t *sres_create_error_rr(sres_resolver_t *res,                                           sres_query_t const *q,                                           uint16_t errcode);static int sres_get_domain(sres_resolver_t *res, char **buf,                            sres_message_t *m);static int sres_get_string(sres_resolver_t *res, char **buf,                            sres_message_t *m);static void m_put_uint16(sres_message_t *m, uint16_t h);static void m_put_uint32(sres_message_t *m, uint32_t w);static uint16_t m_put_domain(sres_message_t *m,                              char const *domain,                              uint16_t top,                              char const *topdomain);static uint32_t m_get_uint32(sres_message_t *m);static uint16_t m_get_uint16(sres_message_t *m);static uint8_t m_get_uint8(sres_message_t *m);static int m_get_string(char *d, int n, sres_message_t *m);static int m_get_domain(char *d, int n, sres_message_t *m, int indirected);/**Create a resolver. * * The function sres_resolver_new() is used to allocate and initialize a new * sres resolver object. The resolver object contains the parsed resolv.conf * file, cached answers from DNS, and a list of active queries. The default * resolv.conf file can be overriden by giving the name of the configuration * file as @a conf_file_path. * * @param conf_file_path name of the resolv.conf configuration file  * * @return The function sres_resolver_new() returns a pointer to a newly * created sres resolver object, or NULL upon an error. *  */sres_resolver_t *sres_resolver_new(char const *conf_file_path){  sres_resolver_t *res;  res = su_home_new(sizeof(*res));  if (res == NULL)    return NULL;  while (res->res_id == 0) {#if HAVE_SU_WAIT_H    su_ntp_t ntp;    ntp = su_ntp_now();    res->res_id = su_ntp_lo(ntp) + su_ntp_hi(ntp) + su_random();#else    res->res_id = time(NULL);#endif  }  res->res_port = 53;		/* Domain */  if (sres_htable_resize(res->res_home, res->res_cache, 0) < 0) {    perror("sres: res_htable_resize");  }   else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {    perror("sres: res_qtable_resize");  }   else if (sres_parse_resolv_conf(res, conf_file_path)) {    res->res_refcount = 1;    return res;  }  sres_resolver_unref(res);  return NULL;}/** Add a lock to resolver object.  * * The function sres_resolver_add_mutex() is used to pass a mutex along with * the functions used obtaining and releasing the mutex to the resolver. The * mutex is needed when resolver is used in multithreaded environment. The * @a lock function is used to obtain the lock. The @a unlock function is * used to release the lock. Both are called with @a mutex as their only * argument. Both @a lock() and @a unlock() should return 0 when successful, * -1 upon an error. * * @note * Please note that the resolver gives away its mutex lock while it * calls the query-specific callback functions. * * @param res pointer to resolver object * @param mutex pointer to a mutex object (may be NULL) * @param lock function used to obtain a lock on @a mutex * @param unlock function used to release a lock on @a mutex *  * @retval 0 when successful * @retval -1 upon an error *  * @ERRORS * @ERROR EFAULT @a res, @a lock or @a unlock point outside the address space */int sres_resolver_add_mutex(sres_resolver_t *res,			    void *mutex,			    int (*lock)(void *mutex),			    int (*unlock)(void *mutex)){  if (res && lock && unlock) {    res->res_mutex = mutex;    res->res_lock = lock;    res->res_unlock = unlock;    return 0;  }  else {    return su_seterrno(EFAULT);  }}/** Obtain lock */#define LOCK(res) \  ((res ? 1 : (errno = EFAULT, 0)) && \   ((res)->res_lock ? (res)->res_lock((res)->res_mutex) : 0) == 0)#define UNLOCK(res) \  (((res)->res_unlock ? (res)->res_unlock((res)->res_mutex) : 0) == 0)/** Create a new reference to resolver. */sres_resolver_t *sres_resolver_ref(sres_resolver_t *res){  if (LOCK(res)) {    if (res->res_refcount != UINT_MAX)      res->res_refcount++;    UNLOCK(res);    return res;  }

⌨️ 快捷键说明

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