📄 dns_cash.c.svn-base
字号:
/* include files declaration */
#include <l3/inc/phase2.h>
#include <l3/ap/dnsr/h/dns.h>
#include <l3/ap/dnsr/h/dnsr_if.h>
/*-----------------------------------------------------------------------
* Local Variables
*-----------------------------------------------------------------------
*/
#define DNS_CACHE_SIZE 11
/* Global variables */
static UI32_T dns_cache_count;
static I32_T dns_gc_mark_time;
static I32_T dns_gc_sweep_time;
static struct dns_rr *dns_cache[DNS_CACHE_SIZE];
/* external variables declaration */
/* external functions declaration */
/*-----------------------------------------------------------------------
* Functions
*-----------------------------------------------------------------------
*/
/*
* This entire module is only included both DNS and its cache are installed.
*/
/*
* Reinventing the wheel for more portable programs.
* If you're not using ASCII, you'll have to redefine these.
*/
#ifndef GLUE_ISUPPER
#define GLUE_ISUPPER(_c_) \
((_c_) >= 'A' && (_c_) <= 'Z')
#endif /* GLUE_ISUPPER */
#ifndef GLUE_LOWER
#define GLUE_LOWER(_c_) \
((_c_) + 'a' - 'A')
#endif /* GLUE_LOWER */
/*
* Compute hash value from DNS name. Hash is case-insensitive.
* Assumes there are no indirection pointers in tne name.
*
* As a compile-time optimization, if DNS_CACHE_SIZE == 1, we
* return 0 immediately and the hash table degenerates to an unsorted
* linked list. This might be appropriate if your application is
* tight on memory and doesn't need a big cache.
*/
#if DNS_CACHE_SIZE == 1
#define dns_hash(_ignored_) (0)
#else /* DNS_CACHE_SIZE == 1 */
static unsigned dns_hash(unsigned char *name)
{
unsigned result = 0;
int i, n;
#if DNSR_DEBUG
char buffer[DNS_MAX_DOMAIN_NAME];
buffer[0] = 0;
if ((i = dns_decode_name(buffer, sizeof(buffer), name, 0, 0)) < 0)
DBG_L3_Printf("dns_hash(): error %d decoding name\n", i);
#endif /* DEBUG */
while ((n = *name) != 0)
{
result += n;
for (i = 1; i <= n; ++i)
result += (GLUE_ISUPPER(name[i]) ? GLUE_LOWER(name[i]) : name[i]);
name += n + 1;
}
#if DNSR_DEBUG
DBG_L3_Printf("dns_hash(%s) = %d\n", buffer, result % DNS_CACHE_SIZE);
#endif /* DEBUG */
return result % DNS_CACHE_SIZE;
}
#endif /* DNS_CACHE_SIZE == 1 */
/*
* For "well-known" RR types the RFCs require us to handle compression
* pointers within the RDATA portion of an RR. We have to get rid of
* the compression pointers when caching.
*/
/*
* Return length of uncompressed encoded name, or zero to indicate an error.
* If destination is 0, just computes uncompressed length without copying.
*/
static int dns_uncompress_name
(unsigned char *destination,
unsigned char *name,
unsigned char *msg,
unsigned msg_len)
{
unsigned result = 0;
if (name == 0)
return 0;
while (*name != 0)
{
switch (*name & DNS_COMPRESSION_MASK)
{
case DNS_COMPRESSION_POINTER:
if (msg == 0)
return 0;
name = msg + ((name[0] & ~DNS_COMPRESSION_MASK) << 8) + name[1];
if (name >= msg + msg_len)
return 0;
continue;
case 0:
if (destination != 0)
{
memcpy((char *) destination, (char *) name, (int) (*name + 1));
destination += *name + 1;
}
result += *name + 1;
name += *name + 1;
continue;
default:
return 0;
} /* switch */
} /* while */
if (destination != 0)
*destination = 0;
return result + 1;
}
/*
* Uncompress the RDATA portion of an RR. If buffer is 0, no
* copying takes place. Returns status code, updates *rdcount.
*/
static enum dns_error dns_uncompress_rdata
(unsigned char *buffer,
struct dns_rr *rr,
unsigned char *msg,
unsigned msg_len,
unsigned *rdcount)
{
unsigned char *rdata = rr->rdata;
char *format = 0;
int n;
if (rr == 0 || msg == 0 || rdcount == 0)
return DNS_ERROR_BAD_ARGS;
/*
* At present all the RRs that need RDATA expansion consist of one
* or more DNS names combined with some small fixed number of data
* bytes. The easiest way to handle this without massive code
* duplication is a format-driven loop. None of the RR types that
* need expansion are class-specific, which simplifies things.
*/
switch (rr->type)
{
case DNS_T_SOA: /* Two domain names and five 32-bit numbers */
format = "ddhhhhhhhhhh";
break;
case DNS_T_MX: /* One 16-bit number and one domain name */
format = "hd";
break;
case DNS_T_CNAME: /* One domain name */
case DNS_T_PTR:
case DNS_T_NS:
case DNS_T_MB:
case DNS_T_MG:
case DNS_T_MR:
format = "d";
break;
case DNS_T_MINFO: /* Two domain names */
format = "dd";
break;
} /* switch */
/*
* Default case, no expansion needed, old rdcount ok.
*/
if (format == 0)
{
if (buffer != 0)
memcpy(buffer, rr->rdata, rr->rdcount);
*rdcount = rr->rdcount;
return DNS_ERROR_OK;
}
/*
* Expand according to format.
*/
*rdcount = 0;
while (*format != '\0')
{
switch (*format++)
{
case 'h': /* Two bytes */
if (buffer != 0)
{
*buffer++ = rdata[0];
*buffer++ = rdata[1];
}
rdata += 2;
*rdcount += 2;
continue;
case 'd': /* A domain name */
if ((n = dns_uncompress_name(buffer, rdata, msg, msg_len)) == 0)
return DNS_ERROR_BAD_NAME;
*rdcount += n;
if (buffer != 0)
buffer += n;
if ((n = dns_decode_name(0, 0, rdata, msg, msg_len)) < 0)
return n;
rdata += n;
continue;
default: /* Anything else */
return DNS_ERROR_IMPOSSIBLE;
} /* switch */
} /* while */
return DNS_ERROR_OK;
}
/*------------------------------------------------------------------------
* dns_lookup()
* Purpose: Routine to look up cache entries.
*
* Parameters:
* Input:
* Output:
* returns :
*------------------------------------------------------------------------
*/
int dns_lookup
(unsigned char *qname, /* Query name */
unsigned qclass, /* Query type */
unsigned qtype, /* Query class */
struct dns_rr *rrs[], /* Where to put results */
int max_rrs) /* Length of rrs[] */
{
struct dns_rr *r;
int n_rrs = 0;
if (qname == 0 || rrs == 0)
return (int) DNS_ERROR_BAD_ARGS;
/*
* Come here when we've found a CNAME and have to restart the search.
*/
restart_cname:
/*
* Look in the appropriate bucket.
*/
for (r = dns_cache[dns_hash(qname)]; r != 0; r = r->next)
{
int t_matched = dns_t_match(qtype, r->type);
/*
* If this RR isn't relevant to our search or has timed out, keep looking.
*/
if (!dns_ttl_valid(r, GLUE_NOW()) || !dns_c_match(qclass, r->class) ||
(r->negative ? (!t_matched): (!t_matched && r->type != DNS_T_CNAME)) ||
dns_namcmp(qname, 0, 0, r->name, 0, 0) != 0)
continue;
/*
* If we found a negative cache entry, return its error code.
*/
if (r->negative)
return r->errcode;
/*
* Normal RR, add it to list if there's room.
*/
if (n_rrs >= max_rrs)
return (int) DNS_ERROR_TRUNCATED;
rrs[n_rrs++] = r;
/*
* If we found a CNAME instead of a match, restart the search with
* this RR's RDATA as the new QNAME. It's not legal for any other
* RRs to exist with the same name and class as a CNAME RR, so
* it's ok for us to just break out of the current search.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -