• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • Directories
  • File List
  • Globals

dns_cache.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * resolver related functions
00005  *
00006  * Copyright (C) 2006 iptelorg GmbH
00007  *
00008  * This file is part of ser, a free SIP server.
00009  *
00010  * ser is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * For a license to use the ser software under conditions
00016  * other than those described here, or to purchase support for this
00017  * software, please contact iptel.org by e-mail at the following addresses:
00018  *    info@iptel.org
00019  *
00020  * ser is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License
00026  * along with this program; if not, write to the Free Software
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  */
00029 /* History:
00030  * --------
00031  *  2006-07-13  created by andrei
00032  *  2006-10-06  port fix (andrei)
00033  *  2007-06-14  dns iterate through A & AAAA records fix (andrei)
00034  *  2007-06-15  srv rr weight based load balancing support (andrei)
00035  *  2007-06-16  naptr support (andrei)
00036  *  2008-07-18  DNS watchdog support -- can be used to inform the core
00037  *              that the DNS servers are down (Miklos)
00038  *  2008-07-25  various rpc commands to manipulate the content
00039  *              of the cache (Miklos)
00040  *  2007-07-30  DNS cache measurements added (Gergo)
00041  *  2007-08-17  dns_cache_del_nonexp config option is introduced (Miklos)
00042  *  2008-02-04  DNS cache options are adapted for the configuration
00043  *              framework (Miklos)
00044  *  2008-02-11  dns_cache_init cfg parameter is introduced (Miklos)
00045  *  2008-10-17  fixed srv continue with 0 hostname (when falling back to
00046                   aaaa) (andrei)
00047  *  2009-03-30  TXT record support, more rpcs (andrei)
00048  *  2009-03-30  EBL record support (andrei)
00049  *  2009-04-01  PTR record support (andrei)
00050  */
00059 #ifdef USE_DNS_CACHE
00060 
00061 #ifdef DNS_SRV_LB
00062 #include <stdlib.h> /* FIXME: rand() */
00063 #endif
00064 #include <string.h>
00065 
00066 #include "globals.h"
00067 #include "cfg_core.h"
00068 #include "dns_cache.h"
00069 #include "dns_wrappers.h"
00070 #include "compiler_opt.h"
00071 #include "mem/shm_mem.h"
00072 #include "hashes.h"
00073 #include "clist.h"
00074 #include "locking.h"
00075 #include "atomic_ops.h"
00076 #include "ut.h"
00077 #include "timer.h"
00078 #include "timer_ticks.h"
00079 #include "error.h"
00080 #include "rpc.h"
00081 #include "rand/fastrand.h"
00082 #ifdef USE_DNS_CACHE_STATS
00083 #include "pt.h"
00084 #endif
00085 
00086 
00087 
00088 #define DNS_CACHE_DEBUG /* extra sanity checks and debugging */
00089 
00090 
00091 #ifndef MAX
00092         #define MAX(a,b) ( ((a)>(b))?(a):(b))
00093 #endif
00094 
00095 #define MAX_DNS_RECORDS 255  /* maximum dns records number  received in a
00096                                                            dns answer*/
00097 
00098 #define DNS_HASH_SIZE   1024 /* must be <= 65535 */
00099 #define DEFAULT_DNS_TIMER_INTERVAL 120  /* 2 min. */
00100 #define DNS_HE_MAX_ADDR 10  /* maxium addresses returne in a hostent struct */
00101 #define MAX_CNAME_CHAIN  10
00102 #define SPACE_FORMAT "    " /* format of view output */
00103 #define DNS_SRV_ZERO_W_CHANCE   1000 /* one in a 1000*weight_sum chance for
00104                                                                                 selecting a 0-weight record */
00105 
00106 int dns_cache_init=1;   /* if 0, the DNS cache is not initialized at startup */
00107 static gen_lock_t* dns_hash_lock=0;
00108 static volatile unsigned int *dns_cache_mem_used=0; /* current mem. use */
00109 unsigned int dns_timer_interval=DEFAULT_DNS_TIMER_INTERVAL; /* in s */
00110 int dns_flags=0; /* default flags used for the  dns_*resolvehost
00111                     (compatibility wrappers) */
00112 
00113 #ifdef USE_DNS_CACHE_STATS
00114 struct t_dns_cache_stats* dns_cache_stats=0;
00115 #endif
00116 
00117 #define LOCK_DNS_HASH()         lock_get(dns_hash_lock)
00118 #define UNLOCK_DNS_HASH()       lock_release(dns_hash_lock)
00119 
00120 #define FIX_TTL(t) \
00121         (((t)<cfg_get(core, core_cfg, dns_cache_min_ttl))? \
00122                 cfg_get(core, core_cfg, dns_cache_min_ttl): \
00123                 (((t)>cfg_get(core, core_cfg, dns_cache_max_ttl))? \
00124                         cfg_get(core, core_cfg, dns_cache_max_ttl): \
00125                         (t)))
00126 
00127 
00128 struct dns_hash_head{
00129         struct dns_hash_entry* next;
00130         struct dns_hash_entry* prev;
00131 };
00132 
00133 #ifdef DNS_LU_LST
00134 struct dns_lu_lst* dns_last_used_lst=0;
00135 #endif
00136 
00137 static struct dns_hash_head* dns_hash=0;
00138 
00139 
00140 static struct timer_ln* dns_timer_h=0;
00141 
00142 #ifdef DNS_WATCHDOG_SUPPORT
00143 static atomic_t *dns_servers_up = NULL;
00144 #endif
00145 
00146 
00147 
00148 static const char* dns_str_errors[]={
00149         "no error",
00150         "no more records", /* not an error, but and end condition */
00151         "unknown error",
00152         "internal error",
00153         "bad SRV entry",
00154         "unresolvable SRV request",
00155         "bad A or AAAA entry",
00156         "unresolvable A or AAAA request",
00157         "invalid ip in A or AAAA record",
00158         "blacklisted ip",
00159         "name too long ", /* try again with a shorter name */
00160         "ip AF mismatch", /* address family mismatch */
00161         "unresolvable NAPTR request",
00162         "bug - critical error"
00163 };
00164 
00165 
00166 
00167 /* param: err (negative error number) */
00168 const char* dns_strerror(int err)
00169 {
00170         err=-err;
00171         if ((err>=0) && (err<sizeof(dns_str_errors)/sizeof(char*)))
00172                 return dns_str_errors[err];
00173         return "bug -- bad error number";
00174 }
00175 
00176 
00177 
00178 /* "internal" only, don't use unless you really know waht you're doing */
00179 inline static void dns_destroy_entry(struct dns_hash_entry* e)
00180 {
00181 #ifdef DNS_CACHE_DEBUG
00182         memset(e, 0, e->total_size);
00183 #endif
00184         shm_free(e); /* nice having it in one block isn't it? :-) */
00185 }
00186 
00187 
00188 /* "internal" only, same as above, asumes shm_lock() held (tm optimization) */
00189 inline static void dns_destroy_entry_shm_unsafe(struct dns_hash_entry* e)
00190 {
00191 #ifdef DNS_CACHE_DEBUG
00192         memset(e, 0, e->total_size);
00193 #endif
00194         shm_free_unsafe(e); /* nice having it in one block isn't it? :-) */
00195 }
00196 
00197 
00198 
00199 /* dec. the internal refcnt and if 0 deletes the entry */
00200 void dns_hash_put(struct dns_hash_entry* e)
00201 {
00202         if(e && atomic_dec_and_test(&e->refcnt)){
00203                 /* atomic_sub_long(dns_cache_total_used, e->total_size); */
00204                 dns_destroy_entry(e);
00205         }
00206 }
00207 
00208 
00209 
00210 /* same as above but uses dns_destroy_unsafe (assumes shm_lock held -- tm
00211  *  optimization) */
00212 void dns_hash_put_shm_unsafe(struct dns_hash_entry* e)
00213 {
00214         if(e && atomic_dec_and_test(&e->refcnt)){
00215                 /* atomic_sub_long(dns_cache_total_used, e->total_size); */
00216                 dns_destroy_entry_shm_unsafe(e);
00217         }
00218 }
00219 
00220 
00221 inline static int dns_cache_clean(unsigned int no, int expired_only);
00222 inline static int dns_cache_free_mem(unsigned int target, int expired_only);
00223 
00224 static ticks_t dns_timer(ticks_t ticks, struct timer_ln* tl, void* data)
00225 {
00226 #ifdef DNS_WATCHDOG_SUPPORT
00227         /* do not clean the hash table if the servers are down */
00228         if (atomic_get(dns_servers_up) == 0)
00229                 return (ticks_t)(-1);
00230 #endif
00231         if (*dns_cache_mem_used>12*(cfg_get(core, core_cfg, dns_cache_max_mem)/16)){ /* ~ 75% used */
00232                 dns_cache_free_mem(cfg_get(core, core_cfg, dns_cache_max_mem)/2, 1);
00233         }else{
00234                 dns_cache_clean(-1, 1); /* all the table, only expired entries */
00235                 /* TODO: better strategy? */
00236         }
00237         return (ticks_t)(-1);
00238 }
00239 
00240 
00241 
00242 void destroy_dns_cache()
00243 {
00244         if (dns_timer_h){
00245                 timer_del(dns_timer_h);
00246                 timer_free(dns_timer_h);
00247                 dns_timer_h=0;
00248         }
00249 #ifdef DNS_WATCHDOG_SUPPORT
00250         if (dns_servers_up){
00251                 shm_free(dns_servers_up);
00252                 dns_servers_up=0;
00253         }
00254 #endif
00255         if (dns_hash_lock){
00256                 lock_destroy(dns_hash_lock);
00257                 lock_dealloc(dns_hash_lock);
00258                 dns_hash_lock=0;
00259         }
00260         if (dns_hash){
00261                 shm_free(dns_hash);
00262                 dns_hash=0;
00263         }
00264 #ifdef DNS_LU_LST
00265         if (dns_last_used_lst){
00266                 shm_free(dns_last_used_lst);
00267                 dns_last_used_lst=0;
00268         }
00269 #endif
00270 #ifdef USE_DNS_CACHE_STATS
00271         if (dns_cache_stats)
00272                 shm_free(dns_cache_stats);
00273 #endif
00274         if (dns_cache_mem_used){
00275                 shm_free((void*)dns_cache_mem_used);
00276                 dns_cache_mem_used=0;
00277         }
00278 }
00279 
00280 /* set the value of dns_flags */
00281 void fix_dns_flags(str *gname, str *name)
00282 {
00283         /* restore the original value of dns_cache_flags first
00284          * (DNS_IPV4_ONLY may have been set only because dns_try_ipv6
00285          * was disabled, and the flag must be cleared when
00286          * dns_try_ipv6 is enabled) (Miklos)
00287          */
00288         dns_flags = cfg_get(core, core_cfg, dns_cache_flags) & 7;
00289 
00290         if (cfg_get(core, core_cfg, dns_try_ipv6)==0){
00291                 dns_flags|=DNS_IPV4_ONLY;
00292         }
00293         if (dns_flags & DNS_IPV4_ONLY){
00294                 dns_flags&=~(DNS_IPV6_ONLY|DNS_IPV6_FIRST);
00295         }
00296         if (cfg_get(core, core_cfg, dns_srv_lb)){
00297 #ifdef DNS_SRV_LB
00298                 dns_flags|=DNS_SRV_RR_LB;
00299 #else
00300                 LOG(L_WARN, "WARNING: fix_dns_flags: SRV loadbalaning is set, but"
00301                                         " support for it is not compiled -- ignoring\n");
00302 #endif
00303         }
00304         if (cfg_get(core, core_cfg, dns_try_naptr)) {
00305 #ifndef USE_NAPTR
00306         LOG(L_WARN, "WARNING: fix_dns_flags: NAPTR support is enabled, but"
00307                                 " support for it is not compiled -- ignoring\n");
00308 #endif
00309                 dns_flags|=DNS_TRY_NAPTR;
00310         }
00311 }
00312 
00313 /* fixup function for use_dns_failover
00314  * verifies that use_dns_cache is set to 1
00315  */
00316 int use_dns_failover_fixup(void *handle, str *gname, str *name, void **val)
00317 {
00318         if ((int)(long)(*val) && !cfg_get(core, handle, use_dns_cache)) {
00319                 LOG(L_ERR, "ERROR: use_dns_failover_fixup(): "
00320                         "DNS cache is turned off, failover cannot be enabled. "
00321                         "(set use_dns_cache to 1)\n");
00322                 return -1;
00323         }
00324         return 0;
00325 }
00326 
00327 /* fixup function for use_dns_cache
00328  * verifies that dns_cache_init is set to 1
00329  */
00330 int use_dns_cache_fixup(void *handle, str *gname, str *name, void **val)
00331 {
00332         if ((int)(long)(*val) && !dns_cache_init) {
00333                 LOG(L_ERR, "ERROR: use_dns_cache_fixup(): "
00334                         "DNS cache is turned off by dns_cache_init=0, "
00335                         "it cannot be enabled runtime.\n");
00336                 return -1;
00337         }
00338         if (((int)(long)(*val)==0) && cfg_get(core, handle, use_dns_failover)) {
00339                 LOG(L_ERR, "ERROR: use_dns_failover_fixup(): "
00340                         "DNS failover depends on use_dns_cache, set use_dns_failover "
00341                         "to 0 before disabling the DNS cache\n");
00342                 return -1;
00343         }
00344         return 0;
00345 }
00346 
00347 /* KByte to Byte conversion */
00348 int dns_cache_max_mem_fixup(void *handle, str *gname, str *name, void **val)
00349 {
00350         unsigned int    u;
00351 
00352         u = ((unsigned int)(long)(*val))<<10;
00353         (*val) = (void *)(long)u;
00354         return 0;
00355 }
00356 
00357 int init_dns_cache()
00358 {
00359         int r;
00360         int ret;
00361 
00362         if (dns_cache_init==0) {
00363                 /* the DNS cache is turned off */
00364                 default_core_cfg.use_dns_cache=0;
00365                 default_core_cfg.use_dns_failover=0;
00366                 return 0;
00367         }
00368 
00369         ret=0;
00370         /* sanity check */
00371         if (E_DNS_CRITICAL>=sizeof(dns_str_errors)/sizeof(char*)){
00372                 LOG(L_CRIT, "BUG: dns_cache_init: bad dns error table\n");
00373                 ret=E_BUG;
00374                 goto error;
00375         }
00376         dns_cache_mem_used=shm_malloc(sizeof(*dns_cache_mem_used));
00377         if (dns_cache_mem_used==0){
00378                 ret=E_OUT_OF_MEM;
00379                 goto error;
00380         }
00381 #ifdef DNS_LU_LST
00382         dns_last_used_lst=shm_malloc(sizeof(*dns_last_used_lst));
00383         if (dns_last_used_lst==0){
00384                 ret=E_OUT_OF_MEM;
00385                 goto error;
00386         }
00387         clist_init(dns_last_used_lst, next, prev);
00388 #endif
00389         dns_hash=shm_malloc(sizeof(struct dns_hash_head)*DNS_HASH_SIZE);
00390         if (dns_hash==0){
00391                 ret=E_OUT_OF_MEM;
00392                 goto error;
00393         }
00394         for (r=0; r<DNS_HASH_SIZE; r++)
00395                 clist_init(&dns_hash[r], next, prev);
00396 
00397         dns_hash_lock=lock_alloc();
00398         if (dns_hash_lock==0){
00399                 ret=E_OUT_OF_MEM;
00400                 goto error;
00401         }
00402         if (lock_init(dns_hash_lock)==0){
00403                 lock_dealloc(dns_hash_lock);
00404                 dns_hash_lock=0;
00405                 ret=-1;
00406                 goto error;
00407         }
00408 
00409 #ifdef DNS_WATCHDOG_SUPPORT
00410         dns_servers_up=shm_malloc(sizeof(atomic_t));
00411         if (dns_servers_up==0){
00412                 ret=E_OUT_OF_MEM;
00413                 goto error;
00414         }
00415         atomic_set(dns_servers_up, 1);
00416 #endif
00417 
00418         /* fix options */
00419         default_core_cfg.dns_cache_max_mem<<=10; /* Kb */ /* TODO: test with 0 */
00420         if (default_core_cfg.use_dns_cache==0)
00421                 default_core_cfg.use_dns_failover=0; /* cannot work w/o dns_cache support */
00422         /* fix flags */
00423         fix_dns_flags(NULL, NULL);
00424 
00425         dns_timer_h=timer_alloc();
00426         if (dns_timer_h==0){
00427                 ret=E_OUT_OF_MEM;
00428                 goto error;
00429         }
00430         if (dns_timer_interval){
00431                 timer_init(dns_timer_h, dns_timer, 0, 0); /* "slow" timer */
00432                 if (timer_add(dns_timer_h, S_TO_TICKS(dns_timer_interval))<0){
00433                         LOG(L_CRIT, "BUG: dns_cache_init: failed to add the timer\n");
00434                         timer_free(dns_timer_h);
00435                         dns_timer_h=0;
00436                         goto error;
00437                 }
00438         }
00439 
00440         return 0;
00441 error:
00442         destroy_dns_cache();
00443         return ret;
00444 }
00445 
00446 #ifdef USE_DNS_CACHE_STATS
00447 int init_dns_cache_stats(int iproc_num)
00448 {
00449         /* do not initialize the stats array if the DNS cache will not be used */
00450         if (dns_cache_init==0) return 0;
00451 
00452         /* if it is already initialized */
00453         if (dns_cache_stats)
00454                 shm_free(dns_cache_stats);
00455 
00456         dns_cache_stats=shm_malloc(sizeof(*dns_cache_stats) * iproc_num);
00457         if (dns_cache_stats==0){
00458                 return E_OUT_OF_MEM;
00459         }
00460         memset(dns_cache_stats, 0, sizeof(*dns_cache_stats) * iproc_num);
00461 
00462         return 0;
00463 }
00464 #endif
00465 
00466 /* hash function, type is not used (obsolete)
00467  * params: char* s, int len, int type
00468  * returns the hash value
00469  */
00470 #define dns_hash_no(s, len, type) \
00471         (get_hash1_case_raw((s),(len)) % DNS_HASH_SIZE)
00472 
00473 
00474 
00475 #ifdef DNS_CACHE_DEBUG
00476 #define DEBUG_LU_LST
00477 #ifdef DEBUG_LU_LST
00478 
00479 #include <stdlib.h> /* abort() */
00480 #define check_lu_lst(l) ((((l)->next==(l)) || ((l)->prev==(l))) && \
00481                                                         ((l)!=dns_last_used_lst))
00482 
00483 #define dbg_lu_lst(txt, l) \
00484                 LOG(L_CRIT, "BUG: %s: crt(%p, %p, %p)," \
00485                                         " prev(%p, %p, %p), next(%p, %p, %p)\n", txt, \
00486                                         (l), (l)->next, (l)->prev, \
00487                                         (l)->prev, (l)->prev->next, (l)->prev->prev, \
00488                                         (l)->next, (l)->next->next, (l)->next->prev \
00489                                 )
00490 
00491 #define debug_lu_lst( txt, l) \
00492         do{ \
00493                 if (check_lu_lst((l))){  \
00494                         dbg_lu_lst(txt  " crt:", (l)); \
00495                         abort(); \
00496                 } \
00497                 if (check_lu_lst((l)->next)){ \
00498                         dbg_lu_lst(txt  " next:",  (l)); \
00499                         abort(); \
00500                 } \
00501                 if (check_lu_lst((l)->prev)){ \
00502                         dbg_lu_lst(txt  " prev:", (l)); \
00503                         abort(); \
00504                 } \
00505         }while(0)
00506 
00507 #endif
00508 #endif /* DNS_CACHE_DEBUG */
00509 
00510 
00511 /* must be called with the DNS_LOCK hold
00512  * remove and entry from the hash, dec. its refcnt and if not referenced
00513  * anymore deletes it */
00514 inline static void _dns_hash_remove(struct dns_hash_entry* e)
00515 {
00516         clist_rm(e, next, prev);
00517 #ifdef DNS_CACHE_DEBUG
00518         e->next=e->prev=0;
00519 #endif
00520 #ifdef DNS_LU_LST
00521 #ifdef DEBUG_LU_LST
00522         debug_lu_lst("_dns_hash_remove: pre rm:", &e->last_used_lst);
00523 #endif
00524         clist_rm(&e->last_used_lst, next, prev);
00525 #ifdef DEBUG_LU_LST
00526         debug_lu_lst("_dns_hash_remove: post rm:", &e->last_used_lst);
00527 #endif
00528 #ifdef DNS_CACHE_DEBUG
00529         e->last_used_lst.next=e->last_used_lst.prev=0;
00530 #endif
00531 #endif
00532         *dns_cache_mem_used-=e->total_size;
00533         dns_hash_put(e);
00534 }
00535 
00536 
00537 
00538 /* non locking  version (the dns hash must _be_ locked externally)
00539  * returns 0 when not found, or the entry on success (an entry with a
00540  * similar name but with a CNAME type will always match).
00541  * it doesn't increase the internal refcnt
00542  * returns the entry when found, 0 when not found and sets *err to !=0
00543  *  on error (e.g. recursive cnames)
00544  * WARNING: - internal use only
00545  *          - always check if the returned entry type is CNAME */
00546 inline static struct dns_hash_entry* _dns_hash_find(str* name, int type,
00547                                                                                                                 int* h, int* err)
00548 {
00549         struct dns_hash_entry* e;
00550         struct dns_hash_entry* tmp;
00551         struct dns_hash_entry* ret;
00552         ticks_t now;
00553         int cname_chain;
00554         str cname;
00555 #ifdef DNS_WATCHDOG_SUPPORT
00556         int servers_up;
00557 
00558         servers_up = atomic_get(dns_servers_up);
00559 #endif
00560 
00561         cname_chain=0;
00562         ret=0;
00563         now=get_ticks_raw();
00564         *err=0;
00565 again:
00566         *h=dns_hash_no(name->s, name->len, type);
00567 #ifdef DNS_CACHE_DEBUG
00568         DBG("dns_hash_find(%.*s(%d), %d), h=%d\n", name->len, name->s,
00569                                                                                                 name->len, type, *h);
00570 #endif
00571         clist_foreach_safe(&dns_hash[*h], e, tmp, next){
00572                 if (
00573 #ifdef DNS_WATCHDOG_SUPPORT
00574                         /* remove expired elements only when the dns servers are up */
00575                         servers_up &&
00576 #endif
00577                         /* automatically remove expired elements */
00578                         ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
00579                         ((s_ticks_t)(now-e->expire)>=0)
00580                 ) {
00581                                 _dns_hash_remove(e);
00582                 }else if ((e->type==type) && (e->name_len==name->len) &&
00583                         (strncasecmp(e->name, name->s, e->name_len)==0)){
00584                         e->last_used=now;
00585 #ifdef DNS_LU_LST
00586                         /* add it at the end */
00587 #ifdef DEBUG_LU_LST
00588                         debug_lu_lst("_dns_hash_find: pre rm:", &e->last_used_lst);
00589 #endif
00590                         clist_rm(&e->last_used_lst, next, prev);
00591                         clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
00592 #ifdef DEBUG_LU_LST
00593                         debug_lu_lst("_dns_hash_find: post append:", &e->last_used_lst);
00594 #endif
00595 #endif
00596                         return e;
00597                 }else if ((e->type==T_CNAME) &&
00598                                         !((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)) &&
00599                                         (e->name_len==name->len) &&
00600                                         (strncasecmp(e->name, name->s, e->name_len)==0)){
00601                         /*if CNAME matches and CNAME is entry is not a neg. cache entry
00602                           (could be produced by a specific CNAME lookup)*/
00603                         e->last_used=now;
00604 #ifdef DNS_LU_LST
00605                         /* add it at the end */
00606 #ifdef DEBUG_LU_LST
00607                         debug_lu_lst("_dns_hash_find: cname: pre rm:", &e->last_used_lst);
00608 #endif
00609                         clist_rm(&e->last_used_lst, next, prev);
00610                         clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
00611 #ifdef DEBUG_LU_LST
00612                         debug_lu_lst("_dns_hash_find: cname: post append:",
00613                                                         &e->last_used_lst);
00614 #endif
00615 #endif
00616                         ret=e; /* if this is an unfinished cname chain, we try to
00617                                           return the last cname */
00618                         /* this is a cname => retry using its value */
00619                         if (cname_chain> MAX_CNAME_CHAIN){
00620                                 LOG(L_ERR, "ERROR: _dns_hash_find: cname chain too long "
00621                                                 "or recursive (\"%.*s\")\n", name->len, name->s);
00622                                 ret=0; /* error*/
00623                                 *err=-1;
00624                                 break;
00625                         }
00626                         cname_chain++;
00627                         cname.s=((struct cname_rdata*)e->rr_lst->rdata)->name;
00628                         cname.len= ((struct cname_rdata*)e->rr_lst->rdata)->name_len;
00629                         name=&cname;
00630                         goto again;
00631                 }
00632         }
00633         return ret;
00634 }
00635 
00636 
00637 
00638 /* frees cache entries, if expired_only=0 only expired entries will be
00639  * removed, else all of them
00640  * it will process maximum no entries (to process all of them use -1)
00641  * returns the number of deleted entries
00642  * This should be called from a timer process*/
00643 inline static int dns_cache_clean(unsigned int no, int expired_only)
00644 {
00645         struct dns_hash_entry* e;
00646         ticks_t now;
00647         unsigned int n;
00648         unsigned int deleted;
00649 #ifdef DNS_LU_LST
00650         struct dns_lu_lst* l;
00651         struct dns_lu_lst* tmp;
00652 #else
00653         struct dns_hash_entry* t;
00654         unsigned int h;
00655         static unsigned int start=0;
00656 #endif
00657 
00658         n=0;
00659         deleted=0;
00660         now=get_ticks_raw();
00661         LOCK_DNS_HASH();
00662 #ifdef DNS_LU_LST
00663         clist_foreach_safe(dns_last_used_lst, l, tmp, next){
00664                 e=(struct dns_hash_entry*)(((char*)l)-
00665                                 (char*)&((struct dns_hash_entry*)(0))->last_used_lst);
00666                 if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
00667                         && (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
00668                 ) {
00669                                 _dns_hash_remove(e);
00670                                 deleted++;
00671                 }
00672                 n++;
00673                 if (n>=no) break;
00674         }
00675 #else
00676         for(h=start; h!=(start+DNS_HASH_SIZE); h++){
00677                 clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
00678                         if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
00679                                 && ((s_ticks_t)(now-e->expire)>=0)
00680                         ) {
00681                                 _dns_hash_remove(e);
00682                                 deleted++;
00683                         }
00684                         n++;
00685                         if (n>=no) goto skip;
00686                 }
00687         }
00688         /* not fair, but faster then random() */
00689         if (!expired_only){
00690                 for(h=start; h!=(start+DNS_HASH_SIZE); h++){
00691                         clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
00692                                 if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) {
00693                                         _dns_hash_remove(e);
00694                                         deleted++;
00695                                 }
00696                                 n++;
00697                                 if (n>=no) goto skip;
00698                         }
00699                 }
00700         }
00701 skip:
00702         start=h;
00703 #endif
00704         UNLOCK_DNS_HASH();
00705         return deleted;
00706 }
00707 
00708 
00709 
00710 /* frees cache entries, if expired_only=0 only expired entries will be
00711  * removed, else all of them
00712  * it will stop when the dns cache used memory reaches target (to process all
00713  * of them use 0)
00714  * returns the number of deleted entries */
00715 inline static int dns_cache_free_mem(unsigned int target, int expired_only)
00716 {
00717         struct dns_hash_entry* e;
00718         ticks_t now;
00719         unsigned int deleted;
00720 #ifdef DNS_LU_LST
00721         struct dns_lu_lst* l;
00722         struct dns_lu_lst* tmp;
00723 #else
00724         struct dns_hash_entry* t;
00725         unsigned int h;
00726         static unsigned int start=0;
00727 #endif
00728 
00729         deleted=0;
00730         now=get_ticks_raw();
00731         LOCK_DNS_HASH();
00732 #ifdef DNS_LU_LST
00733         clist_foreach_safe(dns_last_used_lst, l, tmp, next){
00734                 if (*dns_cache_mem_used<=target) break;
00735                 e=(struct dns_hash_entry*)(((char*)l)-
00736                                 (char*)&((struct dns_hash_entry*)(0))->last_used_lst);
00737                 if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
00738                         && (!expired_only || ((s_ticks_t)(now-e->expire)>=0))
00739                 ) {
00740                                 _dns_hash_remove(e);
00741                                 deleted++;
00742                 }
00743         }
00744 #else
00745         for(h=start; h!=(start+DNS_HASH_SIZE); h++){
00746                 clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
00747                         if (*dns_cache_mem_used<=target)
00748                                 goto skip;
00749                         if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
00750                                 && ((s_ticks_t)(now-e->expire)>=0)
00751                         ) {
00752                                 _dns_hash_remove(e);
00753                                 deleted++;
00754                         }
00755                 }
00756         }
00757         /* not fair, but faster then random() */
00758         if (!expired_only){
00759                 for(h=start; h!=(start+DNS_HASH_SIZE); h++){
00760                         clist_foreach_safe(&dns_hash[h%DNS_HASH_SIZE], e, t, next){
00761                                 if (*dns_cache_mem_used<=target)
00762                                         goto skip;
00763                                 if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
00764                                         && ((s_ticks_t)(now-e->expire)>=0)
00765                                 ) {
00766                                         _dns_hash_remove(e);
00767                                         deleted++;
00768                                 }
00769                         }
00770                 }
00771         }
00772 skip:
00773         start=h;
00774 #endif
00775         UNLOCK_DNS_HASH();
00776         return deleted;
00777 }
00778 
00779 
00780 
00781 /* locking  version (the dns hash must _not_be locked externally)
00782  * returns 0 when not found, the searched entry on success (with CNAMEs
00783  *  followed) or the last CNAME entry from an unfinished CNAME chain,
00784  *  if the search matches a CNAME. On error sets *err (e.g. recursive CNAMEs).
00785  * it increases the internal refcnt => when finished dns_hash_put() must
00786  *  be called on the returned entry
00787  *  WARNING: - the return might be a CNAME even if type!=CNAME, see above */
00788 inline static struct dns_hash_entry* dns_hash_get(str* name, int type, int* h,
00789                                                                                                         int* err)
00790 {
00791         struct dns_hash_entry* e;
00792 
00793         LOCK_DNS_HASH();
00794         e=_dns_hash_find(name, type, h, err);
00795         if (e){
00796                 atomic_inc(&e->refcnt);
00797         }
00798         UNLOCK_DNS_HASH();
00799         return e;
00800 }
00801 
00802 
00803 
00804 /* adds a fully created and init. entry (see dns_cache_mk_entry()) to the hash
00805  * table
00806  * returns 0 on success, -1 on error */
00807 inline static int dns_cache_add(struct dns_hash_entry* e)
00808 {
00809         int h;
00810 
00811         /* check space */
00812         /* atomic_add_long(dns_cache_total_used, e->size); */
00813         if ((*dns_cache_mem_used+e->total_size)>=cfg_get(core, core_cfg, dns_cache_max_mem)){
00814 #ifdef USE_DNS_CACHE_STATS
00815                 dns_cache_stats[process_no].dc_lru_cnt++;
00816 #endif
00817                 LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n");
00818                 /* free ~ 12% of the cache */
00819                 dns_cache_free_mem(*dns_cache_mem_used/16*14,
00820                                         !cfg_get(core, core_cfg, dns_cache_del_nonexp));
00821                 if ((*dns_cache_mem_used+e->total_size)>=cfg_get(core, core_cfg, dns_cache_max_mem)){
00822                         LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n");
00823                         return -1;
00824                 }
00825         }
00826         atomic_inc(&e->refcnt);
00827         h=dns_hash_no(e->name, e->name_len, e->type);
00828 #ifdef DNS_CACHE_DEBUG
00829         DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
00830                         e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
00831 #endif
00832         LOCK_DNS_HASH();
00833                 *dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
00834                                                                                  only from within a lock */
00835                 clist_append(&dns_hash[h], e, next, prev);
00836 #ifdef DNS_LU_LST
00837                 clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
00838 #endif
00839         UNLOCK_DNS_HASH();
00840         return 0;
00841 }
00842 
00843 
00844 
00845 /* same as above, but it must be called with the dns hash lock held
00846  * returns 0 on success, -1 on error */
00847 inline static int dns_cache_add_unsafe(struct dns_hash_entry* e)
00848 {
00849         int h;
00850 
00851         /* check space */
00852         /* atomic_add_long(dns_cache_total_used, e->size); */
00853         if ((*dns_cache_mem_used+e->total_size)>=cfg_get(core, core_cfg, dns_cache_max_mem)){
00854 #ifdef USE_DNS_CACHE_STATS
00855                 dns_cache_stats[process_no].dc_lru_cnt++;
00856 #endif
00857                 LOG(L_WARN, "WARNING: dns_cache_add: cache full, trying to free...\n");
00858                 /* free ~ 12% of the cache */
00859                 UNLOCK_DNS_HASH();
00860                 dns_cache_free_mem(*dns_cache_mem_used/16*14,
00861                                         !cfg_get(core, core_cfg, dns_cache_del_nonexp));
00862                 LOCK_DNS_HASH();
00863                 if ((*dns_cache_mem_used+e->total_size)>=cfg_get(core, core_cfg, dns_cache_max_mem)){
00864                         LOG(L_ERR, "ERROR: dns_cache_add: max. cache mem size exceeded\n");
00865                         return -1;
00866                 }
00867         }
00868         atomic_inc(&e->refcnt);
00869         h=dns_hash_no(e->name, e->name_len, e->type);
00870 #ifdef DNS_CACHE_DEBUG
00871         DBG("dns_cache_add: adding %.*s(%d) %d (flags=%0x) at %d\n",
00872                         e->name_len, e->name, e->name_len, e->type, e->ent_flags, h);
00873 #endif
00874         *dns_cache_mem_used+=e->total_size; /* no need for atomic ops, written
00875                                                                                  only from within a lock */
00876         clist_append(&dns_hash[h], e, next, prev);
00877 #ifdef DNS_LU_LST
00878         clist_append(dns_last_used_lst, &e->last_used_lst, next, prev);
00879 #endif
00880         return 0;
00881 }
00882 
00883 
00884 
00885 /* creates a "negative" entry which will be valid for ttl seconds */
00886 inline static struct dns_hash_entry* dns_cache_mk_bad_entry(str* name,
00887                                                                                                                         int type,
00888                                                                                                                         int ttl,
00889                                                                                                                         int flags)
00890 {
00891         struct dns_hash_entry* e;
00892         int size;
00893         ticks_t now;
00894 
00895 #ifdef DNS_CACHE_DEBUG
00896         DBG("dns_cache_mk_bad_entry(%.*s, %d, %d, %d)\n", name->len, name->s,
00897                                                                         type, ttl, flags);
00898 #endif
00899         size=sizeof(struct dns_hash_entry)+name->len-1+1;
00900         e=shm_malloc(size);
00901         if (e==0){
00902                 LOG(L_ERR, "ERROR: dns_cache_mk_bad_entry: out of memory\n");
00903                 return 0;
00904         }
00905         memset(e, 0, size); /* init with 0*/
00906         e->total_size=size;
00907         e->name_len=name->len;
00908         e->type=type;
00909         now=get_ticks_raw();
00910         e->last_used=now;
00911         e->expire=now+S_TO_TICKS(ttl);
00912         memcpy(e->name, name->s, name->len);
00913         e->ent_flags=flags;
00914         return e;
00915 }
00916 
00917 
00918 
00919 /* create a a/aaaa hash entry from a name and ip address
00920  * returns 0 on error */
00921 inline static struct dns_hash_entry* dns_cache_mk_ip_entry(str* name,
00922                                                                                                                         struct ip_addr* ip)
00923 {
00924         struct dns_hash_entry* e;
00925         int size;
00926         ticks_t now;
00927 
00928         /* everything is allocated in one block: dns_hash_entry + name +
00929          * + dns_rr + rdata;  dns_rr must start at an aligned adress,
00930          * hence we need to round dns_hash_entry+name size to a sizeof(long)
00931          * multiple.
00932          * Memory image:
00933          * struct dns_hash_entry
00934          * name (name_len+1 bytes)
00935          * padding to multiple of sizeof(long)
00936          * dns_rr
00937          * rdata  (no padding needed, since for ip is just an array of chars)
00938           */
00939         size=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1)+
00940                         sizeof(struct dns_rr)+ ip->len;
00941         e=shm_malloc(size);
00942         if (e==0){
00943                 LOG(L_ERR, "ERROR: dns_cache_mk_ip_entry: out of memory\n");
00944                 return 0;
00945         }
00946         memset(e, 0, size); /* init with 0*/
00947         e->total_size=size;
00948         e->name_len=name->len;
00949         e->type=(ip->af==AF_INET)?T_A:T_AAAA;
00950         now=get_ticks_raw();
00951         e->last_used=now;
00952         e->expire=now-1; /* maximum expire */
00953         memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
00954         e->rr_lst=(void*)((char*)e+
00955                                 ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
00956         e->rr_lst->rdata=(void*)((char*)e->rr_lst+sizeof(struct dns_rr));
00957         e->rr_lst->expire=now-1; /* maximum expire */
00958         /* no need to align rr_lst->rdata for a or aaaa records */
00959         memcpy(e->rr_lst->rdata, ip->u.addr, ip->len);
00960         return e;
00961 }
00962 
00963 /* creates an srv hash entry from the given parameters
00964  * returns 0 on error */
00965 static struct dns_hash_entry* dns_cache_mk_srv_entry(str* name,
00966                                                         unsigned short priority,
00967                                                         unsigned short weight,
00968                                                         unsigned short port,
00969                                                         str* rr_name,
00970                                                         int ttl)
00971 {
00972         struct dns_hash_entry* e;
00973         int size;
00974         ticks_t now;
00975 
00976         /* everything is allocated in one block: dns_hash_entry + name +
00977          * + dns_rr + rdata;  dns_rr must start at an aligned adress,
00978          * hence we need to round dns_hash_entry+name size to a sizeof(long),
00979          * and similarly, dns_rr must be rounded to sizeof(short).
00980          * multiple.
00981          * Memory image:
00982          * struct dns_hash_entry
00983          * name (name_len+1 bytes)
00984          * padding to multiple of sizeof(long)
00985          * dns_rr
00986          * padding to multiple of sizeof(short)
00987          * rdata
00988           */
00989         size=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1) +
00990                 ROUND_SHORT(sizeof(struct dns_rr)) +
00991                 sizeof(struct srv_rdata)-1 +
00992                 rr_name->len+1;
00993 
00994         e=shm_malloc(size);
00995         if (e==0){
00996                 LOG(L_ERR, "ERROR: dns_cache_srv_ip_entry: out of memory\n");
00997                 return 0;
00998         }
00999         memset(e, 0, size); /* init with 0*/
01000         e->total_size=size;
01001         e->name_len=name->len;
01002         e->type=T_SRV;
01003         now=get_ticks_raw();
01004         e->last_used=now;
01005         e->expire=now+S_TO_TICKS(ttl);
01006         memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
01007         e->rr_lst=(void*)((char*)e+
01008                                 ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
01009         e->rr_lst->rdata=(void*)((char*)e->rr_lst+ROUND_SHORT(sizeof(struct dns_rr)));
01010         e->rr_lst->expire=e->expire;
01011         ((struct srv_rdata*)e->rr_lst->rdata)->priority = priority;
01012         ((struct srv_rdata*)e->rr_lst->rdata)->weight = weight;
01013         ((struct srv_rdata*)e->rr_lst->rdata)->port = port;
01014         ((struct srv_rdata*)e->rr_lst->rdata)->name_len = rr_name->len;
01015         memcpy(((struct srv_rdata*)e->rr_lst->rdata)->name, rr_name->s, rr_name->len);
01016         return e;
01017 }
01018 
01019 
01020 /* create a dns hash entry from a name and a rdata list (pkg_malloc'ed)
01021  * (it will use only the type records with the name "name" from the
01022  *  rdata list with one exception: if a matching CNAME with the same
01023  *  name is found, the search will stop and this will be the record used)
01024  * returns 0 on error and removes the used elements from the rdata list*/
01025 inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
01026                                                                                                                 struct rdata** rd_lst)
01027 {
01028         struct dns_hash_entry* e;
01029         struct dns_rr* rr;
01030         struct dns_rr** tail_rr;
01031         struct rdata** p;
01032         struct rdata* tmp_lst;
01033         struct rdata** tail;
01034         struct rdata* l;
01035         int size;
01036         ticks_t now;
01037         unsigned int max_ttl;
01038         unsigned int ttl;
01039         int i;
01040 
01041 #define rec_matches(rec, t, n) /*(struct rdata* record, int type, str* name)*/\
01042         (       ((rec)->name_len==(n)->len) && ((rec)->type==(t)) && \
01043                 (strncasecmp((rec)->name, (n)->s, (n)->len)==0))
01044         /* init */
01045         tmp_lst=0;
01046         tail=&tmp_lst;
01047 
01048 
01049         /* everything is allocated in one block: dns_hash_entry + name +
01050          * + dns_rr + rdata_raw+ ....;  dns_rr must start at an aligned adress,
01051          * hence we need to round dns_hash_entry+name size to a sizeof(long)
01052          * multiple. If rdata type requires it, rdata_raw might need to be also
01053          * aligned.
01054          * Memory image:
01055          * struct dns_hash_entry  (e)
01056          * name (name_len+1 bytes)  (&e->name[0])
01057          * padding to multiple of sizeof(char*)
01058          * dns_rr1 (e->rr_lst)
01059          * possible padding: no padding for a_rdata or aaaa_rdata,
01060          *                   multipe of sizeof(short) for srv_rdata,
01061          *                   multiple of sizeof(long) for naptr_rdata and others
01062          * dns_rr1->rdata  (e->rr_lst->rdata)
01063          * padding to multipe of sizeof long
01064          * dns_rr2 (e->rr_lst->next)
01065          * ....
01066          *
01067          */
01068         size=0;
01069         if (*rd_lst==0)
01070                 return 0;
01071         /* find the first matching rr, if it's a CNAME use CNAME as type,
01072          * if not continue with the original type */
01073         for(p=rd_lst; *p; p=&(*p)->next){
01074                 if (((*p)->name_len==name->len) &&
01075                                 (((*p)->type==type) || ((*p)->type==T_CNAME)) &&
01076                                 (strncasecmp((*p)->name, name->s, name->len)==0)){
01077                         type=(*p)->type;
01078                         break;
01079                 }
01080         }
01081         /* continue, we found the type we are looking for */
01082         switch(type){
01083                 case T_A:
01084                         for(; *p;){
01085                                 if (!rec_matches((*p), type, name)){
01086                                         /* skip this record */
01087                                         p=&(*p)->next; /* advance */
01088                                         continue;
01089                                 }
01090                                 size+=ROUND_POINTER(sizeof(struct dns_rr)+
01091                                                                                 sizeof(struct a_rdata));
01092                                 /* add it to our tmp. lst */
01093                                 *tail=*p;
01094                                 tail=&(*p)->next;
01095                                 /* detach it from the rd list */
01096                                 *p=(*p)->next;
01097                                 /* don't advance p, because the crt. elem. has
01098                                  * just been elimintated */
01099                         }
01100                         break;
01101                 case T_AAAA:
01102                         for(; *p;){
01103                                 if (!rec_matches((*p), type, name)){
01104                                         /* skip this record */
01105                                         p=&(*p)->next; /* advance */
01106                                         continue;
01107                                 }
01108                                 /* no padding */
01109                                 size+=ROUND_POINTER(sizeof(struct dns_rr)+
01110                                                                                         sizeof(struct aaaa_rdata));
01111                                 /* add it to our tmp. lst */
01112                                 *tail=*p;
01113                                 tail=&(*p)->next;
01114                                 /* detach it from the rd list */
01115                                 *p=(*p)->next;
01116                                 /* don't advance p, because the crt. elem. has
01117                                  * just been elimintated */
01118                         }
01119                         break;
01120                 case T_SRV:
01121                         for(; *p;){
01122                                 if (!rec_matches((*p), type, name)){
01123                                         /* skip this record */
01124                                         p=&(*p)->next; /* advance */
01125                                         continue;
01126                                 }
01127                                 /* padding to short */
01128                                 size+=ROUND_POINTER(ROUND_SHORT(sizeof(struct dns_rr))+
01129                                                 SRV_RDATA_SIZE(*(struct srv_rdata*)(*p)->rdata));
01130                                 /* add it to our tmp. lst */
01131                                 *tail=*p;
01132                                 tail=&(*p)->next;
01133                                 /* detach it from the rd list */
01134                                 *p=(*p)->next;
01135                                 /* don't advance p, because the crt. elem. has
01136                                  * just been elimintated */
01137                         }
01138                         break;
01139                 case T_NAPTR:
01140                         for(; *p;){
01141                                 if (!rec_matches((*p), type, name)){
01142                                         /* skip this record */
01143                                         p=&(*p)->next; /* advance */
01144                                         continue;
01145                                 }
01146                                 /* padding to char* */
01147                                 size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01148                                                 NAPTR_RDATA_SIZE(*(struct naptr_rdata*)(*p)->rdata));
01149                                 /* add it to our tmp. lst */
01150                                 *tail=*p;
01151                                 tail=&(*p)->next;
01152                                 /* detach it from the rd list */
01153                                 *p=(*p)->next;
01154                                 /* don't advance p, because the crt. elem. has
01155                                  * just been elimintated */
01156                         }
01157                         break;
01158                 case T_CNAME:
01159                         for(; *p;){
01160                                 if (!rec_matches((*p), type, name)){
01161                                         /* skip this record */
01162                                         p=&(*p)->next; /* advance */
01163                                         continue;
01164                                 }
01165                                 /* no padding */
01166                                 size+=ROUND_POINTER(sizeof(struct dns_rr)+
01167                                                 CNAME_RDATA_SIZE(*(struct cname_rdata*)(*p)->rdata));
01168                                 /* add it to our tmp. lst */
01169                                 *tail=*p;
01170                                 tail=&(*p)->next;
01171                                 /* detach it from the rd list */
01172                                 *p=(*p)->next;
01173                                 /* don't advance p, because the crt. elem. has
01174                                  * just been elimintated */
01175                         }
01176                         break;
01177                 case T_TXT:
01178                         for(; *p;){
01179                                 if (!rec_matches((*p), type, name)){
01180                                         /* skip this record */
01181                                         p=&(*p)->next; /* advance */
01182                                         continue;
01183                                 }
01184                                 /* padding to char* (because of txt[]->cstr*/
01185                                 size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01186                                                 TXT_RDATA_SIZE(*(struct txt_rdata*)(*p)->rdata));
01187                                 /* add it to our tmp. lst */
01188                                 *tail=*p;
01189                                 tail=&(*p)->next;
01190                                 /* detach it from the rd list */
01191                                 *p=(*p)->next;
01192                                 /* don't advance p, because the crt. elem. has
01193                                  * just been elimintated */
01194                         }
01195                         break;
01196                 case T_EBL:
01197                         for(; *p;){
01198                                 if (!rec_matches((*p), type, name)){
01199                                         /* skip this record */
01200                                         p=&(*p)->next; /* advance */
01201                                         continue;
01202                                 }
01203                                 /* padding to char* (because of the char* pointers */
01204                                 size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01205                                                 EBL_RDATA_SIZE(*(struct ebl_rdata*)(*p)->rdata));
01206                                 /* add it to our tmp. lst */
01207                                 *tail=*p;
01208                                 tail=&(*p)->next;
01209                                 /* detach it from the rd list */
01210                                 *p=(*p)->next;
01211                                 /* don't advance p, because the crt. elem. has
01212                                  * just been elimintated */
01213                         }
01214                         break;
01215                 case T_PTR:
01216                         for(; *p;){
01217                                 if (!rec_matches((*p), type, name)){
01218                                         /* skip this record */
01219                                         p=&(*p)->next; /* advance */
01220                                         continue;
01221                                 }
01222                                 /* no padding */
01223                                 size+=ROUND_POINTER(sizeof(struct dns_rr)+
01224                                                 PTR_RDATA_SIZE(*(struct ptr_rdata*)(*p)->rdata));
01225                                 /* add it to our tmp. lst */
01226                                 *tail=*p;
01227                                 tail=&(*p)->next;
01228                                 /* detach it from the rd list */
01229                                 *p=(*p)->next;
01230                                 /* don't advance p, because the crt. elem. has
01231                                  * just been elimintated */
01232                         }
01233                         break;
01234                 default:
01235                         LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not "
01236                                                         "supported\n", type);
01237                         /* we don't know what to do with it, so don't
01238                          * add it to the tmp_lst */
01239                         return 0; /* error */
01240         }
01241         *tail=0; /* mark the end of our tmp_lst */
01242         if (size==0){
01243 #ifdef DNS_CACHE_DEBUG
01244                 DBG("dns_cache_mk_rd_entry: entry %.*s (%d) not found\n",
01245                                 name->len, name->s, type);
01246 #endif
01247                 return 0;
01248         }
01249         /* compute size */
01250         size+=ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1);
01251         e=shm_malloc(size);
01252         if (e==0){
01253                 LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
01254                 return 0;
01255         }
01256         memset(e, 0, size); /* init with 0 */
01257         clist_init(e, next, prev);
01258         e->total_size=size;
01259         e->name_len=name->len;
01260         e->type=type;
01261         now=get_ticks_raw();
01262         e->last_used=now;
01263         memcpy(e->name, name->s, name->len); /* memset makes sure is 0-term. */
01264         e->rr_lst=(struct dns_rr*)((char*)e+
01265                                 ROUND_POINTER(sizeof(struct dns_hash_entry)+name->len-1+1));
01266         tail_rr=&(e->rr_lst);
01267         rr=e->rr_lst;
01268         max_ttl=0;
01269         /* copy the actual data */
01270         switch(type){
01271                 case T_A:
01272                         for(l=tmp_lst; l; l=l->next){
01273                                 ttl=FIX_TTL(l->ttl);
01274                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01275                                 max_ttl=MAX(max_ttl, ttl);
01276                                 rr->rdata=(void*)((char*)rr+sizeof(struct dns_rr));
01277                                 memcpy(rr->rdata, l->rdata, sizeof(struct a_rdata));
01278                                 rr->next=(void*)((char*)rr+ROUND_POINTER(sizeof(struct dns_rr)+
01279                                                         sizeof(struct a_rdata)));
01280                                 tail_rr=&(rr->next);
01281                                 rr=rr->next;
01282                         }
01283                         break;
01284                 case T_AAAA:
01285                         for(l=tmp_lst; l; l=l->next){
01286                                 ttl=FIX_TTL(l->ttl);
01287                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01288                                 max_ttl=MAX(max_ttl, ttl);
01289                                 rr->rdata=(void*)((char*)rr+sizeof(struct dns_rr));
01290                                 memcpy(rr->rdata, l->rdata, sizeof(struct aaaa_rdata));
01291                                 rr->next=(void*)((char*)rr+ROUND_POINTER(sizeof(struct dns_rr)+
01292                                                         sizeof(struct aaaa_rdata)));
01293                                 tail_rr=&(rr->next);
01294                                 rr=rr->next;
01295                         }
01296                         break;
01297                 case T_SRV:
01298                         for(l=tmp_lst; l; l=l->next){
01299                                 ttl=FIX_TTL(l->ttl);
01300                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01301                                 max_ttl=MAX(max_ttl, ttl);
01302                                 rr->rdata=(void*)((char*)rr+
01303                                                                 ROUND_SHORT(sizeof(struct dns_rr)));
01304                                 /* copy the whole srv_rdata block*/
01305                                 memcpy(rr->rdata, l->rdata,
01306                                                 SRV_RDATA_SIZE(*(struct srv_rdata*)l->rdata) );
01307                                 rr->next=(void*)((char*)rr+
01308                                                         ROUND_POINTER( ROUND_SHORT(sizeof(struct dns_rr))+
01309                                                                                 SRV_RDATA_SIZE(
01310                                                                                         *(struct srv_rdata*)l->rdata)));
01311                                 tail_rr=&(rr->next);
01312                                 rr=rr->next;
01313                         }
01314                         break;
01315                 case T_NAPTR:
01316                         for(l=tmp_lst; l; l=l->next){
01317                                 ttl=FIX_TTL(l->ttl);
01318                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01319                                 max_ttl=MAX(max_ttl, ttl);
01320                                 rr->rdata=(void*)((char*)rr+
01321                                                                 ROUND_POINTER(sizeof(struct dns_rr)));
01322                                 /* copy the whole naptr_rdata block*/
01323                                 memcpy(rr->rdata, l->rdata,
01324                                                 NAPTR_RDATA_SIZE(*(struct naptr_rdata*)l->rdata) );
01325                                 /* adjust the string pointer */
01326                                 ((struct naptr_rdata*)rr->rdata)->flags=
01327                                         translate_pointer((char*)rr->rdata, (char*)l->rdata,
01328                                                         (((struct naptr_rdata*)l->rdata)->flags));
01329                                 ((struct naptr_rdata*)rr->rdata)->services=
01330                                         translate_pointer((char*)rr->rdata, (char*)l->rdata,
01331                                                         (((struct naptr_rdata*)l->rdata)->services));
01332                                 ((struct naptr_rdata*)rr->rdata)->regexp=
01333                                         translate_pointer((char*)rr->rdata, (char*)l->rdata,
01334                                                         (((struct naptr_rdata*)l->rdata)->regexp));
01335                                 ((struct naptr_rdata*)rr->rdata)->repl=
01336                                         translate_pointer((char*)rr->rdata, (char*)l->rdata,
01337                                                         (((struct naptr_rdata*)l->rdata)->repl));
01338                                 rr->next=(void*)((char*)rr+
01339                                                         ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01340                                                                                 NAPTR_RDATA_SIZE(
01341                                                                                         *(struct naptr_rdata*)l->rdata)));
01342                                 tail_rr=&(rr->next);
01343                                 rr=rr->next;
01344                         }
01345                         break;
01346                 case T_CNAME:
01347                         for(l=tmp_lst; l; l=l->next){
01348                                 ttl=FIX_TTL(l->ttl);
01349                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01350                                 max_ttl=MAX(max_ttl, ttl);
01351                                 rr->rdata=(void*)((char*)rr+sizeof(struct dns_rr));
01352                                 memcpy(rr->rdata, l->rdata,
01353                                                         CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata));
01354                                 rr->next=(void*)((char*)rr+ROUND_POINTER(sizeof(struct dns_rr)+
01355                                                         CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata)));
01356                                 tail_rr=&(rr->next);
01357                                 rr=rr->next;
01358                         }
01359                         break;
01360                 case T_TXT:
01361                         for(l=tmp_lst; l; l=l->next){
01362                                 ttl=FIX_TTL(l->ttl);
01363                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01364                                 max_ttl=MAX(max_ttl, ttl);
01365                                 rr->rdata=(void*)((char*)rr+
01366                                                         ROUND_POINTER(sizeof(struct dns_rr)));
01367                                 memcpy(rr->rdata, l->rdata,
01368                                                         TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
01369                                 /* adjust the string pointers */
01370                                 for (i=0; i<((struct txt_rdata*)l->rdata)->cstr_no; i++){
01371                                         ((struct txt_rdata*)rr->rdata)->txt[i].cstr=
01372                                                 translate_pointer((char*)rr->rdata, (char*)l->rdata,
01373                                                                 ((struct txt_rdata*)l->rdata)->txt[i].cstr);
01374                                 }
01375                                 rr->next=(void*)((char*)rr+
01376                                                 ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01377                                                         TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata)));
01378                                 tail_rr=&(rr->next);
01379                                 rr=rr->next;
01380                         }
01381                         break;
01382                 case T_EBL:
01383                         for(l=tmp_lst; l; l=l->next){
01384                                 ttl=FIX_TTL(l->ttl);
01385                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01386                                 max_ttl=MAX(max_ttl, ttl);
01387                                 rr->rdata=(void*)((char*)rr+
01388                                                         ROUND_POINTER(sizeof(struct dns_rr)));
01389                                 memcpy(rr->rdata, l->rdata,
01390                                                         EBL_RDATA_SIZE(*(struct ebl_rdata*)l->rdata));
01391                                 /* adjust the string pointers */
01392                                 ((struct ebl_rdata*)rr->rdata)->separator=
01393                                         translate_pointer((char*)rr->rdata, (char*)l->rdata,
01394                                                                 ((struct ebl_rdata*)l->rdata)->separator);
01395                                 ((struct ebl_rdata*)rr->rdata)->separator=
01396                                                 translate_pointer((char*)rr->rdata, (char*)l->rdata,
01397                                                                 ((struct ebl_rdata*)l->rdata)->separator);
01398                                 ((struct ebl_rdata*)rr->rdata)->apex=
01399                                                 translate_pointer((char*)rr->rdata, (char*)l->rdata,
01400                                                                 ((struct ebl_rdata*)l->rdata)->apex);
01401                                 rr->next=(void*)((char*)rr+
01402                                                 ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01403                                                         EBL_RDATA_SIZE(*(struct ebl_rdata*)l->rdata)));
01404                                 tail_rr=&(rr->next);
01405                                 rr=rr->next;
01406                         }
01407                         break;
01408                 case T_PTR:
01409                         for(l=tmp_lst; l; l=l->next){
01410                                 ttl=FIX_TTL(l->ttl);
01411                                 rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01412                                 max_ttl=MAX(max_ttl, ttl);
01413                                 rr->rdata=(void*)((char*)rr+sizeof(struct dns_rr));
01414                                 memcpy(rr->rdata, l->rdata,
01415                                                         PTR_RDATA_SIZE(*(struct ptr_rdata*)l->rdata));
01416                                 rr->next=(void*)((char*)rr+ROUND_POINTER(sizeof(struct dns_rr)+
01417                                                         PTR_RDATA_SIZE(*(struct ptr_rdata*)l->rdata)));
01418                                 tail_rr=&(rr->next);
01419                                 rr=rr->next;
01420                         }
01421                         break;
01422                 default:
01423                         /* do nothing */
01424                         LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: create: type %d not "
01425                                                         "supported\n", type);
01426                                 ;
01427         }
01428         *tail_rr=0; /* terminate the list */
01429         e->expire=now+S_TO_TICKS(max_ttl);
01430         free_rdata_list(tmp_lst);
01431         return e;
01432 }
01433 
01434 
01435 
01436 /* structure used only inside dns_cache_mk_rd_entry2 to break
01437  *  the list of records into records of the same type */
01438 struct tmp_rec{
01439         struct rdata* rd;
01440         struct dns_hash_entry* e;
01441         struct dns_rr* rr;
01442         struct dns_rr** tail_rr;
01443         int max_ttl;
01444         int size;
01445 };
01446 
01447 
01448 
01449 /* create several dns hash entries from a list of rdata structs
01450  * returns 0 on error */
01451 inline static struct dns_hash_entry* dns_cache_mk_rd_entry2(struct rdata* rd)
01452 {
01453         struct rdata* l;
01454         ticks_t now;
01455         struct tmp_rec rec[MAX_DNS_RECORDS];
01456         int rec_idx[MAX_DNS_RECORDS];
01457         int r, i, j;
01458         int no_records; /* number of different records */
01459         unsigned int ttl;
01460 
01461 
01462         no_records=0;
01463         rec[0].e=0;
01464         /* everything is allocated in one block: dns_hash_entry + name +
01465          * + dns_rr + rdata_raw+ ....;  dns_rr must start at an aligned adress,
01466          * hence we need to round dns_hash_entry+name size to a sizeof(long)
01467          * multiple. If rdata type requires it, rdata_raw might need to be also
01468          * aligned.
01469          * Memory image:
01470          * struct dns_hash_entry  (e)
01471          * name (name_len+1 bytes)  (&e->name[0])
01472          * padding to multiple of sizeof(char*)
01473          * dns_rr1 (e->rr_lst)
01474          * possible padding: no padding for a_rdata or aaaa_rdata,
01475          *                   multipe of sizeof(short) for srv_rdata,
01476          *                   multiple of sizeof(long) for naptr_rdata and others
01477          * dns_rr1->rdata  (e->rr_lst->rdata)
01478          * padding to multipe of sizeof long
01479          * dns_rr2 (e->rr_lst->next)
01480          * ....
01481          *
01482          */
01483         /* compute size */
01484         for(l=rd, i=0; l && (i<MAX_DNS_RECORDS); l=l->next, i++){
01485                 for (r=0; r<no_records; r++){
01486                         if ((l->type==rec[r].rd->type) &&
01487                                         (l->name_len==rec[r].rd->name_len)
01488                                 && (strncasecmp(l->name, rec[r].rd->name, l->name_len)==0)){
01489                                 /* found */
01490                                 goto found;
01491                         }
01492                 }
01493                 /* not found, create new */
01494                 if (no_records<MAX_DNS_RECORDS){
01495                         rec[r].rd=l;
01496                         rec[r].e=0;
01497                         rec[r].size=ROUND_POINTER(sizeof(struct dns_hash_entry)+
01498                                                         rec[r].rd->name_len-1+1);
01499                         no_records++;
01500                 }else{
01501                         LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry2: too many records: %d\n",
01502                                                 no_records);
01503                         /* skip */
01504                         continue;
01505                 }
01506 found:
01507                 rec_idx[i]=r;
01508                 switch(l->type){
01509                         case T_A:
01510                                 /* no padding */
01511                                 rec[r].size+=ROUND_POINTER(sizeof(struct dns_rr)+
01512                                                                                 sizeof(struct a_rdata));
01513                                 break;
01514                         case T_AAAA:
01515                                 /* no padding */
01516                                 rec[r].size+=ROUND_POINTER(sizeof(struct dns_rr)+
01517                                                                                                 sizeof(struct aaaa_rdata));
01518                                 break;
01519                         case T_SRV:
01520                                 /* padding to short */
01521                                 rec[r].size+=ROUND_POINTER(ROUND_SHORT(sizeof(struct dns_rr))+
01522                                                                 SRV_RDATA_SIZE(*(struct srv_rdata*)l->rdata));
01523                                 break;
01524                         case T_NAPTR:
01525                                         /* padding to char* */
01526                                 rec[r].size+=ROUND_POINTER(ROUND_POINTER(
01527                                                                                                 sizeof(struct dns_rr))+
01528                                                         NAPTR_RDATA_SIZE(*(struct naptr_rdata*)l->rdata));
01529                                 break;
01530                         case T_CNAME:
01531                                         /* no padding */
01532                                 rec[r].size+=ROUND_POINTER(sizeof(struct dns_rr)+
01533                                                         CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata));
01534                                 break;
01535                         case T_TXT:
01536                                         /* padding to char* (because of txt[]->cstr)*/
01537                                 rec[r].size+=ROUND_POINTER(ROUND_POINTER(
01538                                                                                                 sizeof(struct dns_rr))+
01539                                                         TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
01540                                 break;
01541                         case T_EBL:
01542                                         /* padding to char* (because of char* pointers)*/
01543                                 rec[r].size+=ROUND_POINTER(ROUND_POINTER(
01544                                                                                                 sizeof(struct dns_rr))+
01545                                                         EBL_RDATA_SIZE(*(struct ebl_rdata*)l->rdata));
01546                                 break;
01547                         case T_PTR:
01548                                         /* no padding */
01549                                 rec[r].size+=ROUND_POINTER(sizeof(struct dns_rr)+
01550                                                         PTR_RDATA_SIZE(*(struct ptr_rdata*)l->rdata));
01551                                 break;
01552                         default:
01553                                 LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not "
01554                                                         "supported\n", l->type);
01555                 }
01556         }
01557 
01558         now=get_ticks_raw();
01559         /* alloc & init the entries */
01560         for (r=0; r<no_records; r++){
01561                 rec[r].e=shm_malloc(rec[r].size);
01562                 if (rec[r].e==0){
01563                         LOG(L_ERR, "ERROR: dns_cache_mk_rd_entry: out of memory\n");
01564                         goto error;
01565                 }
01566                 memset(rec[r].e, 0, rec[r].size); /* init with 0*/
01567                 rec[r].e->total_size=rec[r].size;
01568                 rec[r].e->name_len=rec[r].rd->name_len;
01569                 rec[r].e->type=rec[r].rd->type;
01570                 rec[r].e->last_used=now;
01571                 /* memset makes sure is 0-term. */
01572                 memcpy(rec[r].e->name, rec[r].rd->name, rec[r].rd->name_len);
01573                 rec[r].e->rr_lst=(struct dns_rr*)((char*)rec[r].e+
01574                                 ROUND_POINTER(sizeof(struct dns_hash_entry)+rec[r].e->name_len
01575                                                                  -1+1));
01576                 rec[r].tail_rr=&(rec[r].e->rr_lst);
01577                 rec[r].rr=rec[r].e->rr_lst;
01578                 rec[r].max_ttl=0;
01579                 /* link them in a list */
01580                 if (r==0){
01581                         clist_init(rec[r].e, next, prev);
01582                 }else{
01583                         clist_append(rec[0].e, rec[r].e, next, prev);
01584                 }
01585         }
01586         /* copy the actual data */
01587         for(l=rd, i=0; l && (i<MAX_DNS_RECORDS); l=l->next, i++){
01588                 r=rec_idx[i];
01589                 ttl=FIX_TTL(l->ttl);
01590                 switch(l->type){
01591                         case T_A:
01592                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01593                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01594                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01595                                                                         sizeof(struct dns_rr));
01596                                 memcpy(rec[r].rr->rdata, l->rdata, sizeof(struct a_rdata));
01597                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01598                                                                         ROUND_POINTER(sizeof(struct dns_rr)+
01599                                                                         sizeof(struct a_rdata)));
01600                                 rec[r].tail_rr=&(rec[r].rr->next);
01601                                 rec[r].rr=rec[r].rr->next;
01602                                 break;
01603                         case T_AAAA:
01604                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01605                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01606                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01607                                                                         sizeof(struct dns_rr));
01608                                 memcpy(rec[r].rr->rdata, l->rdata, sizeof(struct aaaa_rdata));
01609                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01610                                                                         ROUND_POINTER(sizeof(struct dns_rr)+
01611                                                                         sizeof(struct aaaa_rdata)));
01612                                 rec[r].tail_rr=&(rec[r].rr->next);
01613                                 rec[r].rr=rec[r].rr->next;
01614                                 break;
01615                         case T_SRV:
01616                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01617                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01618                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01619                                                                 ROUND_SHORT(sizeof(struct dns_rr)));
01620                                 /* copy the whole srv_rdata block*/
01621                                 memcpy(rec[r].rr->rdata, l->rdata,
01622                                                 SRV_RDATA_SIZE(*(struct srv_rdata*)l->rdata) );
01623                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01624                                                         ROUND_POINTER( ROUND_SHORT(sizeof(struct dns_rr))+
01625                                                                                 SRV_RDATA_SIZE(
01626                                                                                         *(struct srv_rdata*)l->rdata)));
01627                                 rec[r].tail_rr=&(rec[r].rr->next);
01628                                 rec[r].rr=rec[r].rr->next;
01629                                 break;
01630                         case T_NAPTR:
01631                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01632                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01633                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01634                                                                 ROUND_POINTER(sizeof(struct dns_rr)));
01635                                 /* copy the whole srv_rdata block*/
01636                                 memcpy(rec[r].rr->rdata, l->rdata,
01637                                                 NAPTR_RDATA_SIZE(*(struct naptr_rdata*)l->rdata) );
01638                                 /* adjust the string pointer */
01639                                 ((struct naptr_rdata*)rec[r].rr->rdata)->flags=
01640                                         translate_pointer((char*)rec[r].rr->rdata, (char*)l->rdata,
01641                                                         (((struct naptr_rdata*)l->rdata)->flags));
01642                                 ((struct naptr_rdata*)rec[r].rr->rdata)->services=
01643                                         translate_pointer((char*)rec[r].rr->rdata, (char*)l->rdata,
01644                                                         (((struct naptr_rdata*)l->rdata)->services));
01645                                 ((struct naptr_rdata*)rec[r].rr->rdata)->regexp=
01646                                         translate_pointer((char*)rec[r].rr->rdata, (char*)l->rdata,
01647                                                         (((struct naptr_rdata*)l->rdata)->regexp));
01648                                 ((struct naptr_rdata*)rec[r].rr->rdata)->repl=
01649                                         translate_pointer((char*)rec[r].rr->rdata, (char*)l->rdata,
01650                                                         (((struct naptr_rdata*)l->rdata)->repl));
01651                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01652                                                         ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01653                                                                                 NAPTR_RDATA_SIZE(
01654                                                                                         *(struct naptr_rdata*)l->rdata)));
01655                                 rec[r].tail_rr=&(rec[r].rr->next);
01656                                 rec[r].rr=rec[r].rr->next;
01657                                 break;
01658                         case T_CNAME:
01659                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01660                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01661                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr
01662                                                                         +sizeof(struct dns_rr));
01663                                 memcpy(rec[r].rr->rdata, l->rdata,
01664                                                         CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata));
01665                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01666                                                         ROUND_POINTER(sizeof(struct dns_rr)+
01667                                                         CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata)));
01668                                 rec[r].tail_rr=&(rec[r].rr->next);
01669                                 rec[r].rr=rec[r].rr->next;
01670                                 break;
01671                         case T_TXT:
01672                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01673                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01674                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01675                                                                         ROUND_POINTER(sizeof(struct dns_rr)));
01676                                 memcpy(rec[r].rr->rdata, l->rdata,
01677                                                         TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
01678                                 /* adjust the string pointers */
01679                                 for (j=0; j<((struct txt_rdata*)l->rdata)->cstr_no; j++){
01680                                         ((struct txt_rdata*)rec[r].rr->rdata)->txt[j].cstr=
01681                                                 translate_pointer((char*)rec[r].rr->rdata,
01682                                                                 (char*)l->rdata,
01683                                                                 ((struct txt_rdata*)l->rdata)->txt[j].cstr);
01684                                 }
01685                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01686                                                 ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01687                                                         TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata)));
01688                                 rec[r].tail_rr=&(rec[r].rr->next);
01689                                 rec[r].rr=rec[r].rr->next;
01690                                 break;
01691                         case T_EBL:
01692                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01693                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01694                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr+
01695                                                                         ROUND_POINTER(sizeof(struct dns_rr)));
01696                                 memcpy(rec[r].rr->rdata, l->rdata,
01697                                                         EBL_RDATA_SIZE(*(struct ebl_rdata*)l->rdata));
01698                                 /* adjust the string pointers */
01699                                 ((struct ebl_rdata*)rec[r].rr->rdata)->separator=
01700                                         translate_pointer((char*)rec[r].rr->rdata,
01701                                                         (char*)l->rdata,
01702                                                         ((struct ebl_rdata*)l->rdata)->separator);
01703                                 ((struct ebl_rdata*)rec[r].rr->rdata)->apex=
01704                                         translate_pointer((char*)rec[r].rr->rdata,
01705                                                         (char*)l->rdata,
01706                                                         ((struct ebl_rdata*)l->rdata)->apex);
01707                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01708                                                 ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
01709                                                         EBL_RDATA_SIZE(*(struct ebl_rdata*)l->rdata)));
01710                                 rec[r].tail_rr=&(rec[r].rr->next);
01711                                 rec[r].rr=rec[r].rr->next;
01712                                 break;
01713                         case T_PTR:
01714                                 rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
01715                                 rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
01716                                 rec[r].rr->rdata=(void*)((char*)rec[r].rr
01717                                                                         +sizeof(struct dns_rr));
01718                                 memcpy(rec[r].rr->rdata, l->rdata,
01719                                                         PTR_RDATA_SIZE(*(struct ptr_rdata*)l->rdata));
01720                                 rec[r].rr->next=(void*)((char*)rec[r].rr+
01721                                                         ROUND_POINTER(sizeof(struct dns_rr)+
01722                                                         PTR_RDATA_SIZE(*(struct ptr_rdata*)l->rdata)));
01723                                 rec[r].tail_rr=&(rec[r].rr->next);
01724                                 rec[r].rr=rec[r].rr->next;
01725                                 break;
01726                         default:
01727                                 /* do nothing */
01728                                 ;
01729                 }
01730         }
01731         for (r=0; r<no_records; r++){
01732                 *rec[r].tail_rr=0; /* terminate the list */
01733                 rec[r].e->expire=now+S_TO_TICKS(rec[r].max_ttl);
01734         }
01735         return rec[0].e;
01736 error:
01737         for (r=0; r<no_records; r++){
01738                 dns_destroy_entry(rec[r].e);
01739         }
01740         return 0;
01741 }
01742 
01743 
01744 
01745 inline static struct dns_hash_entry* dns_get_entry(str* name, int type);
01746 
01747 
01748 #define CACHE_RELEVANT_RECS_ONLY
01749 
01750 #ifdef CACHE_RELEVANT_RECS_ONLY
01751 /* internal only: gets related entries from a rdata list, appends them
01752  * to e (list) and returns:
01753  *  - e if e is of the requested type
01754  *  -  if e is a CNAME, tries to get to the end of the CNAME chain and returns
01755  *      the final entry if the types match or 0 if the chain is unfinished
01756  *  - 0 on error/not found
01757  * records is modified (the used records are removed from the list and freed)
01758  *
01759  * WARNING: - records must be pkg_malloc'ed
01760  * Notes:   - if the return is 0 and e->type==T_CNAME, the list will contain
01761  *            the CNAME chain (the last element being the last CNAME)
01762  *  */
01763 inline static struct dns_hash_entry* dns_get_related(struct dns_hash_entry* e,
01764                                                                                                                 int type,
01765                                                                                                                 struct rdata** records)
01766 {
01767         struct dns_hash_entry* ret;
01768         struct dns_hash_entry* l;
01769         struct dns_hash_entry* t;
01770         struct dns_hash_entry* lst_end;
01771         struct dns_rr* rr;
01772         static int cname_chain_len=0;
01773         str tmp;
01774 
01775         ret=0;
01776         l=e;
01777 #ifdef DNS_CACHE_DEBUG
01778         DBG("dns_get_related(%p (%.*s, %d), %d, *%p) (%d)\n", e,
01779                         e->name_len, e->name, e->type, type, *records, cname_chain_len);
01780 #endif
01781         clist_init(l, next, prev);
01782         if (type==e->type){
01783                 ret=e;
01784                 switch(e->type){
01785                         case T_SRV:
01786                                 for (rr=e->rr_lst; rr && *records; rr=rr->next){
01787                                         tmp.s=((struct srv_rdata*)rr->rdata)->name;
01788                                         tmp.len=((struct srv_rdata*)rr->rdata)->name_len;
01789                                         if (!(dns_flags&DNS_IPV6_ONLY)){
01790                                                 t=dns_cache_mk_rd_entry(&tmp, T_A, records);
01791                                                 if (t){
01792                                                         if ((t->type==T_CNAME) && *records)
01793                                                                 dns_get_related(t, T_A, records);
01794                                                         lst_end=t->prev; /* needed for clist_append*/
01795                                                         clist_append_sublist(l, t, lst_end, next, prev);
01796                                                 }
01797                                         }
01798                                         if (!(dns_flags&DNS_IPV4_ONLY)){
01799                                                 t=dns_cache_mk_rd_entry(&tmp, T_AAAA, records);
01800                                                 if (t){
01801                                                         if ((t->type==T_CNAME) && *records)
01802                                                                 dns_get_related(t, T_AAAA, records);
01803                                                         lst_end=t->prev; /* needed for clist_append*/
01804                                                         clist_append_sublist(l, t, lst_end, next, prev);
01805                                                 }
01806                                         }
01807                                 }
01808                                 break;
01809 #ifdef USE_NAPTR
01810                         case T_NAPTR:
01811 #ifdef NAPTR_CACHE_ALL_ARS
01812                                 if (*records)
01813                                                 dns_cache_mk_rd_entry2(*records);
01814 #else
01815                                 for (rr=e->rr_lst; rr && *records; rr=rr->next){
01816                                         if (naptr_get_sip_proto((struct naptr_rdata*)rr->rdata)>0){
01817                                                 tmp.s=((struct naptr_rdata*)rr->rdata)->repl;
01818                                                 tmp.len=((struct naptr_rdata*)rr->rdata)->repl_len;
01819                                                 t=dns_cache_mk_rd_entry(&tmp, T_SRV, records);
01820                                                 if (t){
01821                                                         if (*records)
01822                                                                 dns_get_related(t, T_SRV, records);
01823                                                         lst_end=t->prev; /* needed for clist_append*/
01824                                                         clist_append_sublist(l, t, lst_end, next, prev);
01825                                                 }
01826                                         }
01827                                 }
01828 #endif /* NAPTR_CACHE_ALL_ARS */
01829 #endif /* USE_NAPTR */
01830                                 break;
01831                         default:
01832                                 /* nothing extra */
01833                                 break;
01834                 }
01835         }else if ((e->type==T_CNAME) && (cname_chain_len<MAX_CNAME_CHAIN)){
01836                 /* only one cname is allowed (rfc2181), so we ignore
01837                  * the others (we take only the first one) */
01838                 tmp.s=((struct cname_rdata*)e->rr_lst->rdata)->name;
01839                 tmp.len=((struct cname_rdata*)e->rr_lst->rdata)->name_len;
01840                 t=dns_cache_mk_rd_entry(&tmp, type, records);
01841                 if (t){
01842                         if (*records){
01843                                 cname_chain_len++;
01844                                 ret=dns_get_related(t, type, records);
01845                                 cname_chain_len--;
01846                                 lst_end=t->prev;
01847                                 clist_append_sublist(l, t, lst_end, next, prev);
01848                         }else{
01849                                 /* if no more recs, but we found the orig. target anyway,
01850                                  *  return it (e.g. recs are only CNAME x & x A 1.2.3.4 or
01851                                  *  CNAME & SRV) */
01852                                 if (t->type==type)
01853                                         ret=t;
01854                                 clist_append(l, t, next, prev);
01855                         }
01856                 }
01857         }
01858         return ret;
01859 }
01860 #endif
01861 
01862 
01863 
01864 /* calls the external resolver and populates the cache with the result
01865  * returns: 0 on error, pointer to hash entry on success
01866  * WARNING: make sure you use dns_hash_entry_put() when you're
01867  *  finished with the result)
01868  * */
01869 inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
01870 {
01871         struct rdata* records;
01872         struct dns_hash_entry* e;
01873         struct dns_hash_entry* l;
01874         struct dns_hash_entry* r;
01875         struct dns_hash_entry* t;
01876         struct ip_addr* ip;
01877         str cname_val;
01878         char name_buf[MAX_DNS_NAME];
01879         struct dns_hash_entry* old;
01880         str rec_name;
01881         int add_record, h, err;
01882 
01883         e=0;
01884         l=0;
01885         cname_val.s=0;
01886         old = NULL;
01887 
01888 #ifdef USE_DNS_CACHE_STATS
01889         if (dns_cache_stats)
01890                 dns_cache_stats[process_no].dns_req_cnt++;
01891 #endif /* USE_DNS_CACHE_STATS */
01892 
01893         if (type==T_A){
01894                 if ((ip=str2ip(name))!=0){
01895                                 e=dns_cache_mk_ip_entry(name, ip);
01896                                 if (likely(e))
01897                                         atomic_set(&e->refcnt, 1);/* because we ret. a ref. to it*/
01898                                 goto end; /* we do not cache obvious stuff */
01899                 }
01900         }
01901 #ifdef USE_IPV6
01902         else if (type==T_AAAA){
01903                 if ((ip=str2ip6(name))!=0){
01904                                 e=dns_cache_mk_ip_entry(name, ip);
01905                                 if (likely(e))
01906                                         atomic_set(&e->refcnt, 1);/* because we ret. a ref. to it*/
01907                                 goto end;/* we do not cache obvious stuff */
01908                 }
01909         }
01910 #endif /* USE_IPV6 */
01911 #ifdef DNS_WATCHDOG_SUPPORT
01912         if (atomic_get(dns_servers_up)==0)
01913                 goto end; /* the servers are down, needless to perform the query */
01914 #endif
01915         if (name->len>=MAX_DNS_NAME){
01916                 LOG(L_ERR, "ERROR: dns_cache_do_request: name too long (%d chars)\n",
01917                                         name->len);
01918                 goto end;
01919         }
01920         /* null terminate the string, needed by get_record */
01921         memcpy(name_buf, name->s, name->len);
01922         name_buf[name->len]=0;
01923         records=get_record(name_buf, type, RES_AR);
01924         if (records){
01925 #ifdef CACHE_RELEVANT_RECS_ONLY
01926                 e=dns_cache_mk_rd_entry(name, type, &records);
01927                 if (likely(e)){
01928                         l=e;
01929                         e=dns_get_related(l, type, &records);
01930                         /* e should contain the searched entry (if found) and l
01931                          * all the entries (e and related) */
01932                         if (likely(e)){
01933                                 atomic_set(&e->refcnt, 1); /* 1 because we return a
01934                                                                                                 ref. to it */
01935                         }else{
01936                                 /* e==0 => l contains a  cname list => we use the last
01937                                  * cname from the chain for a new resolve attempt (l->prev) */
01938                                 /* only one cname record is allowed (rfc2181), so we ignore
01939                                  * the others (we take only the first one) */
01940                                 cname_val.s=
01941                                         ((struct cname_rdata*)l->prev->rr_lst->rdata)->name;
01942                                 cname_val.len=
01943                                         ((struct cname_rdata*)l->prev->rr_lst->rdata)->name_len;
01944                                 DBG("dns_cache_do_request: cname detected: %.*s (%d)\n",
01945                                                 cname_val.len, cname_val.s, cname_val.len);
01946                         }
01947                         /* add all the records to the hash */
01948                         l->prev->next=0; /* we break the double linked list for easier
01949                                                                 searching */
01950                         LOCK_DNS_HASH(); /* optimization */
01951                         for (r=l; r; r=t){
01952                                 t=r->next;
01953                                 /* add the new record to the cache by default */
01954                                 add_record = 1;
01955                                 if (cfg_get(core, core_cfg, dns_cache_rec_pref) > 0) {
01956                                         /* check whether there is an old record with the
01957                                          * same type in the cache */
01958                                         rec_name.s = r->name;
01959                                         rec_name.len = r->name_len;
01960                                         old = _dns_hash_find(&rec_name, r->type, &h, &err);
01961                                         if (old) {
01962                                                 if (old->type != r->type) {
01963                                                         /* probably CNAME found */
01964                                                         old = NULL;
01965 
01966                                                 } else if (old->ent_flags & DNS_FLAG_PERMANENT) {
01967                                                         /* never overwrite permanent entries */
01968                                                         add_record = 0;
01969 
01970                                                 } else if ((old->ent_flags & DNS_FLAG_BAD_NAME) == 0) {
01971                                                         /* Non-negative, non-permanent entry found with
01972                                                          * the same type. */
01973                                                         add_record =
01974                                                                 /* prefer new records */
01975                                                                 ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 2)
01976                                                                 /* prefer the record with the longer lifetime */
01977                                                                 || ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 3)
01978                                                                         && TICKS_LT(old->expire, r->expire)));
01979                                                 }
01980                                         }
01981                                 }
01982                                 if (add_record) {
01983                                         dns_cache_add_unsafe(r); /* refcnt++ inside */
01984                                         if (atomic_get(&r->refcnt)==0){
01985                                                 /* if cache adding failed and nobody else is interested
01986                                                  * destroy this entry */
01987                                                 dns_destroy_entry(r);
01988                                         }
01989                                         if (old) {
01990                                                 _dns_hash_remove(old);
01991                                                 old = NULL;
01992                                         }
01993                                 } else {
01994                                         if (old) {
01995                                                 if (r == e) {
01996                                                         /* this entry has to be returned */
01997                                                         e = old;
01998                                                         atomic_inc(&e->refcnt);
01999                                                 }
02000                                                 old = NULL;
02001                                         }
02002                                         dns_destroy_entry(r);
02003                                 }
02004                         }
02005                         UNLOCK_DNS_HASH();
02006                         /* if only cnames found => try to resolve the last one */
02007                         if (cname_val.s){
02008                                 DBG("dns_cache_do_request: dns_get_entry(cname: %.*s (%d))\n",
02009                                                 cname_val.len, cname_val.s, cname_val.len);
02010                                 e=dns_get_entry(&cname_val, type);
02011                         }
02012                 }
02013 #else
02014                 l=dns_cache_mk_rd_entry2(records);
02015 #endif
02016                 free_rdata_list(records);
02017         }else if (cfg_get(core, core_cfg, dns_neg_cache_ttl)){
02018                 e=dns_cache_mk_bad_entry(name, type, 
02019                                 cfg_get(core, core_cfg, dns_neg_cache_ttl), DNS_FLAG_BAD_NAME);
02020                 if (likely(e)) {
02021                         atomic_set(&e->refcnt, 1); /* 1 because we return a ref. to it */
02022                         dns_cache_add(e); /* refcnt++ inside*/
02023                 }
02024                 goto end;
02025         }
02026 #ifndef CACHE_RELEVANT_RECS_ONLY
02027         if (l){
02028                 /* add all the records to the cache, but return only the record
02029                  * we are looking for */
02030                 l->prev->next=0; /* we break the double linked list for easier
02031                                                         searching */
02032                 LOCK_DNS_HASH(); /* optimization */
02033                 for (r=l; r; r=t){
02034                         t=r->next;
02035                         if (e==0){ /* no entry found yet */
02036                                 if (r->type==T_CNAME){
02037                                         if ((r->name_len==name->len) && (r->rr_lst) &&
02038                                                         (strncasecmp(r->name, name->s, name->len)==0)){
02039                                                 /* update the name with the name from the cname rec. */
02040                                                 cname_val.s=
02041                                                                 ((struct cname_rdata*)r->rr_lst->rdata)->name;
02042                                                 cname_val.len=
02043                                                         ((struct cname_rdata*)r->rr_lst->rdata)->name_len;
02044                                                 name=&cname_val;
02045                                         }
02046                                 }else if ((r->type==type) && (r->name_len==name->len) &&
02047                                                         (strncasecmp(r->name, name->s, name->len)==0)){
02048                                         e=r;
02049                                         atomic_set(&e->refcnt, 1); /* 1 because we return a ref.
02050                                                                                                   to it */
02051                                 }
02052                         }
02053 
02054                         /* add the new record to the cache by default */
02055                         add_record = 1;
02056                         if (cfg_get(core, core_cfg, dns_cache_rec_pref) > 0) {
02057                                 /* check whether there is an old record with the
02058                                  * same type in the cache */
02059                                 rec_name.s = r->name;
02060                                 rec_name.len = r->name_len;
02061                                 old = _dns_hash_find(&rec_name, r->type, &h, &err);
02062                                 if (old) {
02063                                         if (old->type != r->type) {
02064                                                 /* probably CNAME found */
02065                                                 old = NULL;
02066 
02067                                         } else if (old->ent_flags & DNS_FLAG_PERMANENT) {
02068                                                 /* never overwrite permanent entries */
02069                                                 add_record = 0;
02070 
02071                                         } else if ((old->ent_flags & DNS_FLAG_BAD_NAME) == 0) {
02072                                                 /* Non-negative, non-permanent entry found with
02073                                                  * the same type. */
02074                                                 add_record =
02075                                                         /* prefer new records */
02076                                                         ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 2)
02077                                                         /* prefer the record with the longer lifetime */
02078                                                         || ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 3)
02079                                                                 && TICKS_LT(old->expire, r->expire)));
02080                                         }
02081                                 }
02082                         }
02083                         if (add_record) {
02084                                 dns_cache_add_unsafe(r); /* refcnt++ inside */
02085                                 if (atomic_get(&r->refcnt)==0){
02086                                         /* if cache adding failed and nobody else is interested
02087                                          * destroy this entry */
02088                                         dns_destroy_entry(r);
02089                                 }
02090                                 if (old) {
02091                                         _dns_hash_remove(old);
02092                                         old = NULL;
02093                                 }
02094                         } else {
02095                                 if (old) {
02096                                         if (r == e) {
02097                                                 /* this entry has to be returned */
02098                                                 e = old;
02099                                                 atomic_inc(&e->refcnt);
02100                                         }
02101                                         old = NULL;
02102                                 }
02103                                 dns_destroy_entry(r);
02104                         }
02105                 }
02106                 UNLOCK_DNS_HASH();
02107                 if ((e==0) && (cname_val.s)){ /* not found, but found a cname */
02108                         /* only one cname is allowed (rfc2181), so we ignore the
02109                          * others (we take only the first one) */
02110                         e=dns_get_entry(&cname_val, type);
02111                 }
02112         }
02113 #endif
02114 end:
02115         return e;
02116 }
02117 
02118 
02119 
02120 /* tries to lookup (name, type) in the hash and if not found tries to make
02121  *  a dns request
02122  *  return: 0 on error, pointer to a dns_hash_entry on success
02123  *  WARNING: when not needed anymore dns_hash_put() must be called! */
02124 inline static struct dns_hash_entry* dns_get_entry(str* name, int type)
02125 {
02126         int h;
02127         struct dns_hash_entry* e;
02128         str cname_val;
02129         int err;
02130         static int rec_cnt=0; /* recursion protection */
02131 
02132         e=0;
02133         if (rec_cnt>MAX_CNAME_CHAIN){
02134                 LOG(L_WARN, "WARNING: dns_get_entry: CNAME chain too long or"
02135                                 " recursive CNAMEs (\"%.*s\")\n", name->len, name->s);
02136                 goto error;
02137         }
02138         rec_cnt++;
02139         e=dns_hash_get(name, type, &h, &err);
02140 #ifdef USE_DNS_CACHE_STATS
02141         if (e) {
02142                 if ((e->ent_flags & DNS_FLAG_BAD_NAME) && dns_cache_stats)
02143                         /* negative DNS cache hit */
02144                         dns_cache_stats[process_no].dc_neg_hits_cnt++;
02145                 else if (((e->ent_flags & DNS_FLAG_BAD_NAME) == 0)
02146                                 && dns_cache_stats
02147                 ) /* DNS cache hit */
02148                         dns_cache_stats[process_no].dc_hits_cnt++;
02149 
02150                 if (dns_cache_stats)
02151                         dns_cache_stats[process_no].dns_req_cnt++;
02152         }
02153 #endif /* USE_DNS_CACHE_STATS */
02154 
02155         if ((e==0) && ((err) || ((e=dns_cache_do_request(name, type))==0))){
02156                 goto error;
02157         }else if ((e->type==T_CNAME) && (type!=T_CNAME)){
02158                 /* cname found instead which couldn't be resolved with the cached
02159                  * info => try a dns request */
02160                 /* only one cname record is allowed (rfc2181), so we ignore
02161                  * the others (we take only the first one) */
02162                 cname_val.s= ((struct cname_rdata*)e->rr_lst->rdata)->name;
02163                 cname_val.len=((struct cname_rdata*)e->rr_lst->rdata)->name_len;
02164                 dns_hash_put(e); /* not interested in the cname anymore */
02165                 if ((e=dns_cache_do_request(&cname_val, type))==0)
02166                         goto error; /* could not resolve cname */
02167         }
02168         /* found */
02169         if ((e->rr_lst==0) || (e->ent_flags & DNS_FLAG_BAD_NAME)){
02170                 /* negative cache => not resolvable */
02171                 dns_hash_put(e);
02172                 e=0;
02173         }
02174 error:
02175         rec_cnt--;
02176         return e;
02177 }
02178 
02179 
02180 
02181 /* gets the first non-expired record starting with record no
02182  * from the dns_hash_entry struct e
02183  * params:       e   - dns_hash_entry struct
02184  *               *no - it must contain the start record number (0 initially);
02185  *                      it will be filled with the returned record number
02186  *               now - current time/ticks value
02187  * returns pointer to the rr on success and sets no to the rr number
02188  *         0 on error and fills the error flags
02189         *
02190  * Example usage:
02191  * list all non-expired non-bad-marked ips for name:
02192  * e=dns_get_entry(name, T_A);
02193  * if (e){
02194  *    *no=0;
02195  *    now=get_ticks_raw();
02196  *    while(rr=dns_entry_get_rr(e, no, now){
02197  *       DBG("address %d\n", *no);
02198  *       *no++;  ( get the next address next time )
02199  *     }
02200  *  }
02201  */
02202 inline static struct dns_rr* dns_entry_get_rr(  struct dns_hash_entry* e,
02203                                                                                          unsigned char* no, ticks_t now)
02204 {
02205         struct dns_rr* rr;
02206         int n;
02207 #ifdef DNS_WATCHDOG_SUPPORT
02208         int servers_up;
02209 
02210         servers_up = atomic_get(dns_servers_up);
02211 #endif
02212 
02213         for(rr=e->rr_lst, n=0;rr && (n<*no);rr=rr->next, n++);/* skip *no records*/
02214         for(;rr;rr=rr->next){
02215                 if (
02216 #ifdef DNS_WATCHDOG_SUPPORT
02217                         /* check the expiration time only when the servers are up */
02218                         servers_up &&
02219 #endif
02220                         ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
02221                         ((s_ticks_t)(now-rr->expire)>=0) /* expired rr */
02222                 )
02223                         continue;
02224                 /* everything is ok now */
02225                 *no=n;
02226                 return rr;
02227         }
02228         *no=n;
02229         return 0;
02230 }
02231 
02232 
02233 #ifdef DNS_SRV_LB
02234 
02235 #define srv_reset_tried(p)      (*(p)=0)
02236 #define srv_marked(p, i)        (*(p)&(1UL<<(i)))
02237 #define srv_mark_tried(p, i)    \
02238         do{ \
02239                 (*(p)|=(1UL<<(i))); \
02240         }while(0)
02241 
02242 #define srv_next_rr(n, f, i) srv_mark_tried(f, i)
02243 
02244 /* returns a random number between 0 and max inclusive (0<=r<=max) */
02245 inline static unsigned dns_srv_random(unsigned max)
02246 {
02247         return fastrand_max(max);
02248 }
02249 
02250 /* for a SRV record it will return the next entry to be tried according
02251  * to the RFC2782 server selection mechanism
02252  * params:
02253  *    e     is a dns srv hash entry
02254  *    no    is the start index of the current group (a group is a set of SRV
02255  *          rrs with the same priority)
02256  *    tried is a bitmap where the tried srv rrs of the same priority are
02257  *          marked
02258  *    now - current time/ticks value
02259  * returns pointer to the rr on success and sets no to the rr number
02260  *         0 on error and fills the error flags
02261  * WARNING: unlike dns_entry_get_rr() this will always return another
02262  *           another rr automatically (*no must not be incremented)
02263  *
02264  * Example usage:
02265  * list all non-expired, non-bad-marked, never tried before srv records
02266  * using the rfc2782 algo:
02267  * e=dns_get_entry(name, T_SRV);
02268  * if (e){
02269  *    no=0;
02270  *    srv_reset_tried(&tried);
02271  *    now=get_ticks_raw();
02272  *    while(rr=dns_srv_get_nxt_rr(e, &tried, &no, now){
02273  *       DBG("address %d\n", *no);
02274  *     }
02275  *  }
02276  *
02277  */
02278 inline static struct dns_rr* dns_srv_get_nxt_rr(struct dns_hash_entry* e,
02279                                                                                          srv_flags_t* tried,
02280                                                                                          unsigned char* no, ticks_t now)
02281 {
02282 #define MAX_SRV_GRP_IDX         (sizeof(srv_flags_t)*8)
02283         struct dns_rr* rr;
02284         struct dns_rr* start_grp;
02285         int n;
02286         unsigned sum;
02287         unsigned prio;
02288         unsigned rand_w;
02289         int found;
02290         int saved_idx;
02291         int zero_weight; /* number of records with 0 weight */
02292         int i, idx;
02293         struct r_sums_entry{
02294                         unsigned r_sum;
02295                         struct dns_rr* rr;
02296                         }r_sums[MAX_SRV_GRP_IDX];
02297 #ifdef DNS_WATCHDOG_SUPPORT
02298         int servers_up;
02299 
02300         servers_up = atomic_get(dns_servers_up);
02301 #endif
02302 
02303         rand_w=0;
02304         for(rr=e->rr_lst, n=0;rr && (n<*no);rr=rr->next, n++);/* skip *no records*/
02305 
02306 retry:
02307         if (unlikely(rr==0))
02308                 goto no_more_rrs;
02309         start_grp=rr;
02310         prio=((struct srv_rdata*)start_grp->rdata)->priority;
02311         sum=0;
02312         saved_idx=-1;
02313         zero_weight = 0;
02314         found=0;
02315         for (idx=0;rr && (prio==((struct srv_rdata*)rr->rdata)->priority) &&
02316                                                 (idx < MAX_SRV_GRP_IDX); idx++, rr=rr->next){
02317                 if ((
02318 #ifdef DNS_WATCHDOG_SUPPORT
02319                         /* check the expiration time only when the servers are up */
02320                         servers_up &&
02321 #endif
02322                         ((e->ent_flags & DNS_FLAG_PERMANENT) == 0) &&
02323                         ((s_ticks_t)(now-rr->expire)>=0) /* expired entry */) ||
02324                                 (srv_marked(tried, idx)) ) /* already tried */{
02325                         r_sums[idx].r_sum=0; /* 0 sum, to skip over it */
02326                         r_sums[idx].rr=0;    /* debug: mark it as unused */
02327                         continue;
02328                 }
02329                 /* special case, 0 weight records should be "first":
02330                  * remember the first rr int the "virtual" list: A 0 weight must
02331                  *  come first if present, else get the first one */
02332                 if ((saved_idx==-1) || (((struct srv_rdata*)rr->rdata)->weight==0)){
02333                         saved_idx=idx;
02334                 }
02335                 zero_weight += (((struct srv_rdata*)rr->rdata)->weight == 0);
02336                 sum+=((struct srv_rdata*)rr->rdata)->weight;
02337                 r_sums[idx].r_sum=sum;
02338                 r_sums[idx].rr=rr;
02339                 found++;
02340         }
02341         if (found==0){
02342                 /* try in the next priority group */
02343                 n+=idx; /* next group start idx, last rr */
02344                 srv_reset_tried(tried);
02345                 goto retry;
02346         }else if ((found==1) || (sum==0) ||
02347                                 (((rand_w=(dns_srv_random(sum-1)+1))==1) && zero_weight &&
02348                                         (dns_srv_random(DNS_SRV_ZERO_W_CHANCE)==0))){
02349                 /* 1. if only one found, avoid a useless random() call
02350                       and select it (saved_idx will point to it).
02351                  * 2. if the sum of weights is 0 (all have 0 weight) or
02352                  * 3. rand_w==1 and there are records with 0 weight and
02353                  *    random(probab. of selecting a 0-weight)
02354                  *     immediately select a 0 weight record.
02355                  *  (this takes care of the 0-weight at the beginning requirement) */
02356                 i=saved_idx; /* saved idx contains either first 0 weight or first
02357                                                 valid record */
02358                 goto found;
02359         }
02360         /* if we are here => rand_w is not 0 and we have at least 2 valid options
02361          * => we can safely iterate on the whole r_sums[] whithout any other
02362          * extra checks */
02363         for (i=0; (i<idx) && (r_sums[i].r_sum<rand_w); i++);
02364 found:
02365 #ifdef DNS_CACHE_DEBUG
02366         DBG("dns_srv_get_nxt_rr(%p, %lx, %d, %u): selected %d/%d in grp. %d"
02367                         " (rand_w=%d, rr=%p p=%d w=%d rsum=%d)\n",
02368                 e, (unsigned long)*tried, *no, now, i, idx, n, rand_w, r_sums[i].rr,
02369                 ((struct srv_rdata*)r_sums[i].rr->rdata)->priority,
02370                 ((struct srv_rdata*)r_sums[i].rr->rdata)->weight, r_sums[i].r_sum);
02371 #endif
02372         /* i is the winner */
02373         *no=n; /* grp. start */
02374         srv_mark_tried(tried, i); /* mark it */
02375         return r_sums[i].rr;
02376 no_more_rrs:
02377         *no=n;
02378         return 0;
02379 }
02380 #endif /* DNS_SRV_LB */
02381 
02382 
02383 
02384 /* gethostbyname compatibility: converts a dns_hash_entry structure
02385  * to a statical internal hostent structure
02386  * returns a pointer to the internal hostent structure on success or
02387  *          0 on error
02388  */
02389 inline static struct hostent* dns_entry2he(struct dns_hash_entry* e)
02390 {
02391         static struct hostent he;
02392         static char hostname[256];
02393         static char* p_aliases[1];
02394         static char* p_addr[DNS_HE_MAX_ADDR+1];
02395         static char address[16*DNS_HE_MAX_ADDR]; /* max 10 ipv6 addresses */
02396         int af, len;
02397         struct dns_rr* rr;
02398         unsigned char rr_no;
02399         ticks_t now;
02400         int i;
02401 
02402         switch(e->type){
02403                 case T_A:
02404                         af=AF_INET;
02405                         len=4;
02406                         break;
02407                 case T_AAAA:
02408 #ifdef USE_IPV6
02409                         af=AF_INET6;
02410                         len=16;
02411                         break;
02412 #else /* USE_IPV6 */
02413                         LOG(L_ERR, "ERROR: dns_entry2he: IPv6 dns cache entry, but "
02414                                                 "IPv6 support disabled at compile time"
02415                                                 " (recompile with -DUSE_IPV6)\n");
02416                         return 0;
02417 #endif /* USE_IPV6 */
02418                 default:
02419                         LOG(L_CRIT, "BUG: dns_entry2he: wrong entry type %d for %.*s\n",
02420                                         e->type, e->name_len, e->name);
02421                         return 0;
02422         }
02423 
02424 
02425         rr_no=0;
02426         now=get_ticks_raw();
02427         /* if the entry has already expired use the time at the end of lifetime */
02428         if (unlikely((s_ticks_t)(now-e->expire)>=0)) now=e->expire-1;
02429         rr=dns_entry_get_rr(e, &rr_no, now);
02430         for(i=0; rr && (i<DNS_HE_MAX_ADDR); i++,
02431                                                         rr=dns_entry_get_rr(e, &rr_no, now)){
02432                                 p_addr[i]=&address[i*len];
02433                                 memcpy(p_addr[i], ((struct a_rdata*)rr->rdata)->ip, len);
02434         }
02435         if (i==0){
02436                 DBG("DEBUG: dns_entry2he: no good records found (%d) for %.*s (%d)\n",
02437                                 rr_no, e->name_len, e->name, e->type);
02438                 return 0; /* no good record found */
02439         }
02440 
02441         p_addr[i]=0; /* mark the end of the addresses */
02442         p_aliases[0]=0; /* no aliases */
02443         memcpy(hostname, e->name, e->name_len);
02444         hostname[e->name_len]=0;
02445 
02446         he.h_addrtype=af;
02447         he.h_length=len;
02448         he.h_addr_list=p_addr;
02449         he.h_aliases=p_aliases;
02450         he.h_name=hostname;
02451 
02452         return &he;
02453 }
02454 
02455 
02456 
02457 /* gethostbyname compatibility: performs an a_lookup and returns a pointer
02458  * to a statical internal hostent structure
02459  * returns 0 on success, <0 on error (see the error codes)
02460  */
02461 inline static struct hostent* dns_a_get_he(str* name)
02462 {
02463         struct dns_hash_entry* e;
02464         struct ip_addr* ip;
02465         struct hostent* he;
02466 
02467         e=0;
02468         if ((ip=str2ip(name))!=0){
02469                 return ip_addr2he(name, ip);
02470         }
02471         if ((e=dns_get_entry(name, T_A))==0)
02472                 return 0;
02473         /* found */
02474         he=dns_entry2he(e);
02475         dns_hash_put(e);
02476         return he;
02477 }
02478 
02479 
02480 #ifdef USE_IPV6
02481 /* gethostbyname compatibility: performs an aaaa_lookup and returns a pointer
02482  * to a statical internal hostent structure
02483  * returns 0 on success, <0 on error (see the error codes)
02484  */
02485 inline static struct hostent* dns_aaaa_get_he(str* name)
02486 {
02487         struct dns_hash_entry* e;
02488         struct ip_addr* ip;
02489         struct hostent* he;
02490 
02491         e=0;
02492         if ((ip=str2ip6(name))!=0){
02493                 return ip_addr2he(name, ip);
02494         }
02495         if ((e=dns_get_entry(name, T_AAAA))==0)
02496                         return 0;
02497         /* found */
02498         he=dns_entry2he(e);
02499         dns_hash_put(e);
02500         return he;
02501 }
02502 #endif
02503 
02504 
02505 
02506 /* returns 0 on success, -1 on error (rr type does not contain an ip) */
02507 inline static int dns_rr2ip(int type, struct dns_rr* rr, struct ip_addr* ip)
02508 {
02509         switch(type){
02510                 case T_A:
02511                         ip->af=AF_INET;
02512                         ip->len=4;
02513                         memcpy(ip->u.addr, ((struct a_rdata*)rr->rdata)->ip, 4);
02514                         return 0;
02515                         break;
02516                 case T_AAAA:
02517 #ifdef USE_IPV6
02518                         ip->af=AF_INET6;
02519                         ip->len=16;
02520                         memcpy(ip->u.addr, ((struct aaaa_rdata*)rr->rdata)->ip6, 16);
02521                         return 0;
02522 #else /* USE_IPV6 */
02523                         LOG(L_ERR, "ERROR: dns_rr2ip: IPv6 dns rr, but IPv6 support"
02524                                            "disabled at compile time (recompile with "
02525                                            "-DUSE_IPV6)\n" );
02526 #endif /*USE_IPV6 */
02527                         break;
02528         }
02529         return -1;
02530 }
02531 
02532 
02533 
02534 /* gethostbyname compatibility:
02535  * performs an a or aaaa dns lookup, returns 0 on error and a pointer to a
02536  *          static hostent structure on success
02537  *  flags:  - none set: tries first an a_lookup and if it fails an aaaa_lookup
02538  *          - DNS_IPV6_FIRST: tries first an aaaa_lookup and then an a_lookup
02539  *          - DNS_IPV4_ONLY: tries only an a_lookup
02540  *          - DNS_IPV6_ONLY: tries only an aaaa_lookup
02541  */
02542 struct hostent* dns_get_he(str* name, int flags)
02543 {
02544 #ifdef USE_IPV6
02545         struct hostent* he;
02546 
02547         if ((flags&(DNS_IPV6_FIRST|DNS_IPV6_ONLY))){
02548                 he=dns_aaaa_get_he(name);
02549                 if (he) return he;
02550         }else{
02551                 he=dns_a_get_he(name);
02552                 if (he) return he;
02553         }
02554         if (flags&DNS_IPV6_FIRST){
02555                 he=dns_a_get_he(name);
02556         }else if (!(flags&(DNS_IPV6_ONLY|DNS_IPV4_ONLY))){
02557                 he=dns_aaaa_get_he(name);
02558         }
02559         return he;
02560 #else /* USE_IPV6 */
02561         return dns_a_get_he(name);
02562 #endif /* USE_IPV6 */
02563 }
02564 
02565 
02566 
02567 /* sip_resolvehost helper: gets the first good  hostent/port combination
02568  * returns 0 on error, pointer to static hostent structure on success
02569  *           (and sets port)*/
02570 struct hostent* dns_srv_get_he(str* name, unsigned short* port, int flags)
02571 {
02572         struct dns_hash_entry* e;
02573         struct dns_rr* rr;
02574         str rr_name;
02575         struct hostent* he;
02576         ticks_t now;
02577         unsigned char rr_no;
02578 
02579         rr=0;
02580         he=0;
02581         now=get_ticks_raw();
02582         if ((e=dns_get_entry(name, T_SRV))==0)
02583                         goto error;
02584         /* look inside the RRs for a good one (not expired or marked bad)  */
02585         rr_no=0;
02586         while( (rr=dns_entry_get_rr(e, &rr_no, now))!=0){
02587                 /* everything is ok now, we can try to resolve the ip */
02588                 rr_name.s=((struct srv_rdata*)rr->rdata)->name;
02589                 rr_name.len=((struct srv_rdata*)rr->rdata)->name_len;
02590                 if ((he=dns_get_he(&rr_name, flags))!=0){
02591                                 /* success, at least one good ip found */
02592                                 *port=((struct srv_rdata*)rr->rdata)->port;
02593                                 goto end;
02594                 }
02595                 rr_no++; /* try from the next record, the current one was not good */
02596         }
02597         /* if we reach this point => error, we couldn't find any good rr */
02598 end:
02599         if (e) dns_hash_put(e);
02600 error:
02601         return he;
02602 }
02603 
02604 
02605 
02606 struct hostent* dns_resolvehost(char* name)
02607 {
02608         str host;
02609         struct hostent* ret;
02610         if ((cfg_get(core, core_cfg, use_dns_cache)==0) || (dns_hash==0)){ /* not init yet */
02611                 ret =  _resolvehost(name);
02612                 if(unlikely(!ret)){
02613                         /* increment dns error counter */
02614                         counter_inc(dns_cnts_h.failed_dns_req);
02615                 }
02616                 return ret;
02617         }
02618         host.s=name;
02619         host.len=strlen(name);
02620         return dns_get_he(&host, dns_flags);
02621 }
02622 
02623 
02624 
02625 
02626 #if 0
02627 /* resolves a host name trying  NAPTR,  SRV, A & AAAA lookups, for details
02628  *  see dns_sip_resolve()
02629  *  FIXME: this version will return only the first ip
02630  * returns: hostent struct & *port filled with the port from the SRV record;
02631  *  0 on error
02632  */
02633 struct hostent* dns_sip_resolvehost(str* name, unsigned short* port,
02634                                                                                 char* proto)
02635 {
02636         struct dns_srv_handle h;
02637         struct ip_addr ip;
02638         int ret;
02639 
02640         if ((cfg_get(core, core_cfg, use_dns_cache==0)) || (dns_hash==0)){
02641                 /* not init or off => use normal, non-cached version */
02642                 return _sip_resolvehost(name, port, proto);
02643         }
02644         dns_srv_handle_init(&h);
02645         ret=dns_sip_resolve(&h, name, &ip, port, proto, dns_flags);
02646         dns_srv_handle_put(&h);
02647         if (ret>=0)
02648                 return ip_addr2he(name, &ip);
02649         return 0;
02650 }
02651 #endif
02652 
02653 
02654 
02655 /* resolves a host name trying SRV lookup if *port==0 or normal A/AAAA lookup
02656  * if *port!=0.
02657  * when performing SRV lookup (*port==0) it will use proto to look for
02658  * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
02659  * returns: hostent struct & *port filled with the port from the SRV record;
02660  *  0 on error
02661  */
02662 struct hostent* dns_srv_sip_resolvehost(str* name, unsigned short* port,
02663                                                                                 char* proto)
02664 {
02665         struct hostent* he;
02666         struct ip_addr* ip;
02667         static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */
02668         int len;
02669         str srv_name;
02670         char srv_proto;
02671 
02672         if ((cfg_get(core, core_cfg, use_dns_cache)==0) || (dns_hash==0)){
02673                 /* not init or off => use normal, non-cached version */
02674                 return _sip_resolvehost(name, port, proto);
02675         }
02676         len=0;
02677         if (proto){ /* makes sure we have a protocol set*/
02678                 if (*proto==0)
02679                         *proto=srv_proto=PROTO_UDP; /* default */
02680                 else
02681                         srv_proto=*proto;
02682         }else{
02683                 srv_proto=PROTO_UDP;
02684         }
02685         /* try SRV if no port specified (draft-ietf-sip-srv-06) */
02686         if ((port)&&(*port==0)){
02687                 *port=(srv_proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we
02688                                                                                                                  don't find another */
02689                 if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){
02690                         LOG(L_WARN, "WARNING: dns_sip_resolvehost: domain name too long"
02691                                                 " (%d), unable to perform SRV lookup\n", name->len);
02692                 }else{
02693                         /* check if it's an ip address */
02694                         if ( ((ip=str2ip(name))!=0)
02695 #ifdef  USE_IPV6
02696                                   || ((ip=str2ip6(name))!=0)
02697 #endif
02698                                 ){
02699                                 /* we are lucky, this is an ip address */
02700                                 return ip_addr2he(name,ip);
02701                         }
02702 
02703                         switch(srv_proto){
02704                                 case PROTO_NONE: /* no proto specified, use udp */
02705                                         if (proto)
02706                                                 *proto=PROTO_UDP;
02707                                         /* no break */
02708                                 case PROTO_UDP:
02709                                         memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
02710                                         memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
02711                                         tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
02712                                         len=SRV_UDP_PREFIX_LEN + name->len;
02713                                         break;
02714                                 case PROTO_TCP:
02715                                         memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
02716                                         memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
02717                                         tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
02718                                         len=SRV_TCP_PREFIX_LEN + name->len;
02719                                         break;
02720                                 case PROTO_TLS:
02721                                         memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
02722                                         memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
02723                                         tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
02724                                         len=SRV_TLS_PREFIX_LEN + name->len;
02725                                         break;
02726                                 case PROTO_SCTP:
02727                                         memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
02728                                         memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len);
02729                                         tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
02730                                         len=SRV_SCTP_PREFIX_LEN + name->len;
02731                                         break;
02732                                 default:
02733                                         LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n",
02734                                                         (int)srv_proto);
02735                                         return 0;
02736                         }
02737 
02738                         srv_name.s=tmp;
02739                         srv_name.len=len;
02740                         if ((he=dns_srv_get_he(&srv_name, port, dns_flags))!=0)
02741                                 return he;
02742                 }
02743         }
02744 /*skip_srv:*/
02745         if (name->len >= MAX_DNS_NAME) {
02746                 LOG(L_ERR, "dns_sip_resolvehost: domain name too long\n");
02747                 return 0;
02748         }
02749         he=dns_get_he(name, dns_flags);
02750         return he;
02751 }
02752 
02753 
02754 
02755 #ifdef USE_NAPTR
02756 /* iterates over a naptr rr list, returning each time a "good" naptr record
02757  * is found.( srv type, no regex and a supported protocol)
02758  * params:
02759  *         naptr_head - naptr dns_rr list head
02760  *         tried      - bitmap used to keep track of the already tried records
02761  *                      (no more then sizeof(tried)*8 valid records are
02762  *                      ever walked
02763  *         srv_name   - if succesfull, it will be set to the selected record
02764  *                      srv name (naptr repl.)
02765  *         proto      - if succesfull it will be set to the selected record
02766  *                      protocol
02767  * returns  0 if no more records found or a pointer to the selected record
02768  *  and sets  protocol and srv_name
02769  * WARNING: when calling first time make sure you run first
02770  *           naptr_iterate_init(&tried)
02771  */
02772 struct naptr_rdata* dns_naptr_sip_iterate(struct dns_rr* naptr_head,
02773                                                                                         naptr_bmp_t* tried,
02774                                                                                         str* srv_name, char* proto)
02775 {
02776         int i, idx;
02777         struct dns_rr* l;
02778         struct naptr_rdata* naptr;
02779         struct naptr_rdata* naptr_saved;
02780         char saved_proto;
02781         char naptr_proto;
02782 
02783         idx=0;
02784         naptr_proto=PROTO_NONE;
02785         naptr_saved=0;
02786         saved_proto=0;
02787         i=0;
02788         for(l=naptr_head; l && (i<MAX_NAPTR_RRS); l=l->next){
02789                 naptr=(struct naptr_rdata*) l->rdata;
02790                 if (naptr==0){
02791                                 LOG(L_CRIT, "naptr_iterate: BUG: null rdata\n");
02792                         goto end;
02793                 }
02794                 /* check if valid and get proto */
02795                 if ((naptr_proto=naptr_get_sip_proto(naptr))<=0) continue;
02796                 if (*tried& (1<<i)){
02797                         i++;
02798                         continue; /* already tried */
02799                 }
02800 #ifdef DNS_CACHE_DEBUG
02801                 DBG("naptr_iterate: found a valid sip NAPTR rr %.*s,"
02802                                         " proto %d\n", naptr->repl_len, naptr->repl,
02803                                         (int)naptr_proto);
02804 #endif
02805                 if ((naptr_proto_supported(naptr_proto))){
02806                         if (naptr_choose(&naptr_saved, &saved_proto,
02807                                                                 naptr, naptr_proto))
02808                                 idx=i;
02809                         }
02810                 i++;
02811         }
02812         if (naptr_saved){
02813                 /* found something */
02814 #ifdef DNS_CACHE_DEBUG
02815                 DBG("naptr_iterate: choosed NAPTR rr %.*s, proto %d"
02816                                         " tried: 0x%x\n", naptr_saved->repl_len,
02817                                         naptr_saved->repl, (int)saved_proto, *tried);
02818 #endif
02819                 *tried|=1<<idx;
02820                 *proto=saved_proto;
02821                 srv_name->s=naptr_saved->repl;
02822                 srv_name->len=naptr_saved->repl_len;
02823                 return naptr_saved;
02824         }
02825 end:
02826         return 0;
02827 }
02828 
02829 
02830 
02831 /* resolves a host name trying NAPTR lookup if *proto==0 and *port==0, SRV
02832  * lookup if *port==0 or normal A/AAAA lookup
02833  * if *port!=0.
02834  * when performing SRV lookup (*port==0) it will use proto to look for
02835  * tcp or udp hosts; if proto==0 => no SRV lookup
02836  * returns: hostent struct & *port filled with the port from the SRV record;
02837  *  0 on error
02838  */
02839 struct hostent* dns_naptr_sip_resolvehost(str* name, unsigned short* port,
02840                                                                                 char* proto)
02841 {
02842         struct hostent* he;
02843         struct ip_addr* tmp_ip;
02844         naptr_bmp_t tried_bmp;
02845         struct dns_hash_entry* e;
02846         char n_proto;
02847         str srv_name;
02848 
02849         he=0;
02850         if (dns_hash==0){ /* not init => use normal, non-cached version */
02851                 LOG(L_WARN, "WARNING: dns_sip_resolvehost: called before dns cache"
02852                                         " initialization\n");
02853                 return _sip_resolvehost(name, port, proto);
02854         }
02855         if (proto && port && (*proto==0) && (*port==0)){
02856                 *proto=PROTO_UDP; /* just in case we don't find another */
02857                 /* check if it's an ip address */
02858                 if ( ((tmp_ip=str2ip(name))!=0)
02859 #ifdef  USE_IPV6
02860                           || ((tmp_ip=str2ip6(name))!=0)
02861 #endif
02862                         ){
02863                         /* we are lucky, this is an ip address */
02864 #ifdef  USE_IPV6
02865                         if (((dns_flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
02866                                 ((dns_flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
02867                                 return 0;
02868                         }
02869 #endif
02870                         *port=SIP_PORT;
02871                         return ip_addr2he(name, tmp_ip);
02872                 }
02873                 /* do naptr lookup */
02874                 if ((e=dns_get_entry(name, T_NAPTR))==0)
02875                         goto naptr_not_found;
02876                 naptr_iterate_init(&tried_bmp);
02877                 while(dns_naptr_sip_iterate(e->rr_lst, &tried_bmp,
02878                                                                                                 &srv_name, &n_proto)){
02879                         if ((he=dns_srv_get_he(&srv_name, port, dns_flags))!=0){
02880 #ifdef DNS_CACHE_DEBUG
02881                                 DBG("dns_naptr_sip_resolvehost(%.*s, %d, %d) srv, ret=%p\n",
02882                                                         name->len, name->s, (int)*port, (int)*proto, he);
02883 #endif
02884                                 dns_hash_put(e);
02885                                 *proto=n_proto;
02886                                 return he;
02887                         }
02888                 }
02889                 /* no acceptable naptr record found, fallback to srv */
02890                 dns_hash_put(e);
02891         }
02892 naptr_not_found:
02893         return dns_srv_sip_resolvehost(name, port, proto);
02894 }
02895 #endif /* USE_NAPTR */
02896 
02897 
02898 
02899 /* resolves a host name trying NAPTR lookup if *proto==0 and *port==0, SRV
02900  * lookup if *port==0 or normal A/AAAA lookup
02901  * if *port!=0.
02902  * when performing SRV lookup (*port==0) it will use proto to look for
02903  * tcp or udp hosts; if proto==0 => no SRV lookup
02904  * returns: hostent struct & *port filled with the port from the SRV record;
02905  *  0 on error
02906  */
02907 struct hostent* dns_sip_resolvehost(str* name, unsigned short* port,
02908                                                                                 char* proto)
02909 {
02910 #ifdef USE_NAPTR
02911         if (dns_flags&DNS_TRY_NAPTR)
02912                 return dns_naptr_sip_resolvehost(name, port, proto);
02913 #endif
02914         return dns_srv_sip_resolvehost(name, port, proto);
02915 }
02916 
02917 
02918 
02919 /* performs an a lookup, fills the dns_entry pointer and the ip addr.
02920  *  (with the first good ip). if *e ==0 does the a lookup, and changes it
02921  *   to the result, if not it uses the current value and tries to use
02922  *   the rr_no record from it.
02923  * params:  e - must contain the "in-use" dns_hash_entry pointer (from
02924  *               a previous call) or *e==0 (for the first call)
02925  *          name - host name for which we do the lookup (required only
02926  *                  when *e==0)
02927  *          ip   - will be filled with the first good resolved ip started
02928  *                 at *rr_no
02929  *          rr_no - record number to start searching for a good ip from
02930  *                  (e.g. value from previous call + 1), filled on return
02931  *                  with the number of the record corresponding to the
02932  *                  returned ip
02933  * returns 0 on success, <0 on error (see the error codes),
02934  *         fills e, ip and rr_no
02935  *          On end of records (when used to iterate on all the ips) it
02936  *          will return E_DNS_EOR (you should not log an error for this
02937  *          value, is just a signal that the address list end has been reached)
02938  * Note: either e or name must be different from 0 (name.s !=0 also)
02939  * WARNING: dns_hash_put(*e) must be called when you don't need
02940  *          the entry anymore and *e!=0 (failling to do so => mem. leak)
02941  * Example:
02942  *  dns_entry=0;
02943  *  ret=dns_a_get_ip(&dns_entry, name, &ip, &rr_no);  -- get the first rr.
02944  *  ...
02945  *  rr_no++;
02946  *  while((ret>=0) && dns_entry)
02947  *     dns_a_get_ip(&dns_entry, name, &ip, &rr_no); -- get the next rr
02948  *   if (ret!=-E_DNS_EOR) ERROR(....);
02949  *  ...
02950  *  dns_hash_put(dns_entry); -- finished with the entry
02951  */
02952 inline static int dns_a_resolve( struct dns_hash_entry** e,
02953                                                                  unsigned char* rr_no,
02954                                                                  str* name,
02955                                                                  struct ip_addr* ip)
02956 {
02957         struct dns_rr* rr;
02958         int ret;
02959         ticks_t now;
02960         struct ip_addr* tmp;
02961 
02962         rr=0;
02963         ret=-E_DNS_NO_IP;
02964         if (*e==0){ /* do lookup */
02965                 /* if ip don't set *e */
02966                 if ((tmp=str2ip(name))!=0){
02967                         *ip=*tmp;
02968                         *rr_no=0;
02969                         return 0;
02970                 }
02971                 if ((*e=dns_get_entry(name, T_A))==0)
02972                         goto error;
02973                 /* found */
02974                 *rr_no=0;
02975                 ret=-E_DNS_BAD_IP_ENTRY;
02976         }
02977         now=get_ticks_raw();
02978         /* if the entry has already expired use the time at the end of lifetime */
02979         if (unlikely((s_ticks_t)(now-(*e)->expire)>=0)) now=(*e)->expire-1;
02980         rr=dns_entry_get_rr(*e, rr_no, now);
02981         if (rr){
02982                 /* everything is ok now, we can try to "convert" the ip */
02983                 dns_rr2ip((*e)->type, rr, ip);
02984                 ret=0;
02985         }else{
02986                 ret=-E_DNS_EOR;
02987         }
02988 error:
02989         DBG("dns_a_resolve(%.*s, %d) returning %d\n",
02990                         name->len, name->s, *rr_no, ret);
02991         return ret;
02992 }
02993 
02994 
02995 #ifdef USE_IPV6
02996 /* lookup, fills the dns_entry pointer and the ip addr.
02997  *  (with the first good ip). if *e ==0 does the a lookup, and changes it
02998  *   to the result, if not it uses the current value and tries to use
02999  * Same as dns_a_resolve but for aaaa records (see above).
03000  */
03001 inline static int dns_aaaa_resolve( struct dns_hash_entry** e,
03002                                                                         unsigned char* rr_no,
03003                                                                         str* name,
03004                                                                         struct ip_addr* ip)
03005 {
03006         struct dns_rr* rr;
03007         int ret;
03008         ticks_t now;
03009         struct ip_addr* tmp;
03010 
03011         rr=0;
03012         ret=-E_DNS_NO_IP;
03013         if (*e==0){ /* do lookup */
03014                 /* if ip don't set *e */
03015                 if ((tmp=str2ip6(name))!=0){
03016                         *ip=*tmp;
03017                         *rr_no=0;
03018                         return 0;
03019                 }
03020                 if ((*e=dns_get_entry(name, T_AAAA))==0)
03021                         goto error;
03022                 /* found */
03023                 *rr_no=0;
03024                 ret=-E_DNS_BAD_IP_ENTRY;
03025         }
03026         now=get_ticks_raw();
03027         /* if the entry has already expired use the time at the end of lifetime */
03028         if (unlikely((s_ticks_t)(now-(*e)->expire)>=0)) now=(*e)->expire-1;
03029         rr=dns_entry_get_rr(*e, rr_no, now);
03030         if (rr){
03031                 /* everything is ok now, we can try to "convert" the ip */
03032                 dns_rr2ip((*e)->type, rr, ip);
03033                 ret=0;
03034         }else{
03035                 ret=-E_DNS_EOR; /* no more records */
03036         }
03037 error:
03038         return ret;
03039 }
03040 #endif /* USE_IPV6 */
03041 
03042 
03043 
03044 /* performs an a or aaaa dns lookup, returns <0 on error (see the
03045  *  dns error codes) and 0 on success
03046  *  flags:  - none set: tries first an a_lookup and if it fails an aaaa_lookup
03047  *          - DNS_IPV6_FIRST: tries first an aaaa_lookup and then an a_lookup
03048  *          - DNS_IPV4_ONLY: tries only an a_lookup
03049  *          - DNS_IPV6_ONLY: tries only an aaaa_lookup
03050  *  see dns_a_resolve() for the rest of the params., examples a.s.o
03051  *  WARNING: don't forget dns_hash_put(*e) when e is not needed anymore
03052  */
03053 inline static int dns_ip_resolve(       struct dns_hash_entry** e,
03054                                                                         unsigned char* rr_no,
03055                                                                         str* name,
03056                                                                         struct ip_addr* ip,
03057                                                                         int flags)
03058 {
03059         int ret;
03060         str host;
03061         struct dns_hash_entry* orig;
03062 
03063         ret=-E_DNS_NO_IP;
03064         if (*e==0){ /* first call */
03065 #ifdef USE_IPV6
03066                 if ((flags&(DNS_IPV6_FIRST|DNS_IPV6_ONLY))){
03067                         ret=dns_aaaa_resolve(e, rr_no, name, ip);
03068                         if (ret>=0) return ret;
03069                 }else{
03070                         ret=dns_a_resolve(e, rr_no, name, ip);
03071                         if (ret>=0) return ret;
03072                 }
03073                 if (flags&DNS_IPV6_FIRST){
03074                         ret=dns_a_resolve(e, rr_no, name, ip);
03075                 }else if (!(flags&(DNS_IPV6_ONLY|DNS_IPV4_ONLY))){
03076                         ret=dns_aaaa_resolve(e, rr_no, name, ip);
03077                 }
03078 #else /* USE_IPV6 */
03079                 ret=dns_a_resolve(e, rr_no, name, ip);
03080 #endif /* USE_IPV6 */
03081         }else if ((*e)->type==T_A){
03082                 /* continue A resolving */
03083                 /* retrieve host name from the hash entry  (ignore name which might
03084                   be null when continuing a srv lookup) */
03085                 host.s=(*e)->name;
03086                 host.len=(*e)->name_len;
03087                 ret=dns_a_resolve(e, rr_no, &host, ip);
03088 #ifdef USE_IPV6
03089                 if (ret>=0) return ret;
03090                 if (!(flags&(DNS_IPV6_ONLY|DNS_IPV6_FIRST|DNS_IPV4_ONLY))){
03091                         /* not found, try with AAAA */
03092                         orig=*e;
03093                         *e=0;
03094                         *rr_no=0;
03095                         ret=dns_aaaa_resolve(e, rr_no, &host, ip);
03096                         /* delay original record release until we're finished with host*/
03097                         dns_hash_put(orig);
03098                 }
03099 #endif /* USE_IPV6 */
03100         }else if ((*e)->type==T_AAAA){
03101                 /* retrieve host name from the hash entry  (ignore name which might
03102                   be null when continuing a srv lookup) */
03103                 host.s=(*e)->name;
03104                 host.len=(*e)->name_len;
03105 #ifdef USE_IPV6
03106                 /* continue AAAA resolving */
03107                 ret=dns_aaaa_resolve(e, rr_no, &host, ip);
03108                 if (ret>=0) return ret;
03109                 if ((flags&DNS_IPV6_FIRST) && !(flags&DNS_IPV6_ONLY)){
03110                         /* not found, try with A */
03111                         orig=*e;
03112                         *e=0;
03113                         *rr_no=0;
03114                         ret=dns_a_resolve(e, rr_no, &host, ip);
03115                         /* delay original record release until we're finished with host*/
03116                         dns_hash_put(orig);
03117                 }
03118 #else /* USE_IPV6 */
03119                 /* ipv6 disabled, try with A */
03120                 orig=*e;
03121                 *e=0;
03122                 *rr_no=0;
03123                 ret=dns_a_resolve(e, rr_no, &host, ip);
03124                 /* delay original record release until we're finished with host*/
03125                 dns_hash_put(orig);
03126 #endif /* USE_IPV6 */
03127         }else{
03128                 LOG(L_CRIT, "BUG: dns_ip_resolve: invalid record type %d\n",
03129                                         (*e)->type);
03130         }
03131         return ret;
03132 }
03133 
03134 
03135 
03136 /*  gets the first srv record starting at rr_no
03137  *  Next call will return the next record a.s.o.
03138  *  (similar to dns_a_resolve but for srv, sets host, port and automatically
03139  *   switches to the next record in the future)
03140  *
03141  *   if DNS_SRV_LB and tried!=NULL will do random weight based selection
03142  *   for choosing between SRV RRs with the same priority (as described in
03143  *    RFC2782).
03144  *   If tried==NULL or DNS_SRV_LB is not defined => always returns next
03145  *    record in the priority order and for records with the same priority
03146  *     the record with the higher weight (from the remaining ones)
03147  */
03148 inline static int dns_srv_resolve_nxt(struct dns_hash_entry** e,
03149 #ifdef DNS_SRV_LB
03150                                                 srv_flags_t* tried,
03151 #endif
03152                                                 unsigned char* rr_no,
03153                                                 str* name, str* host, unsigned short* port)
03154 {
03155         struct dns_rr* rr;
03156         int ret;
03157         ticks_t now;
03158 
03159         rr=0;
03160         ret=-E_DNS_NO_SRV;
03161         if (*e==0){
03162                 if ((*e=dns_get_entry(name, T_SRV))==0)
03163                         goto error;
03164                 /* found it */
03165                 *rr_no=0;
03166 #ifdef DNS_SRV_LB
03167                 if (tried)
03168                         srv_reset_tried(tried);
03169 #endif
03170                 ret=-E_DNS_BAD_SRV_ENTRY;
03171         }
03172         now=get_ticks_raw();
03173         /* if the entry has already expired use the time at the end of lifetime */
03174         if (unlikely((s_ticks_t)(now-(*e)->expire)>=0)) now=(*e)->expire-1;
03175 #ifdef DNS_SRV_LB
03176         if (tried){
03177                 rr=dns_srv_get_nxt_rr(*e, tried, rr_no, now);
03178         }else
03179 #endif
03180         {
03181                 rr=dns_entry_get_rr(*e, rr_no, now);
03182                 (*rr_no)++; /* try next record next time */
03183         }
03184         if (rr){
03185                 host->s=((struct srv_rdata*)rr->rdata)->name;
03186                 host->len=((struct srv_rdata*)rr->rdata)->name_len;
03187                 *port=((struct srv_rdata*)rr->rdata)->port;
03188                 ret=0;
03189         }else{
03190                 ret=-E_DNS_EOR; /* no more records */
03191         }
03192 error:
03193         return ret;
03194 }
03195 
03196 
03197 
03198 /*  gets the first srv record starting at h->srv_no, resolve it
03199  *   and get the first ip address (starting at h->ip_no)
03200  *  (similar to dns_a_resolve but for srv, sets host, port)
03201  *  WARNING: don't forget to init h prior to calling this function the first
03202  *   time and dns_srv_handle_put(h), even if error is returned
03203  */
03204 inline static int dns_srv_resolve_ip(struct dns_srv_handle* h,
03205                                         str* name, struct ip_addr* ip, unsigned short* port,
03206                                         int flags)
03207 {
03208         int ret;
03209         str host;
03210 
03211         host.len=0;
03212         host.s=0;
03213         do{
03214                 if (h->a==0){
03215 #ifdef DNS_SRV_LB
03216                         if ((ret=dns_srv_resolve_nxt(&h->srv,
03217                                                                 (flags & DNS_SRV_RR_LB)?&h->srv_tried_rrs:0,
03218                                                                 &h->srv_no,
03219                                                                 name, &host, port))<0)
03220                                 goto error;
03221 #else
03222                         if ((ret=dns_srv_resolve_nxt(&h->srv, &h->srv_no,
03223                                                                 name, &host, port))<0)
03224                                 goto error;
03225 #endif
03226                         h->port=*port; /* store new port */
03227                 }else{
03228                         *port=h->port; /* return the stored port */
03229                 }
03230                 if ((ret=dns_ip_resolve(&h->a, &h->ip_no, &host, ip, flags))<0){
03231                         /* couldn't find any good ip for this record, try the next one */
03232                         if (h->a){
03233                                 dns_hash_put(h->a);
03234                                 h->a=0;
03235                         }
03236                 }else if (h->a==0){
03237                         /* this was an ip, try the next srv record in the future */
03238                 }
03239         }while(ret<0);
03240 error:
03241 #ifdef DNS_CACHE_DEBUG
03242         DBG("dns_srv_resolve_ip(\"%.*s\", %d, %d), ret=%d, ip=%s\n",
03243                         name->len, name->s, h->srv_no, h->ip_no, ret,
03244                         ip?ZSW(ip_addr2a(ip)):"");
03245 #endif
03246         return ret;
03247 }
03248 
03249 
03250 
03251 /* resolves a host name trying SRV lookup if *port==0 or normal A/AAAA lookup
03252  * if *port!=0.
03253  * when performing SRV lookup (*port==0) it will use proto to look for
03254  * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
03255  * h must be initialized prior to  calling this function and can be used to
03256  * get the subsequent ips
03257  * returns:  <0 on error
03258  *            0 on success and it fills *ip, *port, dns_sip_resolve_h
03259  * WARNING: when finished, dns_sip_resolve_put(h) must be called!
03260  */
03261 inline static int dns_srv_sip_resolve(struct dns_srv_handle* h,  str* name,
03262                                                 struct ip_addr* ip, unsigned short* port, char* proto,
03263                                                 int flags)
03264 {
03265         static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */
03266         int len;
03267         str srv_name;
03268         struct ip_addr* tmp_ip;
03269         int ret;
03270         struct hostent* he;
03271         char srv_proto;
03272 
03273         if (dns_hash==0){ /* not init => use normal, non-cached version */
03274                 LOG(L_WARN, "WARNING: dns_sip_resolve: called before dns cache"
03275                                         " initialization\n");
03276                 h->srv=h->a=0;
03277                 he=_sip_resolvehost(name, port, proto);
03278                 if (he){
03279                         hostent2ip_addr(ip, he, 0);
03280                         return 0;
03281                 }
03282                 return -E_DNS_NO_SRV;
03283         }
03284         len=0;
03285         if ((h->srv==0) && (h->a==0)){ /* first call */
03286                 if (proto){ /* makes sure we have a protocol set*/
03287                         if (*proto==0)
03288                                 *proto=srv_proto=PROTO_UDP; /* default */
03289                         else
03290                                 srv_proto=*proto;
03291                 }else{
03292                         srv_proto=PROTO_UDP;
03293                 }
03294                 h->port=(srv_proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we
03295                                                                                                                 don't find another */
03296                 h->proto=srv_proto; /* store initial protocol */
03297                 if (port){
03298                         if (*port==0){
03299                                 /* try SRV if initial call & no port specified
03300                                  * (draft-ietf-sip-srv-06) */
03301                                 if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){
03302                                         LOG(L_WARN, "WARNING: dns_sip_resolvehost: domain name too"
03303                                                                 " long (%d), unable to perform SRV lookup\n",
03304                                                                 name->len);
03305                                 }else{
03306                                         /* check if it's an ip address */
03307                                         if ( ((tmp_ip=str2ip(name))!=0)
03308 #ifdef  USE_IPV6
03309                                                   || ((tmp_ip=str2ip6(name))!=0)
03310 #endif
03311                                                 ){
03312                                                 /* we are lucky, this is an ip address */
03313 #ifdef  USE_IPV6
03314                                                 if (((flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
03315                                                         ((flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
03316                                                         return -E_DNS_AF_MISMATCH;
03317                                                 }
03318 #endif
03319                                                 *ip=*tmp_ip;
03320                                                 *port=h->port;
03321                                                 /* proto already set */
03322                                                 return 0;
03323                                         }
03324 
03325                                         switch(srv_proto){
03326                                                 case PROTO_NONE: /* no proto specified, use udp */
03327                                                         if (proto)
03328                                                                 *proto=PROTO_UDP;
03329                                                         /* no break */
03330                                                 case PROTO_UDP:
03331                                                         memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
03332                                                         memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
03333                                                         tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
03334                                                         len=SRV_UDP_PREFIX_LEN + name->len;
03335                                                         break;
03336                                                 case PROTO_TCP:
03337                                                         memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
03338                                                         memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
03339                                                         tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
03340                                                         len=SRV_TCP_PREFIX_LEN + name->len;
03341                                                         break;
03342                                                 case PROTO_TLS:
03343                                                         memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
03344                                                         memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
03345                                                         tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
03346                                                         len=SRV_TLS_PREFIX_LEN + name->len;
03347                                                         break;
03348                                                 case PROTO_SCTP:
03349                                                         memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
03350                                                         memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len);
03351                                                         tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
03352                                                         len=SRV_SCTP_PREFIX_LEN + name->len;
03353                                                         break;
03354                                                 default:
03355                                                         LOG(L_CRIT, "BUG: sip_resolvehost: "
03356                                                                         "unknown proto %d\n", (int)srv_proto);
03357                                                         return -E_DNS_CRITICAL;
03358                                         }
03359                                         srv_name.s=tmp;
03360                                         srv_name.len=len;
03361                                         if ((ret=dns_srv_resolve_ip(h, &srv_name, ip,
03362                                                                                                                         port, flags))>=0)
03363                                         {
03364 #ifdef DNS_CACHE_DEBUG
03365                                                 DBG("dns_sip_resolve(%.*s, %d, %d), srv0, ret=%d\n",
03366                                                         name->len, name->s, h->srv_no, h->ip_no, ret);
03367 #endif
03368                                                 /* proto already set */
03369                                                 return ret;
03370                                         }
03371                                 }
03372                         }else{ /* if (*port==0) */
03373                                 h->port=*port; /* store initial port */
03374                                 /* proto already set */
03375                         }
03376                 } /* if (port) */
03377         }else if (h->srv){
03378                         srv_name.s=h->srv->name;
03379                         srv_name.len=h->srv->name_len;
03380                         /* continue srv resolving */
03381                         ret=dns_srv_resolve_ip(h, &srv_name, ip, port, flags);
03382                         if (proto)
03383                                 *proto=h->proto;
03384                         DBG("dns_sip_resolve(%.*s, %d, %d), srv, ret=%d\n",
03385                                         name->len, name->s, h->srv_no, h->ip_no, ret);
03386                         return ret;
03387         }
03388 /*skip_srv:*/
03389         if (name->len >= MAX_DNS_NAME) {
03390                 LOG(L_ERR, "dns_sip_resolve: domain name too long\n");
03391                 return -E_DNS_NAME_TOO_LONG;
03392         }
03393         ret=dns_ip_resolve(&h->a, &h->ip_no, name, ip, flags);
03394         if (port)
03395                 *port=h->port;
03396         if (proto)
03397                 *proto=h->proto;
03398 #ifdef DNS_CACHE_DEBUG
03399         DBG("dns_sip_resolve(%.*s, %d, %d), ip, ret=%d\n",
03400                         name->len, name->s, h->srv_no, h->ip_no, ret);
03401 #endif
03402         return ret;
03403 }
03404 
03405 
03406 
03407 #ifdef USE_NAPTR
03408 /* resolves a host name trying:
03409  * - NAPTR lookup if the address is not an ip and proto!=0, port!=0
03410  *    *port==0 and *proto=0 and if flags allow NAPTR lookups
03411  * -SRV lookup if  port!=0 and *port==0
03412  * - normal A/AAAA lookup if *port!=0, or port==0
03413  * when performing SRV lookup (*port==0) it will use proto to look for
03414  * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
03415  * h must be initialized prior to  calling this function and can be used to
03416  * get the subsequent ips
03417  * returns:  <0 on error
03418  *            0 on success and it fills *ip, *port, dns_sip_resolve_h
03419  * WARNING: when finished, dns_sip_resolve_put(h) must be called!
03420  */
03421 inline static int dns_naptr_sip_resolve(struct dns_srv_handle* h,  str* name,
03422                                                 struct ip_addr* ip, unsigned short* port, char* proto,
03423                                                 int flags)
03424 {
03425         struct hostent* he;
03426         struct ip_addr* tmp_ip;
03427         naptr_bmp_t tried_bmp;
03428         struct dns_hash_entry* e;
03429         char n_proto;
03430         str srv_name;
03431         int ret;
03432 
03433         ret=-E_DNS_NO_NAPTR;
03434         if (dns_hash==0){ /* not init => use normal, non-cached version */
03435                 LOG(L_WARN, "WARNING: dns_sip_resolve: called before dns cache"
03436                                         " initialization\n");
03437                 h->srv=h->a=0;
03438                 he=_sip_resolvehost(name, port, proto);
03439                 if (he){
03440                         hostent2ip_addr(ip, he, 0);
03441                         return 0;
03442                 }
03443                 return -E_DNS_NO_NAPTR;
03444         }
03445         if (((h->srv==0) && (h->a==0)) && /* first call */
03446                          proto && port && (*proto==0) && (*port==0)){
03447                 *proto=PROTO_UDP; /* just in case we don't find another */
03448 
03449                 /* check if it's an ip address */
03450                 if ( ((tmp_ip=str2ip(name))!=0)
03451 #ifdef  USE_IPV6
03452                           || ((tmp_ip=str2ip6(name))!=0)
03453 #endif
03454                         ){
03455                         /* we are lucky, this is an ip address */
03456 #ifdef  USE_IPV6
03457                         if (((flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
03458                                 ((flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
03459                                 return -E_DNS_AF_MISMATCH;
03460                         }
03461 #endif
03462                         *ip=*tmp_ip;
03463                         h->port=SIP_PORT;
03464                         h->proto=*proto;
03465                         *port=h->port;
03466                         return 0;
03467                 }
03468                 /* do naptr lookup */
03469                 if ((e=dns_get_entry(name, T_NAPTR))==0)
03470                         goto naptr_not_found;
03471                 naptr_iterate_init(&tried_bmp);
03472                 while(dns_naptr_sip_iterate(e->rr_lst, &tried_bmp,
03473                                                                                                 &srv_name, &n_proto)){
03474                         dns_srv_handle_init(h); /* make sure h does not contain garbage
03475                                                                         from previous dns_srv_sip_resolve calls */
03476                         if ((ret=dns_srv_resolve_ip(h, &srv_name, ip, port, flags))>=0){
03477 #ifdef DNS_CACHE_DEBUG
03478                                 DBG("dns_naptr_sip_resolve(%.*s, %d, %d), srv0, ret=%d\n",
03479                                                                 name->len, name->s, h->srv_no, h->ip_no, ret);
03480 #endif
03481                                 dns_hash_put(e);
03482                                 *proto=n_proto;
03483                                 h->proto=*proto;
03484                                 return ret;
03485                         }
03486                 }
03487                 /* no acceptable naptr record found, fallback to srv */
03488                 dns_hash_put(e);
03489                 dns_srv_handle_init(h); /* make sure h does not contain garbage
03490                                                                 from previous dns_srv_sip_resolve calls */
03491         }
03492 naptr_not_found:
03493         return dns_srv_sip_resolve(h, name, ip, port, proto, flags);
03494 }
03495 #endif /* USE_NAPTR */
03496 
03497 
03498 
03499 /* resolves a host name trying:
03500  * - NAPTR lookup if the address is not an ip and proto!=0, port!=0
03501  *    *port==0 and *proto=0 and if flags allow NAPTR lookups
03502  * -SRV lookup if  port!=0 and *port==0
03503  * - normal A/AAAA lookup if *port!=0, or port==0
03504  * when performing SRV lookup (*port==0) it will use proto to look for
03505  * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
03506  * h must be initialized prior to  calling this function and can be used to
03507  * get the subsequent ips
03508  * returns:  <0 on error
03509  *            0 on success and it fills *ip, *port, dns_sip_resolve_h
03510  * WARNING: when finished, dns_sip_resolve_put(h) must be called!
03511  */
03512 int dns_sip_resolve(struct dns_srv_handle* h,  str* name,
03513                                                 struct ip_addr* ip, unsigned short* port, char* proto,
03514                                                 int flags)
03515 {
03516 #ifdef USE_NAPTR
03517         if (flags&DNS_TRY_NAPTR)
03518                 return dns_naptr_sip_resolve(h, name, ip, port, proto, flags);
03519 #endif
03520         return dns_srv_sip_resolve(h, name, ip, port, proto, flags);
03521 }
03522 
03523 /* performs an a lookup and fills ip with the first good ip address
03524  * returns 0 on success, <0 on error (see the error codes)
03525  */
03526 inline static int dns_a_get_ip(str* name, struct ip_addr* ip)
03527 {
03528         struct dns_hash_entry* e;
03529         int ret;
03530         unsigned char rr_no;
03531 
03532         e=0;
03533         rr_no=0;
03534         ret=dns_a_resolve(&e, &rr_no, name, ip);
03535         if (e) dns_hash_put(e);
03536         return ret;
03537 }
03538 
03539 
03540 #ifdef USE_IPV6
03541 inline static int dns_aaaa_get_ip(str* name, struct ip_addr* ip)
03542 {
03543         struct dns_hash_entry* e;
03544         int ret;
03545         unsigned char rr_no;
03546 
03547         e=0;
03548         rr_no=0;
03549         ret=dns_aaaa_resolve(&e, &rr_no, name, ip);
03550         if (e) dns_hash_put(e);
03551         return ret;
03552 }
03553 #endif /* USE_IPV6 */
03554 
03555 
03556 
03557 /* performs an a or aaaa dns lookup, returns <0 on error (see the
03558  *  dns error codes) and 0 on success
03559  *  flags:  - none set: tries first an a_lookup and if it fails an aaaa_lookup
03560  *          - DNS_IPV6_FIRST: tries first an aaaa_lookup and then an a_lookup
03561  *          - DNS_IPV4_ONLY: tries only an a_lookup
03562  *          - DNS_IPV6_ONLY: tries only an aaaa_lookup
03563  */
03564 int dns_get_ip(str* name, struct ip_addr* ip, int flags)
03565 {
03566         int ret;
03567         struct dns_hash_entry* e;
03568         unsigned char rr_no;
03569 
03570         e=0;
03571         rr_no=0;
03572         ret=dns_ip_resolve(&e, &rr_no, name, ip, flags);
03573         if (e)
03574                 dns_hash_put(e);
03575         return ret;
03576 }
03577 
03578 
03579 
03580 /* fast "inline" version, gets the first good ip:port */
03581 int dns_srv_get_ip(str* name, struct ip_addr* ip, unsigned short* port,
03582                                                 int flags)
03583 {
03584         int ret;
03585         struct dns_srv_handle h;
03586 
03587         dns_srv_handle_init(&h);
03588         ret=dns_srv_resolve_ip(&h, name, ip, port, flags);
03589         dns_srv_handle_put(&h);
03590         return ret;
03591 }
03592 
03593 
03594 #ifdef DNS_WATCHDOG_SUPPORT
03595 /* sets the state of the DNS servers:
03596  * 1: at least one server is up
03597  * 0: all the servers are down
03598  */
03599 void dns_set_server_state(int state)
03600 {
03601         atomic_set(dns_servers_up, state);
03602 }
03603 
03604 /* returns the state of the DNS servers */
03605 int dns_get_server_state(void)
03606 {
03607         return atomic_get(dns_servers_up);
03608 }
03609 #endif /* DNS_WATCHDOG_SUPPORT */
03610 
03611 /* rpc functions */
03612 void dns_cache_mem_info(rpc_t* rpc, void* ctx)
03613 {
03614         if (!cfg_get(core, core_cfg, use_dns_cache)){
03615                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
03616                 return;
03617         }
03618         rpc->add(ctx, "dd",  *dns_cache_mem_used, cfg_get(core, core_cfg, dns_cache_max_mem));
03619 }
03620 
03621 
03622 void dns_cache_debug(rpc_t* rpc, void* ctx)
03623 {
03624         int h;
03625         struct dns_hash_entry* e;
03626         ticks_t now;
03627 
03628         if (!cfg_get(core, core_cfg, use_dns_cache)){
03629                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
03630                 return;
03631         }
03632         now=get_ticks_raw();
03633         LOCK_DNS_HASH();
03634                 for (h=0; h<DNS_HASH_SIZE; h++){
03635                         clist_foreach(&dns_hash[h], e, next){
03636                                 rpc->add(ctx, "sdddddd",
03637                                                                 e->name, e->type, e->total_size, e->refcnt.val,
03638                                                                 (s_ticks_t)(e->expire-now)<0?-1:
03639                                                                         TICKS_TO_S(e->expire-now),
03640                                                                 TICKS_TO_S(now-e->last_used),
03641                                                                 e->ent_flags);
03642                         }
03643                 }
03644         UNLOCK_DNS_HASH();
03645 }
03646 
03647 
03648 #ifdef USE_DNS_CACHE_STATS
03649 static unsigned long  stat_sum(int ivar, int breset)
03650 {
03651         unsigned long isum=0;
03652         int i1=0;
03653 
03654         for (; i1 < get_max_procs(); i1++)
03655                 switch (ivar) {
03656                         case 0:
03657                                 isum+=dns_cache_stats[i1].dns_req_cnt;
03658                                 if (breset)
03659                                         dns_cache_stats[i1].dns_req_cnt=0;
03660                                 break;
03661                         case 1:
03662                                 isum+=dns_cache_stats[i1].dc_hits_cnt;
03663                                 if (breset)
03664                                         dns_cache_stats[i1].dc_hits_cnt=0;
03665                                 break;
03666                         case 2:
03667                                 isum+=dns_cache_stats[i1].dc_neg_hits_cnt;
03668                                 if (breset)
03669                                         dns_cache_stats[i1].dc_neg_hits_cnt=0;
03670                                 break;
03671                         case 3:
03672                                 isum+=dns_cache_stats[i1].dc_lru_cnt;
03673                                 if (breset)
03674                                         dns_cache_stats[i1].dc_lru_cnt=0;
03675                                 break;
03676                 }
03677 
03678         return isum;
03679 }
03680 
03681 
03682 void dns_cache_stats_get(rpc_t* rpc, void* c)
03683 {
03684         char *name=NULL;
03685         void *handle;
03686         int found=0,i=0;
03687         int reset=0;
03688         char* dns_cache_stats_names[] = {
03689                 "dns_req_cnt",
03690                 "dc_hits_cnt",
03691                 "dc_neg_hits_cnt",
03692                 "dc_lru_cnt",
03693                 NULL
03694         };
03695 
03696 
03697         if (!cfg_get(core, core_cfg, use_dns_cache)) {
03698                 rpc->fault(c, 500, "dns cache support disabled");
03699                 return;
03700         }
03701         if (rpc->scan(c, "s", &name) < 0)
03702                 return;
03703         if (rpc->scan(c, "d", &reset) < 0)
03704                 return;
03705         if (!strcasecmp(name, DNS_CACHE_ALL_STATS)) {
03706                 /* dump all the dns cache stat values */
03707                 rpc->add(c, "{", &handle);
03708                 for (i=0; dns_cache_stats_names[i]; i++)
03709                         rpc->struct_add(handle, "d",
03710                                                         dns_cache_stats_names[i],
03711                                                         stat_sum(i, reset));
03712 
03713                 found=1;
03714         } else {
03715                 for (i=0; dns_cache_stats_names[i]; i++)
03716                         if (!strcasecmp(dns_cache_stats_names[i], name)) {
03717                                 rpc->add(c, "{", &handle);
03718                                 rpc->struct_add(handle, "d",
03719                                                                 dns_cache_stats_names[i],
03720                                                                 stat_sum(i, reset));
03721                                 found=1;
03722                                 break;
03723                         }
03724         }
03725         if(!found)
03726                 rpc->fault(c, 500, "unknown dns cache stat parameter");
03727 
03728         return;
03729 }
03730 #endif /* USE_DNS_CACHE_STATS */
03731 
03732 /* rpc functions */
03733 void dns_cache_debug_all(rpc_t* rpc, void* ctx)
03734 {
03735         int h;
03736         struct dns_hash_entry* e;
03737         struct dns_rr* rr;
03738         struct ip_addr ip;
03739         int i;
03740         ticks_t now;
03741 
03742         if (!cfg_get(core, core_cfg, use_dns_cache)){
03743                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
03744                 return;
03745         }
03746         now=get_ticks_raw();
03747         LOCK_DNS_HASH();
03748                 for (h=0; h<DNS_HASH_SIZE; h++){
03749                         clist_foreach(&dns_hash[h], e, next){
03750                                 for (i=0, rr=e->rr_lst; rr; i++, rr=rr->next){
03751                                         rpc->add(ctx, "sddddddd",
03752                                                                 e->name, (int)e->type, i, (int)e->total_size,
03753                                                                 (int)e->refcnt.val,
03754                                                                 (int)(s_ticks_t)(e->expire-now)<0?-1:
03755                                                                         TICKS_TO_S(e->expire-now),
03756                                                                 (int)TICKS_TO_S(now-e->last_used),
03757                                                                 (int)e->ent_flags);
03758                                         switch(e->type){
03759                                                 case T_A:
03760                                                 case T_AAAA:
03761                                                         if (dns_rr2ip(e->type, rr, &ip)==0){
03762                                                                 rpc->add(ctx, "ss", "ip", ip_addr2a(&ip) );
03763                                                         }else{
03764                                                                 rpc->add(ctx, "ss", "ip", "<error: bad rr>");
03765                                                         }
03766                                                         break;
03767                                                 case T_SRV:
03768                                                         rpc->add(ctx, "ss", "srv",
03769                                                                         ((struct srv_rdata*)(rr->rdata))->name);
03770                                                         break;
03771                                                 case T_NAPTR:
03772                                                         rpc->add(ctx, "ss", "naptr ",
03773                                                                 ((struct naptr_rdata*)(rr->rdata))->flags);
03774                                                         break;
03775                                                 case T_CNAME:
03776                                                         rpc->add(ctx, "ss", "cname",
03777                                                                         ((struct cname_rdata*)(rr->rdata))->name);
03778                                                         break;
03779                                                 case T_TXT:
03780                                                         rpc->add(ctx, "ss", "txt",
03781                                                                 ((struct txt_rdata*)(rr->rdata))->cstr_no?
03782                                                                 ((struct txt_rdata*)(rr->rdata))->txt[0].cstr:
03783                                                                 "");
03784                                                         break;
03785                                                 case T_EBL:
03786                                                         rpc->add(ctx, "ss", "ebl",
03787                                                                 ((struct ebl_rdata*)(rr->rdata))->apex);
03788                                                         break;
03789                                                 case T_PTR:
03790                                                         rpc->add(ctx, "ss", "ptr",
03791                                                                 ((struct ptr_rdata*)(rr->rdata))->ptrdname);
03792                                                         break;
03793                                                 default:
03794                                                         rpc->add(ctx, "ss", "unknown", "?");
03795                                         }
03796                                         rpc->add(ctx, "d",
03797                                                                 (int)(s_ticks_t)(rr->expire-now)<0?-1:
03798                                                                         TICKS_TO_S(rr->expire-now));
03799                                 }
03800                         }
03801                 }
03802         UNLOCK_DNS_HASH();
03803 }
03804 
03805 
03806 static char *print_type(unsigned short type)
03807 {
03808         switch (type) {
03809                 case T_A:
03810                         return "A";
03811                 case T_AAAA:
03812                         return "AAAA";
03813                 case T_SRV:
03814                         return "SRV";
03815                 case T_NAPTR:
03816                         return "NAPTR";
03817                 case T_CNAME:
03818                         return "CNAME";
03819                 case T_TXT:
03820                         return "TXT";
03821                 case T_EBL:
03822                         return "EBL";
03823                 case T_PTR:
03824                         return "PTR";
03825                 default:
03826                         return "unknown";
03827         }
03828 }
03829 
03830 
03835 static int dns_get_type(str* s)
03836 {
03837         char *t;
03838         int len;
03839         
03840         t=s->s;
03841         len=s->len;
03842         /* skip over a T_ or t_ prefix */
03843         if ((len>2) && (t[0]=='T' || t[0]=='t') && (t[1]=='_')){
03844                 t+=2;
03845                 len-=2;
03846         }
03847         switch(len){
03848                 case 1:
03849                         if (t[0]=='A' || t[0]=='a')
03850                                 return T_A;
03851                         break;
03852                 case 4:
03853                         if (strncasecmp(t, "AAAA", len)==0)
03854                                 return T_AAAA;
03855                         break;
03856                 case 3:
03857                         if (strncasecmp(t, "SRV", len)==0)
03858                                 return T_SRV;
03859                         else if (strncasecmp(t, "TXT", len)==0)
03860                                 return T_TXT;
03861                         else if (strncasecmp(t, "EBL", len)==0)
03862                                 return T_EBL;
03863                         else if (strncasecmp(t, "PTR", len)==0)
03864                                 return T_PTR;
03865                         break;
03866                 case 5:
03867                         if (strncasecmp(t, "NAPTR", len)==0)
03868                                 return T_NAPTR;
03869                         else if (strncasecmp(t, "CNAME", len)==0)
03870                                 return T_CNAME;
03871                         break;
03872         }
03873         return -1;
03874 }
03875 
03876 
03879 void dns_cache_print_entry(rpc_t* rpc, void* ctx, struct dns_hash_entry* e)
03880 {
03881         int expires;
03882         struct dns_rr* rr;
03883         struct ip_addr ip;
03884         ticks_t now;
03885         str s;
03886         int i;
03887 
03888         now=get_ticks_raw();
03889         expires = (s_ticks_t)(e->expire-now)<0?-1: TICKS_TO_S(e->expire-now);
03890         
03891         rpc->printf(ctx, "%sname: %s", SPACE_FORMAT, e->name);
03892         rpc->printf(ctx, "%stype: %s", SPACE_FORMAT, print_type(e->type));
03893         rpc->printf(ctx, "%ssize (bytes): %d", SPACE_FORMAT,
03894                                                 e->total_size);
03895         rpc->printf(ctx, "%sreference counter: %d", SPACE_FORMAT,
03896                                                 e->refcnt.val);
03897         if (e->ent_flags & DNS_FLAG_PERMANENT) {
03898                 rpc->printf(ctx, "%spermanent: yes", SPACE_FORMAT);
03899         } else {
03900                 rpc->printf(ctx, "%spermanent: no", SPACE_FORMAT);
03901                 rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
03902         }
03903         rpc->printf(ctx, "%slast used (s): %d", SPACE_FORMAT,
03904                                                 TICKS_TO_S(now-e->last_used));
03905         rpc->printf(ctx, "%snegative entry: %s", SPACE_FORMAT,
03906                                                 (e->ent_flags & DNS_FLAG_BAD_NAME) ? "yes" : "no");
03907         
03908         for (rr=e->rr_lst; rr; rr=rr->next) {
03909                 switch(e->type) {
03910                         case T_A:
03911                         case T_AAAA:
03912                                 if (dns_rr2ip(e->type, rr, &ip)==0){
03913                                   rpc->printf(ctx, "%srr ip: %s", SPACE_FORMAT,
03914                                                                         ip_addr2a(&ip) );
03915                                 }else{
03916                                   rpc->printf(ctx, "%srr ip: <error: bad rr>", 
03917                                                                         SPACE_FORMAT);
03918                                 }
03919                                 break;
03920                         case T_SRV:
03921                                 rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
03922                                                         ((struct srv_rdata*)(rr->rdata))->name);
03923                                 rpc->printf(ctx, "%srr port: %d", SPACE_FORMAT,
03924                                                         ((struct srv_rdata*)(rr->rdata))->port);
03925                                 rpc->printf(ctx, "%srr priority: %d", SPACE_FORMAT,
03926                                                 ((struct srv_rdata*)(rr->rdata))->priority);
03927                                 rpc->printf(ctx, "%srr weight: %d", SPACE_FORMAT,
03928                                                         ((struct srv_rdata*)(rr->rdata))->weight);
03929                                 break;
03930                         case T_NAPTR:
03931                                 rpc->printf(ctx, "%srr order: %d", SPACE_FORMAT,
03932                                                         ((struct naptr_rdata*)(rr->rdata))->order);
03933                                 rpc->printf(ctx, "%srr preference: %d", SPACE_FORMAT,
03934                                                         ((struct naptr_rdata*)(rr->rdata))->pref);
03935                                 s.s = ((struct naptr_rdata*)(rr->rdata))->flags;
03936                                 s.len = ((struct naptr_rdata*)(rr->rdata))->flags_len;
03937                                 rpc->printf(ctx, "%srr flags: %.*s", SPACE_FORMAT,
03938                                                                         s.len, s.s);
03939                                 s.s=((struct naptr_rdata*)(rr->rdata))->services;
03940                                 s.len=((struct naptr_rdata*)(rr->rdata))->services_len;
03941                                 rpc->printf(ctx, "%srr service: %.*s", SPACE_FORMAT,
03942                                                                         s.len, s.s);
03943                                 s.s = ((struct naptr_rdata*)(rr->rdata))->regexp;
03944                                 s.len = ((struct naptr_rdata*)(rr->rdata))->regexp_len;
03945                                 rpc->printf(ctx, "%srr regexp: %.*s", SPACE_FORMAT,
03946                                                                         s.len, s.s);
03947                                 s.s = ((struct naptr_rdata*)(rr->rdata))->repl;
03948                                 s.len = ((struct naptr_rdata*)(rr->rdata))->repl_len;
03949                                 rpc->printf(ctx, "%srr replacement: %.*s", 
03950                                                                         SPACE_FORMAT, s.len, s.s);
03951                                 break;
03952                         case T_CNAME:
03953                                 rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
03954                                                         ((struct cname_rdata*)(rr->rdata))->name);
03955                                 break;
03956                         case T_TXT:
03957                                 for (i=0; i<((struct txt_rdata*)(rr->rdata))->cstr_no;
03958                                                 i++){
03959                                         rpc->printf(ctx, "%stxt[%d]: %s", SPACE_FORMAT, i,
03960                                                 ((struct txt_rdata*)(rr->rdata))->txt[i].cstr);
03961                                 }
03962                                 break;
03963                         case T_EBL:
03964                                 rpc->printf(ctx, "%srr position: %d", SPACE_FORMAT,
03965                                                         ((struct ebl_rdata*)(rr->rdata))->position);
03966                                 rpc->printf(ctx, "%srr separator: %s", SPACE_FORMAT,
03967                                                         ((struct ebl_rdata*)(rr->rdata))->separator);
03968                                 rpc->printf(ctx, "%srr apex: %s", SPACE_FORMAT,
03969                                                         ((struct ebl_rdata*)(rr->rdata))->apex);
03970                                 break;
03971                         case T_PTR:
03972                                 rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
03973                                                         ((struct ptr_rdata*)(rr->rdata))->ptrdname);
03974                                 break;
03975                         default:
03976                                 rpc->printf(ctx, "%sresource record: unknown",
03977                                                                         SPACE_FORMAT);
03978                 }
03979                 if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
03980                         rpc->printf(ctx, "%srr expires in (s): %d", SPACE_FORMAT,
03981                                                 (s_ticks_t)(rr->expire-now)<0?-1 : 
03982                                                 TICKS_TO_S(rr->expire-now));
03983         }
03984 }
03985 
03986 
03987 
03988 /* dumps the content of the cache in a human-readable format */
03989 void dns_cache_view(rpc_t* rpc, void* ctx)
03990 {
03991         int h;
03992         struct dns_hash_entry* e;
03993         ticks_t now;
03994 
03995         if (!cfg_get(core, core_cfg, use_dns_cache)){
03996                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
03997                 return;
03998         }
03999         now=get_ticks_raw();
04000         LOCK_DNS_HASH();
04001         for (h=0; h<DNS_HASH_SIZE; h++){
04002                 clist_foreach(&dns_hash[h], e, next){
04003                         if (((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
04004                                 && TICKS_LT(e->expire, now)
04005                         ) {
04006                                 continue;
04007                         }
04008                         rpc->printf(ctx, "{\n");
04009                         dns_cache_print_entry(rpc, ctx, e);
04010                         rpc->printf(ctx, "}");
04011                 }
04012         }
04013         UNLOCK_DNS_HASH();
04014 }
04015 
04016 
04017 /* Delete all the entries from the cache.
04018  * If del_permanent is 0, then only the
04019  * non-permanent entries are deleted.
04020  */
04021 void dns_cache_flush(int del_permanent)
04022 {
04023         int h;
04024         struct dns_hash_entry* e;
04025         struct dns_hash_entry* tmp;
04026 
04027         DBG("dns_cache_flush(): removing elements from the cache\n");
04028         LOCK_DNS_HASH();
04029                 for (h=0; h<DNS_HASH_SIZE; h++){
04030                         clist_foreach_safe(&dns_hash[h], e, tmp, next){
04031                                 if (del_permanent || ((e->ent_flags & DNS_FLAG_PERMANENT) == 0))
04032                                         _dns_hash_remove(e);
04033                         }
04034                 }
04035         UNLOCK_DNS_HASH();
04036 }
04037 
04038 /* deletes all the non-permanent entries from the cache */
04039 void dns_cache_delete_all(rpc_t* rpc, void* ctx)
04040 {
04041         if (!cfg_get(core, core_cfg, use_dns_cache)){
04042                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04043                 return;
04044         }
04045         dns_cache_flush(0);
04046 }
04047 
04048 /* deletes all the entries from the cache,
04049  * even the permanent ones */
04050 void dns_cache_delete_all_force(rpc_t* rpc, void* ctx)
04051 {
04052         if (!cfg_get(core, core_cfg, use_dns_cache)){
04053                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04054                 return;
04055         }
04056         dns_cache_flush(1);
04057 }
04058 
04059 /* clones an entry and extends its memory area to hold a new rr.
04060  * if rdata_size>0 the new dns_rr struct is initialized, but the rdata is
04061  * only filled with 0.
04062  */
04063 static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e,
04064                                                                                                         int rdata_size,
04065                                                                                                         int ttl,
04066                                                                                                         struct dns_rr **_new_rr)
04067 {
04068         struct dns_hash_entry *new;
04069         struct dns_rr *rr, *last_rr, *new_rr;
04070         int size, rounded_size, rr_size;
04071         ticks_t now;
04072         int i;
04073 
04074         now=get_ticks_raw();
04075         size = e->total_size;
04076         if (rdata_size) {
04077                 /* we have to extend the entry */
04078                 rounded_size = ROUND_POINTER(size); /* size may not have been 
04079                                                                                                 rounded previously */
04080                 switch (e->type) {
04081                         case T_A:
04082                         case T_AAAA:
04083                         case T_CNAME:
04084                                 rr_size = sizeof(struct dns_rr);
04085                                 break;
04086                         case T_SRV:
04087                                 rr_size = ROUND_SHORT(sizeof(struct dns_rr));
04088                                 break;
04089                         case T_NAPTR:
04090                                 rr_size = ROUND_POINTER(sizeof(struct dns_rr));
04091                                 break;
04092                         case T_TXT:
04093                                 rr_size = ROUND_POINTER(sizeof(struct dns_rr));
04094                                 break;
04095                         case T_EBL:
04096                                 rr_size = ROUND_POINTER(sizeof(struct dns_rr));
04097                                 break;
04098                         case T_PTR:
04099                                 rr_size = sizeof(struct dns_rr);
04100                                 break;
04101                         default:
04102                                 LOG(L_ERR, "ERROR: dns_cache_clone_entry: type %d not "
04103                                                         "supported\n", e->type);
04104                                 return NULL;
04105                 }
04106         } else {
04107                 rounded_size = size; /* no need to round the size, we just clone
04108                                                                 the entry without extending it */
04109                 rr_size = 0;
04110         }
04111 
04112         new=shm_malloc(rounded_size+rr_size+rdata_size);
04113         if (!new) {
04114                 LOG(L_ERR, "ERROR: dns_cache_clone_entry: out of memory\n");
04115                 return NULL;
04116         }
04117         memset(new, 0, rounded_size+rr_size+rdata_size);
04118         /* clone the entry */
04119         memcpy(new, e, size);
04120         /* fix the values and pointers */
04121         new->next = new->prev = NULL;
04122 #ifdef DNS_LU_LST
04123         new->last_used_lst.next = new->last_used_lst.prev = NULL;
04124 #endif
04125         new->rr_lst = (struct dns_rr*)translate_pointer((char*)new, (char*)e,
04126                                                                                                                 (char*)new->rr_lst);
04127         atomic_set(&new->refcnt, 0);
04128         new->last_used = now;
04129         /* expire and total_size are fixed later if needed */
04130         /* fix the pointers inside the rr structures */
04131         last_rr = NULL;
04132         for (rr=new->rr_lst; rr; rr=rr->next) {
04133                 rr->rdata = (void*)translate_pointer((char*)new, (char*)e, 
04134                                                                                                 (char*)rr->rdata);
04135                 if (rr->next)
04136                         rr->next = (struct dns_rr*)translate_pointer((char*)new, (char*)e,
04137                                                                                                 (char*)rr->next);
04138                 else
04139                         last_rr = rr;
04140 
04141                 switch(e->type){
04142                         case T_NAPTR:
04143                                 /* there are pointers inside the NAPTR rdata stucture */
04144                                 ((struct naptr_rdata*)rr->rdata)->flags =
04145                                         translate_pointer((char*)new, (char*)e,
04146                                                 ((struct naptr_rdata*)rr->rdata)->flags);
04147 
04148                                 ((struct naptr_rdata*)rr->rdata)->services =
04149                                         translate_pointer((char*)new, (char*)e,
04150                                                 ((struct naptr_rdata*)rr->rdata)->services);
04151 
04152                                 ((struct naptr_rdata*)rr->rdata)->regexp =
04153                                         translate_pointer((char*)new, (char*)e,
04154                                                 ((struct naptr_rdata*)rr->rdata)->regexp);
04155 
04156                                 ((struct naptr_rdata*)rr->rdata)->repl =
04157                                         translate_pointer((char*)new, (char*)e,
04158                                                 ((struct naptr_rdata*)rr->rdata)->repl);
04159                                 break;
04160                         case T_TXT:
04161                                 /* there are pointers inside the TXT structure */
04162                                 for (i=0; i<((struct txt_rdata*)rr->rdata)->cstr_no; i++){
04163                                         ((struct txt_rdata*)rr->rdata)->txt[i].cstr=
04164                                                 translate_pointer((char*) new, (char*) e,
04165                                                         ((struct txt_rdata*)rr->rdata)->txt[i].cstr);
04166                                 }
04167                                 break;
04168                         case T_EBL:
04169                                 /* there are pointers inside the EBL structure */
04170                                 ((struct ebl_rdata*)rr->rdata)->separator =
04171                                         translate_pointer((char*)new, (char*)e,
04172                                                         ((struct ebl_rdata*)rr->rdata)->separator);
04173                                 ((struct ebl_rdata*)rr->rdata)->apex =
04174                                         translate_pointer((char*)new, (char*)e,
04175                                                         ((struct ebl_rdata*)rr->rdata)->apex);
04176                                 break;
04177                 }
04178         }
04179 
04180 
04181         if (rdata_size) {
04182                 /* set the pointer to the new rr structure */
04183                 new_rr = (void*)((char*)new + rounded_size);
04184                 new_rr->rdata = (void*)((char*)new_rr+rr_size);
04185                 new_rr->expire = now + S_TO_TICKS(ttl);
04186                 /* link the rr to the previous one */
04187                 last_rr->next = new_rr;
04188 
04189                 /* fix the total_size and expires values */
04190                 new->total_size=rounded_size+rr_size+rdata_size;
04191                 new->expire = MAX(new->expire, new_rr->expire);
04192 
04193 
04194                 if (_new_rr)
04195                         *_new_rr = new_rr;
04196         } else {
04197                 if (_new_rr)
04198                         *_new_rr = NULL;
04199         }
04200 
04201         return new;
04202 }
04203 
04204 
04205 /* Adds a new record to the cache.
04206  * If there is an existing record with the same name and value
04207  * (ip address in case of A/AAAA record, name in case of SRV record)
04208  * only the remaining fields are updated.
04209  * 
04210  * Note that permanent records cannot be overwritten unless
04211  * the new record is also permanent. A permanent record
04212  * completely replaces a non-permanent one.
04213  *
04214  * Currently only A, AAAA, and SRV records are supported.
04215  */
04216 int dns_cache_add_record(unsigned short type,
04217                         str *name,
04218                         int ttl,
04219                         str *value,
04220                         int priority,
04221                         int weight,
04222                         int port,
04223                         int flags)
04224 {
04225         struct dns_hash_entry *old=NULL, *new=NULL;
04226         struct dns_rr *rr;
04227         str rr_name;
04228         struct ip_addr *ip_addr;
04229         ticks_t expire;
04230         int err, h;
04231         int size;
04232         struct dns_rr   *new_rr, **rr_p, **rr_iter;
04233         struct srv_rdata        *srv_rd;
04234 
04235         /* eliminate gcc warnings */
04236         ip_addr = 0;
04237         size = 0;
04238         rr_name.s = NULL;
04239         rr_name.len = 0;
04240 
04241         if (!cfg_get(core, core_cfg, use_dns_cache)){
04242                 LOG(L_ERR, "ERROR: dns cache support disabled (see use_dns_cache)\n");
04243                 return -1;
04244         }
04245         
04246         if ((type != T_A) && (type != T_AAAA) && (type != T_SRV)) {
04247                 LOG(L_ERR, "ERROR: rr type %d is not implemented\n",
04248                         type);
04249                 return -1;
04250         }
04251 
04252         if ((flags & DNS_FLAG_BAD_NAME) == 0) {
04253                 /* fix-up the values */
04254                 switch(type) {
04255                 case T_A:
04256                         ip_addr = str2ip(value);
04257                         if (!ip_addr) {
04258                                 LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
04259                                         value->len, value->s);
04260                                 return -1;
04261                         }
04262                         break;
04263                 case T_AAAA:
04264 #ifdef USE_IPV6
04265                         ip_addr = str2ip6(value);
04266                         if (!ip_addr) {
04267                                 LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
04268                                         value->len, value->s);
04269                                 return -1;
04270                         }
04271                         break;
04272 #else /* USE_IPV6 */
04273                         LOG(L_ERR, "ERROR: IPv6 support is disabled\n");
04274                         return -1;
04275 #endif /* USE_IPV6 */
04276                 case T_SRV:
04277                         rr_name = *value;
04278                         break;
04279                 }
04280         }
04281 
04282         /* check whether there is a matching entry in the cache */
04283         old = dns_hash_get(name, type, &h, &err);
04284         if (old && old->type!=type) {
04285                 /* probably we found a CNAME instead of the specified type,
04286                 it is not needed */
04287                 dns_hash_put(old);
04288                 old=NULL;
04289         }
04290 
04291         if (old
04292                 && (old->ent_flags & DNS_FLAG_PERMANENT)
04293                 && ((flags & DNS_FLAG_PERMANENT) == 0)
04294         ) {
04295                 LOG(L_ERR, "ERROR: A non-permanent record cannot overwrite "
04296                                 "a permanent entry\n");
04297                 goto error;
04298         }
04299         /* prepare the entry */
04300         if (flags & DNS_FLAG_BAD_NAME) {
04301                 /* negative entry */
04302                 new = dns_cache_mk_bad_entry(name, type, ttl, flags);
04303                 if (!new) {
04304                         LOG(L_ERR, "ERROR: Failed to create a negative "
04305                                         "DNS cache entry\n");
04306                         goto error;
04307                 }
04308         } else {
04309                 if (!old
04310                         || (old->ent_flags & DNS_FLAG_BAD_NAME)
04311                         || (((old->ent_flags & DNS_FLAG_PERMANENT) == 0)
04312                                 && (flags & DNS_FLAG_PERMANENT))
04313                 ) {
04314                         /* There was no matching entry in the hash table,
04315                          * the entry is a negative record with inefficient space,
04316                          * or a permanent entry overwrites a non-permanent one.
04317                          * Let us create a new one.
04318                          */
04319                         switch(type) {
04320                         case T_A:
04321                         case T_AAAA:
04322                                 new = dns_cache_mk_ip_entry(name, ip_addr);
04323                                 if (!new) {
04324                                         LOG(L_ERR, "ERROR: Failed to create an A/AAAA record\n");
04325                                         goto error;
04326                                 }
04327                                 /* fix the expiration time, dns_cache_mk_ip_entry() sets it 
04328                                  * to now-1 */
04329                                 expire = get_ticks_raw() + S_TO_TICKS(ttl);
04330                                 new->expire = expire;
04331                                 new->rr_lst->expire = expire;
04332                                 break;
04333                         case T_SRV:
04334                                 new = dns_cache_mk_srv_entry(name, priority, weight, port,
04335                                                                                                 &rr_name, ttl);
04336                                 if (!new) {
04337                                         LOG(L_ERR, "ERROR: Failed to create an SRV record\n");
04338                                         goto error;
04339                                 }
04340                         }
04341                         new->ent_flags = flags;
04342                 } else {
04343                         /* we must modify the entry, so better to clone it, modify the new 
04344                          * one, and replace the old with the new entry in the hash table,
04345                          * because the entry might be in use (even if the dns hash is 
04346                          * locked). The old entry will be removed from the hash and 
04347                          * automatically destroyed when its refcnt will be 0*/
04348 
04349                         /* check whether there is an rr with the same value */
04350                         for (rr=old->rr_lst; rr; rr=rr->next)
04351                                 if ((((type == T_A) || (type == T_AAAA)) &&
04352                                         (memcmp(ip_addr->u.addr, ((struct a_rdata*)rr->rdata)->ip,
04353                                                                                 ip_addr->len)==0))
04354                                 || ((type == T_SRV) &&
04355                                         (((struct srv_rdata*)rr->rdata)->name_len == rr_name.len)&&
04356                                         (memcmp(rr_name.s, ((struct srv_rdata*)rr->rdata)->name,
04357                                                                                 rr_name.len)==0)))
04358                                 break;
04359 
04360                         if (rr) {
04361                                 /* the rr was found in the list */
04362                                 new = dns_cache_clone_entry(old, 0, 0, 0);
04363                                 if (!new) {
04364                                         LOG(L_ERR, "ERROR: Failed to clone an existing "
04365                                                         "DNS cache entry\n");
04366                                         goto error;
04367                                 }
04368                                 /* let the rr point to the new structure */
04369                                 rr = (struct dns_rr*)translate_pointer((char*)new, (char*)old,
04370                                                                                                                 (char*)rr);
04371                                 new_rr = rr;
04372 
04373                                 if (type == T_SRV) {
04374                                         /* fix the priority, weight, and port */
04375                                         ((struct srv_rdata*)rr->rdata)->priority = priority;
04376                                         ((struct srv_rdata*)rr->rdata)->weight = weight;
04377                                         ((struct srv_rdata*)rr->rdata)->port = port;
04378                                 }
04379 
04380                                 /* fix the expire value */
04381                                 rr->expire = get_ticks_raw() + S_TO_TICKS(ttl);
04382                                 new->expire = 0;
04383                                 for (rr=new->rr_lst; rr; rr=rr->next)
04384                                         new->expire = MAX(new->expire, rr->expire);
04385                         } else {
04386                                 /* there was no matching rr, extend the structure with a new
04387                                  * one */
04388                                 switch(type) {
04389                                 case T_A:
04390                                         size = sizeof(struct a_rdata);
04391                                         break;
04392                                 case T_AAAA:
04393                                         size = sizeof(struct aaaa_rdata);
04394                                         break;
04395                                 case T_SRV:
04396                                         size = sizeof(struct srv_rdata)-1 +
04397                                                 rr_name.len+1;
04398                                         break;
04399                                 }
04400                                 new = dns_cache_clone_entry(old, size, ttl, &rr);
04401                                 if (!new) {
04402                                         LOG(L_ERR, "ERROR: Failed to clone an existing "
04403                                                         "DNS cache entry\n");
04404                                         goto error;
04405                                 }
04406                                 new_rr = rr;
04407 
04408                                 switch(type) {
04409                                 case T_A:
04410                                 case T_AAAA:
04411                                         memcpy(rr->rdata, ip_addr->u.addr, ip_addr->len);
04412                                         break;
04413                                 case T_SRV:
04414                                         ((struct srv_rdata*)rr->rdata)->priority = priority;
04415                                         ((struct srv_rdata*)rr->rdata)->weight = weight;
04416                                         ((struct srv_rdata*)rr->rdata)->port = port;
04417                                         ((struct srv_rdata*)rr->rdata)->name_len = rr_name.len;
04418                                         memcpy(((struct srv_rdata*)rr->rdata)->name, rr_name.s, 
04419                                                                         rr_name.len);
04420                                 }
04421                                 /* maximum expire value has been already fixed by 
04422                                  * dns_cache_clone_entry() */
04423                         }
04424 
04425                         if (type == T_SRV) {
04426                                 /* SRV records must be ordered by their priority and weight.
04427                                  * With modifying an exising rr, or adding new rr to the DNS entry,
04428                                  * the ordered list might got broken which needs to be fixed.
04429                                  */
04430                                 rr_p = NULL;
04431                                 for (   rr_iter = &new->rr_lst;
04432                                         *rr_iter;
04433                                         rr_iter = &((*rr_iter)->next)
04434                                 ) {
04435                                         if (*rr_iter == new_rr) {
04436                                                 rr_p = rr_iter;
04437                                                 continue;
04438                                         }
04439                                         srv_rd = (struct srv_rdata*)(*rr_iter)->rdata;
04440                                         if ((priority < srv_rd->priority) ||
04441                                                 ((priority == srv_rd->priority) && (weight > srv_rd->weight))
04442                                         )
04443                                                 break; /* insert here */
04444                                 }
04445 
04446                                 if (!rr_p)
04447                                         for (   rr_p = rr_iter;
04448                                                 *rr_p && (*rr_p != new_rr);
04449                                                 rr_p = &((*rr_p)->next)
04450                                         );
04451                                 if (!rr_p) {
04452                                         LOG(L_ERR, "ERROR: Failed to correct the orderd list of SRV resource records\n");
04453                                         goto error;
04454                                 }
04455 
04456                                 if (*rr_iter != new_rr->next) {
04457                                         /* unlink rr from the list */
04458                                         *rr_p = (*rr_p)->next;
04459                                         /* link it before *rr_iter */
04460                                         new_rr->next = *rr_iter;
04461                                         *rr_iter = new_rr;
04462                                 }
04463                         }
04464                 }
04465         }
04466 
04467         LOCK_DNS_HASH();
04468         if (dns_cache_add_unsafe(new)) {
04469                 LOG(L_ERR, "ERROR: Failed to add the entry to the cache\n");
04470                 UNLOCK_DNS_HASH();
04471                 goto error;
04472         } else {
04473                 /* remove the old entry from the list */
04474                 if (old)
04475                         _dns_hash_remove(old);
04476         }
04477         UNLOCK_DNS_HASH();
04478 
04479         if (old)
04480                 dns_hash_put(old);
04481         return 0;
04482 
04483 error:
04484         /* leave the old entry in the list, and free the new one */
04485         if (old)
04486                 dns_hash_put(old);
04487         if (new)
04488                 dns_destroy_entry(new);
04489         return -1;
04490 }
04491 
04492 
04493 /* deletes a record from the cache */
04494 static void dns_cache_delete_record(rpc_t* rpc, void* ctx, unsigned short type)
04495 {
04496         struct dns_hash_entry *e;
04497         str name;
04498         int err, h, found=0, permanent=0;
04499 
04500         if (!cfg_get(core, core_cfg, use_dns_cache)){
04501                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04502                 return;
04503         }
04504         
04505         if (rpc->scan(ctx, "S", &name) < 1)
04506                 return;
04507 
04508         LOCK_DNS_HASH();
04509 
04510         e=_dns_hash_find(&name, type, &h, &err);
04511         if (e && (e->type==type)) {
04512                 if ((e->ent_flags & DNS_FLAG_PERMANENT) == 0)
04513                         _dns_hash_remove(e);
04514                 else
04515                         permanent = 1;
04516                 found = 1;
04517         }
04518 
04519         UNLOCK_DNS_HASH();
04520 
04521         if (permanent)
04522                 rpc->fault(ctx, 400, "Permanent entries cannot be deleted");
04523         else if (!found)
04524                 rpc->fault(ctx, 400, "Not found");
04525 }
04526 
04527 /* Delete a single record from the cache,
04528  * i.e. the record with the same name and value
04529  * (ip address in case of A/AAAA record, name in case of SRV record).
04530  *
04531  * Currently only A, AAAA, and SRV records are supported.
04532  */
04533 int dns_cache_delete_single_record(unsigned short type,
04534                         str *name,
04535                         str *value,
04536                         int flags)
04537 {
04538         struct dns_hash_entry *old=NULL, *new=NULL;
04539         struct dns_rr *rr, **next_p;
04540         str rr_name;
04541         struct ip_addr *ip_addr;
04542         int err, h;
04543 
04544         /* eliminate gcc warnings */
04545         rr_name.s = NULL;
04546         rr_name.len = 0;
04547         ip_addr = 0;
04548 
04549         if (!cfg_get(core, core_cfg, use_dns_cache)){
04550                 LOG(L_ERR, "ERROR: dns cache support disabled (see use_dns_cache)\n");
04551                 return -1;
04552         }
04553         
04554         if ((type != T_A) && (type != T_AAAA) && (type != T_SRV)) {
04555                 LOG(L_ERR, "ERROR: rr type %d is not implemented\n",
04556                         type);
04557                 return -1;
04558         }
04559 
04560         if ((flags & DNS_FLAG_BAD_NAME) == 0) {
04561                 /* fix-up the values */
04562                 switch(type) {
04563                 case T_A:
04564                         ip_addr = str2ip(value);
04565                         if (!ip_addr) {
04566                                 LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
04567                                         value->len, value->s);
04568                                 return -1;
04569                         }
04570                         break;
04571                 case T_AAAA:
04572 #ifdef USE_IPV6
04573                         ip_addr = str2ip6(value);
04574                         if (!ip_addr) {
04575                                 LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
04576                                         value->len, value->s);
04577                                 return -1;
04578                         }
04579                         break;
04580 #else /* USE_IPV6 */
04581                         LOG(L_ERR, "ERROR: IPv6 support is disabled\n");
04582                         return -1;
04583 #endif /* USE_IPV6 */
04584                 case T_SRV:
04585                         rr_name = *value;
04586                         break;
04587                 }
04588         }
04589 
04590         /* check whether there is a matching entry in the cache */
04591         if ((old = dns_hash_get(name, type, &h, &err)) == NULL)
04592                 goto not_found;
04593 
04594         if ((old->type != type) /* may be CNAME */
04595                 || (old->ent_flags != flags)
04596         )
04597                 goto not_found;
04598 
04599         if (flags & DNS_FLAG_BAD_NAME) /* negative record, there is no value */
04600                 goto delete;
04601 
04602         /* check whether there is an rr with the same value */
04603         for (rr=old->rr_lst, next_p=&old->rr_lst;
04604                 rr;
04605                 next_p=&rr->next, rr=rr->next
04606         )
04607                 if ((((type == T_A) || (type == T_AAAA)) &&
04608                         (memcmp(ip_addr->u.addr, ((struct a_rdata*)rr->rdata)->ip,
04609                                                                 ip_addr->len)==0))
04610                 || ((type == T_SRV) &&
04611                         (((struct srv_rdata*)rr->rdata)->name_len == rr_name.len) &&
04612                         (memcmp(rr_name.s, ((struct srv_rdata*)rr->rdata)->name,
04613                                                                 rr_name.len)==0)))
04614                 break;
04615 
04616         if (!rr)
04617                 goto not_found;
04618 
04619         if ((rr == old->rr_lst) && (rr->next == NULL)) {
04620                 /* There is a single rr value, hence the whole
04621                  * hash entry can be deleted */
04622                 goto delete;
04623         } else {
04624                 /* we must modify the entry, so better to clone it, modify the new 
04625                 * one, and replace the old with the new entry in the hash table,
04626                 * because the entry might be in use (even if the dns hash is 
04627                 * locked). The old entry will be removed from the hash and 
04628                 * automatically destroyed when its refcnt will be 0*/
04629                 new = dns_cache_clone_entry(old, 0, 0, 0);
04630                 if (!new) {
04631                         LOG(L_ERR, "ERROR: Failed to clone an existing "
04632                                 "DNS cache entry\n");
04633                         dns_hash_put(old);
04634                         return -1;
04635                 }
04636                 /* let rr and next_p point to the new structure */
04637                 rr = (struct dns_rr*)translate_pointer((char*)new,
04638                                                 (char*)old,
04639                                                 (char*)rr);
04640                 next_p = (struct dns_rr**)translate_pointer((char*)new,
04641                                                 (char*)old,
04642                                                 (char*)next_p);
04643                 /* unlink rr from the list. The memory will be freed
04644                  * when the whole record is freed */
04645                 *next_p = rr->next;
04646         }
04647 
04648 delete:
04649         LOCK_DNS_HASH();
04650         if (new) {
04651                 /* delete the old entry only if the new one can be added */
04652                 if (dns_cache_add_unsafe(new)) {
04653                         LOG(L_ERR, "ERROR: Failed to add the entry to the cache\n");
04654                         UNLOCK_DNS_HASH();
04655                         if (old)
04656                                 dns_hash_put(old);
04657                         return -1;
04658                 } else {
04659                         /* remove the old entry from the list */
04660                         if (old)
04661                                 _dns_hash_remove(old);
04662                 }
04663         } else if (old) {
04664                 _dns_hash_remove(old);
04665         }
04666         UNLOCK_DNS_HASH();
04667 
04668         if (old)
04669                 dns_hash_put(old);
04670         return 0;
04671 
04672 not_found:
04673         LOG(L_ERR, "ERROR: No matching record found\n");
04674         if (old)
04675                 dns_hash_put(old);
04676         return -1;
04677 }
04678 
04679 /* performs  a dns lookup over rpc */
04680 void dns_cache_rpc_lookup(rpc_t* rpc, void* ctx)
04681 {
04682         struct dns_hash_entry *e;
04683         str name;
04684         str type;
04685         int t;
04686 
04687         if (!cfg_get(core, core_cfg, use_dns_cache)){
04688                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04689                 return;
04690         }
04691         
04692         if (rpc->scan(ctx, "SS", &type, &name) < 1)
04693                 return;
04694         t=dns_get_type(&type);
04695         if (t<0){
04696                 rpc->fault(ctx, 400, "Invalid type");
04697                 return;
04698         }
04699         e=dns_get_entry(&name, t);
04700         if (e==0){
04701                 rpc->fault(ctx, 400, "Not found");
04702                 return;
04703         }
04704         dns_cache_print_entry(rpc, ctx, e);
04705         dns_hash_put(e);
04706 }
04707 
04708 
04709 
04710 /* wrapper functions for adding and deleting records */
04711 void dns_cache_add_a(rpc_t* rpc, void* ctx)
04712 {
04713         str     name;
04714         int     ttl;
04715         str     ip;
04716         int     flags;
04717 
04718         if (rpc->scan(ctx, "SdSd", &name, &ttl, &ip, &flags) < 4)
04719                 return;
04720 
04721         if (dns_cache_add_record(T_A,
04722                                 &name,
04723                                 ttl,
04724                                 &ip,
04725                                 0 /* priority */,
04726                                 0 /* weight */,
04727                                 0 /* port */,
04728                                 flags)
04729         )
04730                 rpc->fault(ctx, 400, "Failed to add the entry to the cache");
04731 }
04732 
04733 
04734 void dns_cache_add_aaaa(rpc_t* rpc, void* ctx)
04735 {
04736         str     name;
04737         int     ttl;
04738         str     ip;
04739         int     flags;
04740 
04741         if (rpc->scan(ctx, "SdSd", &name, &ttl, &ip, &flags) < 4)
04742                 return;
04743 
04744         if (dns_cache_add_record(T_AAAA,
04745                                 &name,
04746                                 ttl,
04747                                 &ip,
04748                                 0 /* priority */,
04749                                 0 /* weight */,
04750                                 0 /* port */,
04751                                 flags)
04752         )
04753                 rpc->fault(ctx, 400, "Failed to add the entry to the cache");
04754 }
04755 
04756 void dns_cache_add_srv(rpc_t* rpc, void* ctx)
04757 {
04758         str     name;
04759         int     ttl, priority, weight, port;
04760         str     rr_name;
04761         int     flags;
04762 
04763         if (rpc->scan(ctx, "SddddSd", &name, &ttl, &priority, &weight, &port,
04764                                         &rr_name, &flags) < 7
04765         )
04766                 return;
04767 
04768         if (dns_cache_add_record(T_SRV,
04769                                 &name,
04770                                 ttl,
04771                                 &rr_name,
04772                                 priority,
04773                                 weight,
04774                                 port,
04775                                 flags)
04776         )
04777                 rpc->fault(ctx, 400, "Failed to add the entry to the cache");
04778 }
04779 
04780 
04781 
04782 
04783 void dns_cache_delete_a(rpc_t* rpc, void* ctx)
04784 {
04785         dns_cache_delete_record(rpc, ctx, T_A);
04786 }
04787 
04788 
04789 void dns_cache_delete_aaaa(rpc_t* rpc, void* ctx)
04790 {
04791         dns_cache_delete_record(rpc, ctx, T_AAAA);
04792 }
04793 
04794 
04795 void dns_cache_delete_srv(rpc_t* rpc, void* ctx)
04796 {
04797         dns_cache_delete_record(rpc, ctx, T_SRV);
04798 }
04799 
04800 
04801 void dns_cache_delete_naptr(rpc_t* rpc, void* ctx)
04802 {
04803         dns_cache_delete_record(rpc, ctx, T_NAPTR);
04804 }
04805 
04806 
04807 void dns_cache_delete_cname(rpc_t* rpc, void* ctx)
04808 {
04809         dns_cache_delete_record(rpc, ctx, T_CNAME);
04810 }
04811 
04812 
04813 void dns_cache_delete_txt(rpc_t* rpc, void* ctx)
04814 {
04815         dns_cache_delete_record(rpc, ctx, T_TXT);
04816 }
04817 
04818 void dns_cache_delete_ebl(rpc_t* rpc, void* ctx)
04819 {
04820         dns_cache_delete_record(rpc, ctx, T_EBL);
04821 }
04822 
04823 void dns_cache_delete_ptr(rpc_t* rpc, void* ctx)
04824 {
04825         dns_cache_delete_record(rpc, ctx, T_PTR);
04826 }
04827 
04828 
04829 
04830 #ifdef DNS_WATCHDOG_SUPPORT
04831 /* sets the DNS server states */
04832 void dns_set_server_state_rpc(rpc_t* rpc, void* ctx)
04833 {
04834         int     state;
04835 
04836         if (!cfg_get(core, core_cfg, use_dns_cache)){
04837                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04838                 return;
04839         }
04840         if (rpc->scan(ctx, "d", &state) < 1)
04841                 return;
04842         dns_set_server_state(state);
04843 }
04844 
04845 /* prints the DNS server state */
04846 void dns_get_server_state_rpc(rpc_t* rpc, void* ctx)
04847 {
04848         if (!cfg_get(core, core_cfg, use_dns_cache)){
04849                 rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
04850                 return;
04851         }
04852         rpc->add(ctx, "d", dns_get_server_state());
04853 }
04854 #endif /* DNS_WATCHDOG_SUPPORT */
04855 
04856 #endif

Generated on Tue May 22 2012 13:10:06 for SIP Router by  doxygen 1.7.1