dns_cache.h
dcb59e67
 /*
  * resolver/dns related functions, dns cache and failover
  *
  * Copyright (C) 2006 iptelorg GmbH
  *
02ca141b
  * This file is part of Kamailio, a free SIP server.
dcb59e67
  *
02ca141b
  * Kamailio is free software; you can redistribute it and/or modify
dcb59e67
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
02ca141b
  * Kamailio is distributed in the hope that it will be useful,
dcb59e67
  * 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.
  *
3c8a8654
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
dcb59e67
  */
3ca1a53f
 
dcb59e67
 
3ca1a53f
 /**
  * @file
6806e46a
  * @brief Kamailio core :: resolver/dns related functions, dns cache and failover
02ca141b
  * @author andrei
3ca1a53f
  * @ingroup core
  * Module: @ref core
  */
 
 
dcb59e67
 
 #ifndef __dns_cache_h
 #define __dns_cache_h
 
 #include "str.h"
dd4ffbb7
 #include "config.h" /* MAX_BRANCHES */
dcb59e67
 #include "timer.h"
 #include "ip_addr.h"
 #include "atomic_ops.h"
 #include "resolve.h"
 
 
 #if defined(USE_DNS_FAILOVER) && !defined(USE_DNS_CACHE)
 #error "DNS FAILOVER requires DNS CACHE support (define USE_DNS_CACHE)"
 #endif
 
f682fd71
 #if defined(DNS_WATCHDOG_SUPPORT) && !defined(USE_DNS_CACHE)
 #error "DNS WATCHDOG requires DNS CACHE support (define USE_DNS_CACHE)"
 #endif
 
2cfcc6bb
 #define DEFAULT_DNS_NEG_CACHE_TTL 60 /* 1 min. */
 #define DEFAULT_DNS_CACHE_MIN_TTL 0 /* (disabled) */
 #define DEFAULT_DNS_CACHE_MAX_TTL ((unsigned int)(-1)) /* (maxint) */
 #define DEFAULT_DNS_MAX_MEM 500 /* 500 Kb */
 
3ca1a53f
 /** @brief uncomment the define below for SRV weight based load balancing */
dae0bc71
 #define DNS_SRV_LB
 
dcb59e67
 #define DNS_LU_LST
 
3ca1a53f
 /** @brief dns functions return them as negative values (e.g. return -E_DNS_NO_IP)
  *
dcb59e67
  * listed in the order of importance ( if more errors, only the most important
  * is returned)
  */
 enum dns_errors{
 					E_DNS_OK=0,
3ca1a53f
 					E_DNS_EOR, /**< no more records (not an error)
3c8a8654
 					              -- returned only by the dns_resolve*
dcb59e67
 								  functions when called iteratively,; it
 								  signals the end of the ip/records list */
3ca1a53f
 					E_DNS_UNKNOWN /**< unkown error */,
 					E_DNS_INTERNAL_ERR /**< internal error */,
dcb59e67
 					E_DNS_BAD_SRV_ENTRY,
3ca1a53f
 					E_DNS_NO_SRV /**< unresolvable srv record */,
dcb59e67
 					E_DNS_BAD_IP_ENTRY,
3ca1a53f
 					E_DNS_NO_IP /**< unresolvable a or aaaa records*/,
 					E_DNS_BAD_IP /**< the ip is invalid */,
 					E_DNS_BLACKLIST_IP /**< the ip is blacklisted */,
 					E_DNS_NAME_TOO_LONG /**< try again with a shorter name */,
 					E_DNS_AF_MISMATCH /**< ipv4 or ipv6 only requested, but
dcb59e67
 										 name contains an ip addr. of the
 										 opossite type */ ,
3ca1a53f
 					E_DNS_NO_NAPTR /**< unresolvable naptr record */,
 					E_DNS_CRITICAL /**< critical error, marks the end
dcb59e67
 									  of the error table (always last) */
 };
 
 
 
3ca1a53f
 /** @brief return a short string, printable error description (err <=0) */
dcb59e67
 const char* dns_strerror(int err);
 
ec79c28a
 /** @brief dns entry flags,
  * shall be on the power of 2 */
 /*@{ */
 #define DNS_FLAG_BAD_NAME	1 /**< error flag: unresolvable */
 #define DNS_FLAG_PERMANENT	2 /**< permanent record, never times out,
 					never deleted, never overwritten
 					unless explicitely requested */
 /*@} */
dcb59e67
 
3ca1a53f
 /** @name dns requests flags */
 /*@{ */
dcb59e67
 #define DNS_NO_FLAGS	0
 #define DNS_IPV4_ONLY	1
 #define DNS_IPV6_ONLY	2
 #define DNS_IPV6_FIRST	4
3ca1a53f
 #define DNS_SRV_RR_LB	8  /**< SRV RR weight based load balancing */
 #define DNS_TRY_NAPTR	16 /**< enable naptr lookup */
 /*@} */
dcb59e67
 
 
3ca1a53f
 /** @name ip blacklist error flags */
 /*@{ */
