diff --git a/ChangeLog b/ChangeLog index 79e467e..3a2477a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 0.6.0 ===== + 03-Sep-2007: - keep failed DNS attempts in cache for 10 minutes. + This should protect from repeating DNS timeouts to + caused by broken DNS server (possible DOS) 16-Aug-2007: - added comment in siproxd.conf about hosts_allow_sip 30-Jun-2007: - some come cleanup in log.c (Bob Beers) 22-Jun-2007: - fixed an error in "my via"detection when using the diff --git a/src/siproxd.h b/src/siproxd.h index 5f1c03f..c7734da 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -260,7 +260,8 @@ int sip_message_set_body(osip_message_t * sip, const char *buf, size_t len); #define URL_STRING_SIZE 128 /* max size of an URL/URI string */ #define STATUSCODE_SIZE 5 /* size of string representation of status */ #define DNS_CACHE_SIZE 256 /* number of entries in internal DNS cache */ -#define DNS_MAX_AGE 60 /* maximum age of an cache entry (sec) */ +#define DNS_GOOD_AGE 60 /* maximum age of a good cache entry (sec) */ +#define DNS_BAD_AGE 600 /* maximum age of a bad cache entry (sec) */ #define IFADR_CACHE_SIZE 32 /* number of entries in internal IFADR cache */ #define IFADR_MAX_AGE 5 /* max. age of the IF address cache (sec) */ #define IFNAME_SIZE 16 /* max string length of a interface name */ diff --git a/src/utils.c b/src/utils.c index e7fe3d8..d318ee9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -62,8 +63,8 @@ extern int h_errno; * STS_FAILURE on failure */ int get_ip_by_host(char *hostname, struct in_addr *addr) { - int i, j; - time_t t; + int i, j, k; + time_t t1, t2; struct hostent *hostentry; #if defined(HAVE_GETHOSTBYNAME_R) struct hostent result_buffer; @@ -71,8 +72,9 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { #endif int error; static struct { - time_t timestamp; - struct in_addr addr; + time_t expires_timestamp; /* time of expiration */ + struct in_addr addr; /* IP address or 0.0.0.0 if a bad entry */ + char bad_entry; /* != 0 if resolving failed */ char hostname[HOSTNAME_SIZE+1]; } dns_cache[DNS_CACHE_SIZE]; static int cache_initialized=0; @@ -94,11 +96,11 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { cache_initialized=1; } - time(&t); + time(&t1); /* clean expired entries */ for (i=0; i %s", - hostname, utils_inet_ntoa(*addr)); + hostname, utils_inet_ntoa(*addr)); return STS_SUCCESS; } } - /* did not find it in cache, so I have to resolve it */ + /* I did not find it in cache, so I have to resolve it */ + error = 0; /* need to deal with reentrant versions of gethostbyname_r() * as we may use threads... */ @@ -156,6 +164,8 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { #else #error "need gethostbyname() or gethostbyname_r()" #endif + /* Here I have 'hostentry' and 'error' */ + if (hostentry==NULL) { /* @@ -163,8 +173,6 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { * From the manpage: * HOST_NOT_FOUND * The specified host is unknown. - * HOST_NOT_FOUND - * The specified host is unknown. * NO_ADDRESS or NO_DATA * The requested name is valid but does not have an IP * address. @@ -187,27 +195,42 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { ERROR("gethostbyname(%s) failed: h_errno=%i",hostname, h_errno); #endif } - return STS_FAILURE; } - memcpy(addr, hostentry->h_addr, sizeof(struct in_addr)); - DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s", - hostname, utils_inet_ntoa(*addr)); + if (hostentry) { + memcpy(addr, hostentry->h_addr, sizeof(struct in_addr)); + DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s", + hostname, utils_inet_ntoa(*addr)); + } /* * find an empty slot in the cache */ j=0; + k=0; + t1=MAXINT; + t2=MAXINT; for (i=0; i= DNS_CACHE_SIZE) i=j; + /* if no empty slot found, victimize oldest one. + * Give preference to the oldest "bad" entry if + * one exists */ + if (i >= DNS_CACHE_SIZE) { + if (k > 0) i=k; + else i=j; + } /* * store the result in the cache @@ -215,9 +238,13 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { DEBUGC(DBCLASS_DNS, "DNS lookup - store into cache, entry %i)", i); memset(&dns_cache[i], 0, sizeof(dns_cache[0])); strncpy(dns_cache[i].hostname, hostname, HOSTNAME_SIZE); - time(&dns_cache[i].timestamp); - memcpy(&dns_cache[i].addr, addr, sizeof(struct in_addr)); - + if (hostentry) { + dns_cache[i].expires_timestamp = time(NULL) + DNS_GOOD_AGE; + memcpy(&dns_cache[i].addr, addr, sizeof(struct in_addr)); + } else { + dns_cache[i].expires_timestamp = time(NULL) + DNS_BAD_AGE; + dns_cache[i].bad_entry = 1; + } return STS_SUCCESS; }