- 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:
parent
5cefee8192
commit
ed3ea029e3
@ -1,5 +1,8 @@
|
|||||||
0.6.0
|
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
|
16-Aug-2007: - added comment in siproxd.conf about hosts_allow_sip
|
||||||
30-Jun-2007: - some come cleanup in log.c (Bob Beers)
|
30-Jun-2007: - some come cleanup in log.c (Bob Beers)
|
||||||
22-Jun-2007: - fixed an error in "my via"detection when using the
|
22-Jun-2007: - fixed an error in "my via"detection when using the
|
||||||
|
|||||||
@ -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 URL_STRING_SIZE 128 /* max size of an URL/URI string */
|
||||||
#define STATUSCODE_SIZE 5 /* size of string representation of status */
|
#define STATUSCODE_SIZE 5 /* size of string representation of status */
|
||||||
#define DNS_CACHE_SIZE 256 /* number of entries in internal DNS cache */
|
#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_CACHE_SIZE 32 /* number of entries in internal IFADR cache */
|
||||||
#define IFADR_MAX_AGE 5 /* max. age of the IF address cache (sec) */
|
#define IFADR_MAX_AGE 5 /* max. age of the IF address cache (sec) */
|
||||||
#define IFNAME_SIZE 16 /* max string length of a interface name */
|
#define IFNAME_SIZE 16 /* max string length of a interface name */
|
||||||
|
|||||||
73
src/utils.c
73
src/utils.c
@ -23,6 +23,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <values.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -62,8 +63,8 @@ extern int h_errno;
|
|||||||
* STS_FAILURE on failure
|
* STS_FAILURE on failure
|
||||||
*/
|
*/
|
||||||
int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
||||||
int i, j;
|
int i, j, k;
|
||||||
time_t t;
|
time_t t1, t2;
|
||||||
struct hostent *hostentry;
|
struct hostent *hostentry;
|
||||||
#if defined(HAVE_GETHOSTBYNAME_R)
|
#if defined(HAVE_GETHOSTBYNAME_R)
|
||||||
struct hostent result_buffer;
|
struct hostent result_buffer;
|
||||||
@ -71,8 +72,9 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
|||||||
#endif
|
#endif
|
||||||
int error;
|
int error;
|
||||||
static struct {
|
static struct {
|
||||||
time_t timestamp;
|
time_t expires_timestamp; /* time of expiration */
|
||||||
struct in_addr addr;
|
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];
|
char hostname[HOSTNAME_SIZE+1];
|
||||||
} dns_cache[DNS_CACHE_SIZE];
|
} dns_cache[DNS_CACHE_SIZE];
|
||||||
static int cache_initialized=0;
|
static int cache_initialized=0;
|
||||||
@ -94,11 +96,11 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
|||||||
cache_initialized=1;
|
cache_initialized=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
time(&t);
|
time(&t1);
|
||||||
/* clean expired entries */
|
/* clean expired entries */
|
||||||
for (i=0; i<DNS_CACHE_SIZE; i++) {
|
for (i=0; i<DNS_CACHE_SIZE; i++) {
|
||||||
if (dns_cache[i].hostname[0]=='\0') continue;
|
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);
|
DEBUGC(DBCLASS_DNS, "cleaning DNS cache (entry %i)", i);
|
||||||
memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
|
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 (dns_cache[i].hostname[0]=='\0') continue; /* empty */
|
||||||
if (strcasecmp(hostname, dns_cache[i].hostname) == 0) { /* match */
|
if (strcasecmp(hostname, dns_cache[i].hostname) == 0) { /* match */
|
||||||
memcpy(addr, &dns_cache[i].addr, sizeof(struct in_addr));
|
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",
|
DEBUGC(DBCLASS_DNS, "DNS lookup - from cache: %s -> %s",
|
||||||
hostname, utils_inet_ntoa(*addr));
|
hostname, utils_inet_ntoa(*addr));
|
||||||
return STS_SUCCESS;
|
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()
|
/* need to deal with reentrant versions of gethostbyname_r()
|
||||||
* as we may use threads... */
|
* as we may use threads... */
|
||||||
@ -156,6 +164,8 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
|||||||
#else
|
#else
|
||||||
#error "need gethostbyname() or gethostbyname_r()"
|
#error "need gethostbyname() or gethostbyname_r()"
|
||||||
#endif
|
#endif
|
||||||
|
/* Here I have 'hostentry' and 'error' */
|
||||||
|
|
||||||
|
|
||||||
if (hostentry==NULL) {
|
if (hostentry==NULL) {
|
||||||
/*
|
/*
|
||||||
@ -163,8 +173,6 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
|||||||
* From the manpage:
|
* From the manpage:
|
||||||
* HOST_NOT_FOUND
|
* HOST_NOT_FOUND
|
||||||
* The specified host is unknown.
|
* The specified host is unknown.
|
||||||
* HOST_NOT_FOUND
|
|
||||||
* The specified host is unknown.
|
|
||||||
* NO_ADDRESS or NO_DATA
|
* NO_ADDRESS or NO_DATA
|
||||||
* The requested name is valid but does not have an IP
|
* The requested name is valid but does not have an IP
|
||||||
* address.
|
* 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);
|
ERROR("gethostbyname(%s) failed: h_errno=%i",hostname, h_errno);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return STS_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(addr, hostentry->h_addr, sizeof(struct in_addr));
|
if (hostentry) {
|
||||||
DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s",
|
memcpy(addr, hostentry->h_addr, sizeof(struct in_addr));
|
||||||
hostname, utils_inet_ntoa(*addr));
|
DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s",
|
||||||
|
hostname, utils_inet_ntoa(*addr));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find an empty slot in the cache
|
* find an empty slot in the cache
|
||||||
*/
|
*/
|
||||||
j=0;
|
j=0;
|
||||||
|
k=0;
|
||||||
|
t1=MAXINT;
|
||||||
|
t2=MAXINT;
|
||||||
for (i=0; i<DNS_CACHE_SIZE; i++) {
|
for (i=0; i<DNS_CACHE_SIZE; i++) {
|
||||||
if (dns_cache[i].hostname[0]=='\0') break;
|
if (dns_cache[i].hostname[0]=='\0') break;
|
||||||
if (dns_cache[i].timestamp < t) {
|
if ((dns_cache[i].expires_timestamp < t1) &&
|
||||||
/* remember oldest entry */
|
(dns_cache[i].bad_entry == 0)) {
|
||||||
t=dns_cache[i].timestamp;
|
/* remember oldest good entry */
|
||||||
j=i;
|
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 no empty slot found, victimize oldest one.
|
||||||
if (i >= DNS_CACHE_SIZE) i=j;
|
* 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
|
* 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);
|
DEBUGC(DBCLASS_DNS, "DNS lookup - store into cache, entry %i)", i);
|
||||||
memset(&dns_cache[i], 0, sizeof(dns_cache[0]));
|
memset(&dns_cache[i], 0, sizeof(dns_cache[0]));
|
||||||
strncpy(dns_cache[i].hostname, hostname, HOSTNAME_SIZE);
|
strncpy(dns_cache[i].hostname, hostname, HOSTNAME_SIZE);
|
||||||
time(&dns_cache[i].timestamp);
|
if (hostentry) {
|
||||||
memcpy(&dns_cache[i].addr, addr, sizeof(struct in_addr));
|
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;
|
return STS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user