dcb59e67
 #define IP_ERR_BAD_DST      2 /* destination is marked as bad (e.g. bad ip) */
 #define IP_ERR_SND          3 /* send error while using this as destination */
 #define IP_ERR_TIMEOUT      4 /* timeout waiting for a response */
 #define IP_ERR_TCP_CON      5 /* could not establish tcp connection */
3ca1a53f
 /*@} */
dcb59e67
 
 
3ca1a53f
 /** @brief stripped down dns rr 
 	@note name, type and class are not needed, contained in struct dns_query */
dcb59e67
 struct dns_rr{
 	struct dns_rr* next;
3ca1a53f
 	void* rdata; /**< depends on the type */
 	ticks_t expire; /**< = ttl + crt_time */
dcb59e67
 };
 
 
 
 #ifdef DNS_LU_LST
 struct dns_lu_lst{  /* last used ordered list */
 	struct dns_lu_lst* next;
 	struct dns_lu_lst* prev;
 };
 #endif
 
 struct dns_hash_entry{
 	/* hash table links */
 	struct dns_hash_entry* next;
 	struct dns_hash_entry* prev;
 #ifdef DNS_LU_LST
 	struct dns_lu_lst last_used_lst;
 #endif
 	struct dns_rr* rr_lst;
 	atomic_t refcnt;
 	ticks_t last_used;
 	ticks_t expire; /* when the whole entry will expire */
 	int total_size;
 	unsigned short type;
ec79c28a
 	unsigned char ent_flags; /* entry flags: unresolvable/permanent */
dcb59e67
 	unsigned char name_len; /* can be maximum 255 bytes */
3c8a8654
 	char name[1]; /* variable length, name, null terminated
dcb59e67
 	                 (actual lenght = name_len +1)*/
 };
 
 
e008edb9
 /* to fit in the limit of MAX_BRANCHES */
 #if MAX_BRANCHES_LIMIT < 32
dae0bc71
 typedef unsigned int srv_flags_t;
dd4ffbb7
 #else
 typedef unsigned long long srv_flags_t;
 #endif
dcb59e67
 
 struct dns_srv_handle{
3ca1a53f
 	struct dns_hash_entry* srv; /**< srv entry */
 	struct dns_hash_entry* a;   /**< a or aaaa current entry */
dae0bc71
 #ifdef DNS_SRV_LB
 	srv_flags_t srv_tried_rrs;
 #endif
3ca1a53f
 	unsigned short port; /**< current port */
 	unsigned char srv_no; /**< current record no. in the srv entry */
 	unsigned char ip_no;  /**< current record no. in the a/aaaa entry */
 	unsigned char proto;  /**< protocol number */
dcb59e67
 };
 
 
 
 const char* dns_strerror(int err);
 
33bfeb9d
 void fix_dns_flags(str *gname, str *name);
 int use_dns_failover_fixup(void *handle, str *gname, str *name, void **val);
 int use_dns_cache_fixup(void *handle, str *gname, str *name, void **val);
 int dns_cache_max_mem_fixup(void *handle, str *gname, str *name, void **val);
abb01fb4
 int init_dns_cache(void);
3c8a8654
 #ifdef USE_DNS_CACHE_STATS
 int init_dns_cache_stats(int iproc_num);
 #define DNS_CACHE_ALL_STATS "dc_all_stats"
 #endif
abb01fb4
 void destroy_dns_cache(void);
dcb59e67
 
 
 void dns_hash_put(struct dns_hash_entry* e);
 void dns_hash_put_shm_unsafe(struct dns_hash_entry* e);
 
 inline static void dns_srv_handle_put(struct dns_srv_handle* h)
 {
 	if (h){
 		if (h->srv){
 			dns_hash_put(h->srv);
 			h->srv=0;
 		}
 		if (h->a){
 			dns_hash_put(h->a);
 			h->a=0;
 		}
 	}
 }
 
 
 
3ca1a53f
 /** @brief use it when copying, it manually increases the ref cound */
dcb59e67
 inline static void dns_srv_handle_ref(struct dns_srv_handle *h)
 {
 	if (h){
 		if (h->srv)
 			atomic_inc(&h->srv->refcnt);
 		if (h->a)
 			atomic_inc(&h->a->refcnt);
 	}
 }
 
 
 
3ca1a53f
 /** @brief safe copy increases the refcnt, src must not change while in this function
dcb59e67
  * WARNING: the copy must be dns_srv_handle_put ! */
 inline static void dns_srv_handle_cpy(struct dns_srv_handle* dst,
 										struct dns_srv_handle* src)
 {
 	dns_srv_handle_ref(src);
 	*dst=*src;
 }
 
 
 
3ca1a53f
 /** @brief same as above but assume shm_lock held (for internal tm use only) */
dcb59e67
 inline static void dns_srv_handle_put_shm_unsafe(struct dns_srv_handle* h)
 {
 	if (h){
 		if (h->srv){
 			dns_hash_put_shm_unsafe(h->srv);
 			h->srv=0;
 		}
 		if (h->a){
 			dns_hash_put_shm_unsafe(h->a);
 			h->a=0;
 		}
 	}
 }
 
 
 
