- keep failed DNS attempts in cache for 10 minutes.

This should protect from repeating DNS timeouts to
  caused by broken DNS server (possible DOS)
This commit is contained in:
Thomas Ries 2007-09-03 19:55:11 +00:00
parent 5cefee8192
commit ed3ea029e3
3 changed files with 55 additions and 24 deletions

View File

@ -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

View File

@ -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 */

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <values.h>
#include <time.h>
#include <signal.h>
#include <string.h>
@ -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<DNS_CACHE_SIZE; i++) {
if (dns_cache[i].hostname[0]=='\0') continue;
if ( (dns_cache[i].timestamp+DNS_MAX_AGE) < t ) {
if ( (dns_cache[i].expires_timestamp) < t1 ) {
DEBUGC(DBCLASS_DNS, "cleaning DNS cache (entry %i)", i);
memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
}
@ -111,13 +113,19 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
if (dns_cache[i].hostname[0]=='\0') continue; /* empty */
if (strcasecmp(hostname, dns_cache[i].hostname) == 0) { /* match */
memcpy(addr, &dns_cache[i].addr, sizeof(struct in_addr));
if (dns_cache[i].bad_entry) {
DEBUGC(DBCLASS_DNS, "DNS lookup - bad entry from cache: %s",
hostname);
return STS_FAILURE;
}
DEBUGC(DBCLASS_DNS, "DNS lookup - from cache: %s -> %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++) {
if (dns_cache[i].hostname[0]=='\0') break;
if (dns_cache[i].timestamp < t) {
/* remember oldest entry */
t=dns_cache[i].timestamp;
j=i;
if ((dns_cache[i].expires_timestamp < t1) &&
(dns_cache[i].bad_entry == 0)) {
/* remember oldest good entry */
t1=dns_cache[i].expires_timestamp;
j=i;
} else
if (dns_cache[i].expires_timestamp < t2) {
/* remember oldest bad entry */
t2=dns_cache[i].expires_timestamp;
k=i;
}
}
/* if no empty slot found, take oldest one */
if (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;
}