dcb59e67 |
/*
* $Id$
*
* resolver/dns related functions, dns cache and failover
*
* Copyright (C) 2006 iptelorg GmbH
*
* This file is part of ser, a free SIP server.
*
* ser 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 of the License, or
* (at your option) any later version
*
* ser 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.
* |
3c8a8654 |
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software |
dcb59e67 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ |
3ca1a53f |
|
dcb59e67 |
/* History:
* --------
* 2006-07-13 created by andrei |
dd4ffbb7 |
* 2007-06-16 naptr support (andrei) |
3c8a8654 |
* 2007-07-30 DNS cache measurements added (Gergo) |
dcb59e67 |
*/
|
3ca1a53f |
/**
* @file
* @brief SIP-router core :: resolver/dns related functions, dns cache and failover
* @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);
|
3ca1a53f |
/** @brief dns entry error flags */ |
dcb59e67 |
#define DNS_BAD_NAME 1 /* unresolvable */
|
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 */
unsigned char err_flags; /**< if 0 everything is ok */ |
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;
unsigned char err_flags;
unsigned char name_len; /* can be maximum 255 bytes */ |
3c8a8654 |
char name[1]; /* variable length, name, null terminated |
dcb59e67 |
(actual lenght = name_len +1)*/
};
|
dd4ffbb7 |
#if MAX_BRANCHES < 16
/* forking is limited by tm to 12 by default */
typedef unsigned short srv_flags_t;
#elif MAX_BRANCHES < 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); |
dcb59e67 |
int init_dns_cache(); |
3c8a8654 |
#ifdef USE_DNS_CACHE_STATS
int init_dns_cache_stats(int iproc_num);
#define DNS_CACHE_ALL_STATS "dc_all_stats"
#endif |
dcb59e67 |
void destroy_dns_cache();
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 |
|
3ca1a53f |
/** @brief deletes all the entries from the cache */ |
ba813ed5 |
void dns_cache_flush(void);
|
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 */
|
dcb59e67 |
#endif |