3ca1a53f
 /** @brief get "next" ip next time a dns_srv_handle function is called
dcb59e67
  * params: h   - struct dns_srv_handler
3c8a8654
  *         err - return code of the last dns_*_resolve* call
dcb59e67
  * returns: 0 if it doesn't make sense to try another record,
  * 1 otherwise
  */
 inline static int dns_srv_handle_next(struct dns_srv_handle* h, int err)
 {
 	if (err<0) return 0;
 	h->ip_no++;
 	return (h->srv || h->a);
 }
 
 
 
 inline static void dns_srv_handle_init(struct dns_srv_handle* h)
 {
 	h->srv=h->a=0;
 	h->srv_no=h->ip_no=0;
dd4ffbb7
 	h->port=0;
 	h->proto=0;
dae0bc71
 #ifdef DNS_SRV_LB
 	h->srv_tried_rrs=0;
 #endif
dcb59e67
 }
 
 
 
3ca1a53f
 /** @brief performes a srv query on name
dcb59e67
  * Params:  name  - srv query target (e.g. _sip._udp.foo.bar)
  *          ip    - result: first good ip found
  *          port  - result: corresponding port number
  *          flags - resolve options (like ipv4 only, ipv6 prefered a.s.o)
  * Returns: < 0 on error (can be passed to dns_strerror(), 0 on success
  */
 int dns_srv_get_ip(str* name, struct ip_addr* ip, unsigned short* port,
 					int flags);
 
3ca1a53f
 /** @brief performs an A, AAAA (or both) query/queries
dcb59e67
  * Params:  name  - query target (e.g. foo.bar)
  *          ip    - result: first good ip found
  *          flags - resolve options (like ipv4 only, ipv6 prefered a.s.o)
  * Returns: < 0 on error (can be passed to dns_strerror(), 0 on success
  */
 int dns_get_ip(str* name, struct ip_addr* ip, int flags);
 
 struct hostent* dns_srv_get_he(str* name, unsigned short* port, int flags);
 struct hostent* dns_get_he(str* name, int flags);
 
 
3ca1a53f
 /** @brief resolve name to an ip, using srv record. Can be called multiple times
dcb59e67
  * to iterate on all the possible ips, e.g :
  * dns_srv_handle_init(h);
  * ret_code=dns_sip_resolve(h,...);
  *  while( dns_srv_handle_next(h, ret_code){ ret_code=dns_sip_resolve(h...); }
  * dns_srv_handle_put(h);
  * WARNING: dns_srv_handle_init() must be called to initialize h and
  *  dns_srv_handle_put(h) must be called when h is no longer needed
  */
 int dns_sip_resolve(struct dns_srv_handle* h,  str* name, struct ip_addr* ip,
dd4ffbb7
 					unsigned short* port, char* proto, int flags);
dcb59e67
 
3ca1a53f
 /** @brief same as above, but fills su intead of changing port and filling an ip */
dcb59e67
 inline static int dns_sip_resolve2su(struct dns_srv_handle* h,
 									 union sockaddr_union* su,
 									 str* name, unsigned short port,
dd4ffbb7
 									 char* proto, int flags)
dcb59e67
 {
 	struct ip_addr ip;
 	int ret;
3c8a8654
 
dcb59e67
 	ret=dns_sip_resolve(h, name, &ip, &port, proto, flags);
 	if (ret>=0)
 		init_su(su, &ip, port);
 	return ret;
 }
f682fd71
 
ec79c28a
 /** @brief Delete all the entries from the cache.
  * If del_permanent is 0, then only the
  * non-permanent entries are deleted.
  */
 void dns_cache_flush(int del_permanent);
ba813ed5
 
f682fd71
 #ifdef DNS_WATCHDOG_SUPPORT
3ca1a53f
 /** @brief sets the state of the DNS servers:
f682fd71
  * 1: at least one server is up
  * 0: all the servers are down
  */
 void dns_set_server_state(int state);
50152220
 
3ca1a53f
 /** @brief returns the state of the DNS servers */
50152220
 int dns_get_server_state(void);
f682fd71
 #endif /* DNS_WATCHDOG_SUPPORT */
 
fa09f630
 /** @brief Adds a new record to the cache.
13e59ebb
  * If there is an existing record with the same name and value
  * (ip address in case of A/AAAA record, name in case of SRV record)
  * only the remaining fields are updated.
  *
ec79c28a
  * Note that permanent records cannot be overwritten unless
  * the new record is also permanent. A permanent record
  * completely replaces a non-permanent one.
  *
13e59ebb
  * Currently only A, AAAA, and SRV records are supported.
  */
 int dns_cache_add_record(unsigned short type,
 			str *name,
 			int ttl,
 			str *value,
 			int priority,
 			int weight,
 			int port,
 			int flags);
 
fa09f630
 /** @brief Delete a single record from the cache,
  * i.e. the record with the same name and value
  * (ip address in case of A/AAAA record, name in case of SRV record).
  *
  * Currently only A, AAAA, and SRV records are supported.
  */
 int dns_cache_delete_single_record(unsigned short type,
 			str *name,
 			str *value,
 			int flags);
 
13e59ebb
 
dcb59e67
 #endif