提交 b7bc5240 authored 作者: Michael Jerris's avatar Michael Jerris

Fri Jan 23 11:13:41 CST 2009 Pekka Pessi <first.last@nokia.com>

  * sresolv: caching SRES_RECORD_ERR in case a CNAME is returned, too
  
  Tracing the CNAMEs when doing cache lookups.



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11844 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 ba7a77e7
Wed Feb 11 11:08:29 CST 2009 Wed Feb 11 11:12:10 CST 2009
...@@ -42,6 +42,11 @@ _sips._udp SRV 3 100 5061 sip00 ...@@ -42,6 +42,11 @@ _sips._udp SRV 3 100 5061 sip00
SRV 4 50 5051 sip02 SRV 4 50 5051 sip02
SRV 5 10 5061 sip01 SRV 5 10 5061 sip01
cloop CNAME cloop0
cloop0 CNAME cloop1
cloop1 CNAME cloop2
cloop2 CNAME cloop0
sip CNAME sip00 sip CNAME sip00
subnet A6 0 3ff0:0:: subnet A6 0 3ff0:0::
......
...@@ -495,7 +495,9 @@ static int sres_decode_msg(sres_resolver_t *res, ...@@ -495,7 +495,9 @@ static int sres_decode_msg(sres_resolver_t *res,
static char const *sres_toplevel(char buf[], size_t bsize, char const *domain); static char const *sres_toplevel(char buf[], size_t bsize, char const *domain);
static sres_record_t *sres_create_record(sres_resolver_t *, sres_message_t *m); static sres_record_t *sres_create_record(sres_resolver_t *,
sres_message_t *m,
int nth);
static sres_record_t *sres_init_rr_soa(sres_cache_t *cache, static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
sres_soa_record_t *, sres_soa_record_t *,
...@@ -3539,7 +3541,7 @@ sres_decode_msg(sres_resolver_t *res, ...@@ -3539,7 +3541,7 @@ sres_decode_msg(sres_resolver_t *res,
total = errorcount + m->m_ancount + m->m_nscount + m->m_arcount; total = errorcount + m->m_ancount + m->m_nscount + m->m_arcount;
answers = su_zalloc(chome, (total + 1) * sizeof answers[0]); answers = su_zalloc(chome, (total + 2) * sizeof answers[0]);
if (!answers) if (!answers)
return -1; return -1;
...@@ -3548,7 +3550,7 @@ sres_decode_msg(sres_resolver_t *res, ...@@ -3548,7 +3550,7 @@ sres_decode_msg(sres_resolver_t *res,
if (i < errorcount) if (i < errorcount)
rr = error = sres_create_error_rr(res->res_cache, query, err); rr = error = sres_create_error_rr(res->res_cache, query, err);
else else
rr = sres_create_record(res, m); rr = sres_create_record(res, m, i - errorcount);
if (!rr) { if (!rr) {
SU_DEBUG_5(("sres_create_record: %s\n", m->m_error)); SU_DEBUG_5(("sres_create_record: %s\n", m->m_error));
...@@ -3565,12 +3567,31 @@ sres_decode_msg(sres_resolver_t *res, ...@@ -3565,12 +3567,31 @@ sres_decode_msg(sres_resolver_t *res,
} }
if (i < total) { if (i < total) {
SU_DEBUG_5(("sres_decode_msg: %s\n", "less records than promised"));
for (i = 0; i < total; i++) for (i = 0; i < total; i++)
sres_cache_free_record(res->res_cache, answers[i]); sres_cache_free_record(res->res_cache, answers[i]);
su_free(chome, answers); su_free(chome, answers);
return -1; return -1;
} }
if (m->m_ancount > 0 && errorcount == 0 && query->q_type < sres_qtype_tsig) {
char b0[8], b1[8];
for (i = 0; i < m->m_ancount; i++) {
if (query->q_type == answers[i]->sr_type)
break;
}
if (i == m->m_ancount) {
/* The queried request was not found. CNAME? */
SU_DEBUG_5(("sres_decode_msg: sent query %s, got %s\n",
sres_record_type(query->q_type, b0),
sres_record_type(answers[0]->sr_type, b1)));
rr = sres_create_error_rr(res->res_cache, query, err = SRES_RECORD_ERR);
memmove(answers + 1, answers, (sizeof answers[0]) * total++);
answers[errorcount++] = rr;
}
}
for (i = 0; i < total; i++) { for (i = 0; i < total; i++) {
rr = answers[i]; rr = answers[i];
...@@ -3591,7 +3612,7 @@ sres_decode_msg(sres_resolver_t *res, ...@@ -3591,7 +3612,7 @@ sres_decode_msg(sres_resolver_t *res,
static static
sres_record_t * sres_record_t *
sres_create_record(sres_resolver_t *res, sres_message_t *m) sres_create_record(sres_resolver_t *res, sres_message_t *m, int nth)
{ {
sres_cache_t *cache = res->res_cache; sres_cache_t *cache = res->res_cache;
sres_record_t *sr, sr0[1]; sres_record_t *sr, sr0[1];
...@@ -3614,7 +3635,11 @@ sres_create_record(sres_resolver_t *res, sres_message_t *m) ...@@ -3614,7 +3635,11 @@ sres_create_record(sres_resolver_t *res, sres_message_t *m)
name[len] = 0; name[len] = 0;
SU_DEBUG_9(("RR received %s %s %s %d rdlen=%d\n", name, SU_DEBUG_9(("%s RR received %s %s %s %d rdlen=%d\n",
nth < m->m_ancount ? "ANSWER" :
nth < m->m_ancount + m->m_nscount ? "AUTHORITY" :
"ADDITIONAL",
name,
sres_record_type(sr->sr_type, btype), sres_record_type(sr->sr_type, btype),
sres_record_class(sr->sr_class, bclass), sres_record_class(sr->sr_class, bclass),
sr->sr_ttl, sr->sr_rdlen)); sr->sr_ttl, sr->sr_rdlen));
......
...@@ -169,15 +169,98 @@ void sres_cache_unref(sres_cache_t *cache) ...@@ -169,15 +169,98 @@ void sres_cache_unref(sres_cache_t *cache)
su_home_unref(cache->cache_home); su_home_unref(cache->cache_home);
} }
struct frame {
struct frame *previous;
char const *domain;
};
/** Count or get matching records from cache */
static int
sres_cache_get0(sres_htable_t *htable,
sres_rr_hash_entry_t **iter,
uint16_t type,
char const *domain,
time_t now,
sres_record_t **cached,
int len,
struct frame *previous)
{
sres_cname_record_t *cname = NULL;
int dcount = 0, derrorcount = 0, ccount = 0;
for (; iter && *iter; iter = sres_htable_next(htable, iter)) {
sres_record_t *rr = (*iter)->rr;
if (rr == NULL)
continue;
if (now > (*iter)->rr_expires)
continue;
if (rr->sr_name == NULL)
continue;
if (!su_casematch(rr->sr_name, domain))
continue;
if (rr->sr_type == type || type == sres_qtype_any) {
if (rr->sr_status == SRES_RECORD_ERR && type == sres_qtype_any)
continue;
if (cached) {
if (dcount >= len)
return -1;
cached[dcount] = rr, rr->sr_refcount++;
}
dcount++;
if (rr->sr_status)
derrorcount++;
}
if (type != sres_type_cname && rr->sr_type == sres_type_cname) {
if (rr->sr_status == 0)
cname = rr->sr_cname;
}
}
if (cname && dcount == derrorcount) {
/* Nothing found, trace CNAMEs */
struct frame *f, frame = { previous, domain };
unsigned hash = sres_hash_key(domain = cname->cn_cname);
if (cached) {
if (dcount >= len)
return -1;
cached[dcount] = (sres_record_t *)cname;
cname->cn_record->r_refcount++;
}
dcount++;
/* Check for cname loops */
for (f = previous; f; f = f->previous) {
if (su_casematch(domain, f->domain))
break;
}
if (f == NULL) {
ccount = sres_cache_get0(htable, sres_htable_hash(htable, hash),
type, domain, now,
cached ? cached + dcount : NULL,
cached ? len - dcount : 0,
&frame);
}
if (ccount < 0)
return ccount;
}
return dcount + ccount;
}
/** Get a list of matching records from cache. */ /** Get a list of matching records from cache. */
int sres_cache_get(sres_cache_t *cache, int sres_cache_get(sres_cache_t *cache,
uint16_t type, uint16_t type,
char const *domain, char const *domain,
sres_record_t ***return_cached) sres_record_t ***return_cached)
{ {
sres_record_t **result = NULL, *rr = NULL; sres_record_t **result = NULL;
sres_rr_hash_entry_t **rr_iter, **rr_iter2; sres_rr_hash_entry_t **slot;
int result_size, rr_count = 0; int result_size, i, j;
unsigned hash; unsigned hash;
time_t now; time_t now;
char b[8]; char b[8];
...@@ -198,28 +281,16 @@ int sres_cache_get(sres_cache_t *cache, ...@@ -198,28 +281,16 @@ int sres_cache_get(sres_cache_t *cache,
time(&now); time(&now);
/* First pass: just count the number of rr:s for array allocation */ /* First pass: just count the number of rr:s for array allocation */
rr_iter2 = sres_htable_hash(cache->cache_hash, hash); slot = sres_htable_hash(cache->cache_hash, hash);
/* Find the domain records from the hash table */
for (rr_iter = rr_iter2;
rr_iter && *rr_iter;
rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) {
rr = (*rr_iter)->rr;
if (rr != NULL &&
now <= (*rr_iter)->rr_expires &&
(type == sres_qtype_any || rr->sr_type == type) &&
rr->sr_name != NULL &&
su_casematch(rr->sr_name, domain))
rr_count++;
}
if (rr_count == 0) { i = sres_cache_get0(cache->cache_hash, slot, type, domain, now,
NULL, 0, NULL);
if (i <= 0) {
UNLOCK(cache); UNLOCK(cache);
return 0; return 0;
} }
result_size = (sizeof *result) * (rr_count + 1); result_size = (sizeof *result) * (i + 1);
result = su_zalloc(cache->cache_home, result_size); result = su_zalloc(cache->cache_home, result_size);
if (result == NULL) { if (result == NULL) {
UNLOCK(cache); UNLOCK(cache);
...@@ -227,35 +298,30 @@ int sres_cache_get(sres_cache_t *cache, ...@@ -227,35 +298,30 @@ int sres_cache_get(sres_cache_t *cache,
} }
/* Second pass: add the rr pointers to the allocated array */ /* Second pass: add the rr pointers to the allocated array */
j = sres_cache_get0(cache->cache_hash, slot, type, domain, now,
for (rr_iter = rr_iter2, rr_count = 0; result, i, NULL);
rr_iter && *rr_iter; if (i != j) {
rr_iter = sres_htable_next(cache->cache_hash, rr_iter)) { /* Uh-oh. */
rr = (*rr_iter)->rr; SU_DEBUG_9(("%s(%p, %s, \"%s\") got %d != %d\n", "sres_cache_get",
(void *)cache, sres_record_type(type, b), domain, i, j));
if (rr != NULL && for (i = 0; i < result_size; i++) {
now <= (*rr_iter)->rr_expires && if (result[i])
(type == sres_qtype_any || rr->sr_type == type) && result[i]->sr_refcount--;
rr->sr_name != NULL &&
su_casematch(rr->sr_name, domain)) {
SU_DEBUG_9(("rr found in cache: %s %02d\n",
rr->sr_name, rr->sr_type));
result[rr_count++] = rr;
rr->sr_refcount++;
} }
su_free(cache->cache_home, result);
return 0;
} }
result[rr_count] = NULL; result[i] = NULL;
UNLOCK(cache); UNLOCK(cache);
SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get", SU_DEBUG_9(("%s(%p, %s, \"%s\") returned %d entries\n", "sres_cache_get",
(void *)cache, sres_record_type(type, b), domain, rr_count)); (void *)cache, sres_record_type(type, b), domain, i));
*return_cached = result; *return_cached = result;
return rr_count; return i;
} }
sres_record_t * sres_record_t *
......
...@@ -90,6 +90,10 @@ typedef unsigned _int32 uint32_t; ...@@ -90,6 +90,10 @@ typedef unsigned _int32 uint32_t;
#include <signal.h> #include <signal.h>
#endif #endif
#include <sofia-sip/su_log.h>
extern su_log_t sresolv_log[];
char const name[] = "test_sresolv"; char const name[] = "test_sresolv";
struct sres_context_s struct sres_context_s
...@@ -982,24 +986,133 @@ int test_srv(sres_context_t *ctx) ...@@ -982,24 +986,133 @@ int test_srv(sres_context_t *ctx)
int test_cname(sres_context_t *ctx) int test_cname(sres_context_t *ctx)
{ {
sres_resolver_t *res = ctx->resolver; sres_resolver_t *res = ctx->resolver;
sres_record_t **result; sres_record_t **result, *sr;
const sres_cname_record_t *rr; const sres_cname_record_t *cn;
char const *domain = "sip.example.com"; char const *domain = "sip.example.com";
BEGIN(); BEGIN();
TEST_1(sres_query(res, test_answer, ctx, sres_type_naptr, domain));
TEST_RUN(ctx);
TEST_1(result = ctx->result);
TEST_1(sr = result[0]);
TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
TEST_1(cn = result[1]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "sip00.example.com.");
sres_free_answers(res, ctx->result), ctx->result = NULL;
TEST_1(result = sres_cached_answers(res, sres_type_naptr, domain));
TEST_1(sr = result[0]);
TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
TEST_1(cn = result[1]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "sip00.example.com.");
sres_free_answers(res, result), ctx->result = NULL;
TEST_1(result = sres_cached_answers(res, sres_qtype_any, domain));
TEST_1(cn = result[0]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "sip00.example.com.");
/* We might have A record, or then not */
sres_free_answers(res, result), ctx->result = NULL;
TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
TEST_RUN(ctx);
TEST_1(result = ctx->result);
TEST_1(cn = result[0]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "sip00.example.com.");
TEST_1(sr = result[1]);
TEST(sr->sr_record->r_class, sres_class_in);
TEST(sr->sr_record->r_type, sres_type_a);
sres_free_answers(res, ctx->result), ctx->result = NULL;
TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
TEST_1(cn = result[0]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "sip00.example.com.");
TEST_1(sr = result[1]);
TEST(sr->sr_record->r_class, sres_class_in);
TEST(sr->sr_record->r_type, sres_type_a);
sres_free_answers(res, result);
domain = "cloop.example.com";
TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain)); TEST_1(sres_query(res, test_answer, ctx, sres_type_a, domain));
TEST_RUN(ctx); TEST_RUN(ctx);
TEST_1(result = ctx->result); TEST_1(result = ctx->result);
TEST_1(rr = result[0]->sr_cname); TEST_1(sr = result[0]);
TEST(rr->cn_record->r_class, sres_class_in); TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
TEST(rr->cn_record->r_type, sres_type_cname); TEST_1(cn = result[1]->sr_cname);
TEST(rr->cn_record->r_ttl, 60); TEST(cn->cn_record->r_class, sres_class_in);
TEST_S(rr->cn_cname, "sip00.example.com."); TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop0.example.com.");
TEST_1(cn = result[2]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop1.example.com.");
TEST_1(cn = result[3]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop2.example.com.");
TEST_1(cn = result[4]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop0.example.com.");
TEST_1(result[5] == NULL);
sres_free_answers(res, ctx->result), ctx->result = NULL; sres_free_answers(res, ctx->result), ctx->result = NULL;
TEST_1(result = sres_cached_answers(res, sres_type_a, domain));
TEST_1(sr = result[0]);
TEST_1(sr->sr_record->r_status == SRES_RECORD_ERR);
TEST_1(cn = result[1]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop0.example.com.");
TEST_1(cn = result[2]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop1.example.com.");
TEST_1(cn = result[3]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop2.example.com.");
TEST_1(cn = result[4]->sr_cname);
TEST(cn->cn_record->r_class, sres_class_in);
TEST(cn->cn_record->r_type, sres_type_cname);
TEST(cn->cn_record->r_ttl, 60);
TEST_S(cn->cn_cname, "cloop0.example.com.");
TEST_1(result[5] == NULL);
sres_free_answers(res, result);
END(); END();
} }
...@@ -1892,10 +2005,6 @@ void usage(int exitcode) ...@@ -1892,10 +2005,6 @@ void usage(int exitcode)
exit(exitcode); exit(exitcode);
} }
#include <sofia-sip/su_log.h>
extern su_log_t sresolv_log[];
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int i; int i;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论