3proxy/src/hashtables.c
Vladimir Dubrovin d5e78a0900 resolver: the system's name servers and hosts file by default
Without nserver (or fakeresolve) names were resolved by the C library.
3proxy's own resolver is now the default, with the system's name
servers: up to 3 from /etc/resolv.conf, on Windows from the registry
(set for the system, set for an interface with an address, Tcpip6
interfaces, then those DHCP gave). With none found, the C library as
before. nserver takes up to 3 as well (MAXNSERVERS), a fourth is
warned about.

The name servers in force belong to the process, not a configuration:
nserver lines are kept aside while a configuration is read and replace
them only once it is committed, so a reload resolves with those in
force until then. Resolutions and dnspr read a copy of them.

The system's are read at start, before the configuration and a chroot
in it, and are in force while it is read, so its host names resolve
with them; read again at a commit, and checked every 5 seconds from
the main loop while the default is in force. What cannot be read then
(within a chroot) stays as last read.

The hosts file, read with them, is imported into tables of its own
while the default is in force: its first address of a family for a
name. A name is looked up as one nsrecord made first, then the hosts
file, then the name cache, then name servers. A changed file replaces
what was imported. No name cache is made for it: without nscache
nothing is cached, as before.

The name cache's keys are host names of any case now: DNS names are.

Tests: sysdns, a name of the hosts file answered by dnspr without
nserver, in any case, and not with one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:49:21 +03:00

100 lines
4.7 KiB
C

#include "proxy.h"
#include "mdhash.h"
static void char_index2hash(const struct hashtable *ht, void *index, uint8_t *hash){
int len;
unsigned int blen;
len = strlen((const char*)index);
memset(hash, 0, ht->hash_size);
if(len <= ht->hash_size) memcpy(hash, index, len);
else {
mdh_ctx *bctx = mdh_init(MDH_BLAKE2, ht->hash_size);
if(!bctx) return;
mdh_update(bctx, index, (unsigned int)(strlen((const char*)index) + 1));
blen = ht->hash_size;
mdh_final(bctx, hash, &blen);
mdh_free(bctx);
}
}
/* A host name, whose case does not matter: hashed as lower case */
static void dns_index2hash(const struct hashtable *ht, void *index, uint8_t *hash){
char low[1024];
size_t i, len = strlen((const char *)index);
if(len >= sizeof(low)) {
char_index2hash(ht, index, hash);
return;
}
for(i = 0; i <= len; i++) low[i] = (char)tolower(((unsigned char *)index)[i]);
char_index2hash(ht, low, hash);
}
static void param2hash_add(const struct hashtable *ht, void *index, uint8_t *hash){
struct clientparam *param = (struct clientparam *)index;
memcpy(hash, param->hash, ht->hash_size);
}
void param2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
struct clientparam *param = (struct clientparam *)index;
unsigned type = param->srv->authcachetype;
int oplen = 0, acllen = 0, ulen = 0, plen = 0, hlen = 0, a1len = 0, a2len = 0, a3len = 0, p1len=0, p2len = 0;
if((type & 2) && *param->username) ulen = strlen((const char *)param->username) + 1;
if((type & 4) && *param->password) plen = strlen((const char *)param->password) + 1;
if((type & 1) && !(type & 8)) a1len = SAADDRLEN(&param->sincr);
if((type & 16)) acllen = sizeof(param->srv->acl);
if((type & 64)) a2len = SAADDRLEN(&param->req);
if((type & 128)) p1len = 2 ;
if((type & 256) && *param->hostname) hlen = strlen((const char *)param->hostname) + 1;
if((type & 512)) oplen = sizeof(param->operation);
if((type & 1024)) a3len = SAADDRLEN(&param->srv->intsa);
if((type & 2048)) p2len = 2;
memset(hash, 0, ht->hash_size);
if(ulen + plen + a1len + acllen + a2len + p1len + hlen + oplen + a3len + p2len <= ht->hash_size){
int offset = 0;
if((type & 2) && *param->username){ memcpy(hash + offset, param->username, ulen); offset += ulen; }
if((type & 4) && *param->password){ memcpy(hash + offset, param->password, plen); offset += plen; }
if((type & 1) && !(type & 8)){ memcpy(hash + offset, SAADDR(&param->sincr), a1len); offset += a1len; }
if((type & 16)){ memcpy(hash + offset, &param->srv->acl, acllen); offset += acllen; }
if((type & 64)){ memcpy(hash + offset, SAADDR(&param->req), a2len); offset += a2len; }
if((type & 128)){ memcpy(hash + offset, SAPORT(&param->req), p1len); offset += 2; }
if((type & 256) && *param->hostname){ memcpy(hash + offset, param->hostname, hlen); offset += hlen; }
if((type & 512)){ memcpy(hash + offset, &param->operation, oplen); offset += oplen; }
if((type & 1024)){ memcpy(hash + offset, SAADDR(&param->srv->intsa), a3len); offset += a3len; }
if((type & 2048)){ memcpy(hash + offset, SAPORT(&param->srv->intsa), p2len); offset += 2; }
}
else {
mdh_ctx *bctx = mdh_init(MDH_BLAKE2, ht->hash_size);
unsigned int blen = ht->hash_size;
if(!bctx) { memcpy(param->hash, hash, ht->hash_size); return; }
if((type & 2) && *param->username)mdh_update(bctx, param->username, ulen);
if((type & 4) && *param->password)mdh_update(bctx, param->password, plen);
if((type & 1) && !(type & 8))mdh_update(bctx, SAADDR(&param->sincr), a1len);
if((type & 16))mdh_update(bctx, &param->srv->acl, acllen);
if((type & 64))mdh_update(bctx, SAADDR(&param->req), a2len);
if((type & 128))mdh_update(bctx, SAPORT(&param->req), 2);
if((type & 256) && *param->hostname)mdh_update(bctx, param->hostname, hlen);
if((type & 512))mdh_update(bctx, &param->operation, sizeof(param->operation));
if((type & 1024))mdh_update(bctx, SAADDR(&param->srv->intsa), a3len);
if((type & 2048))mdh_update(bctx, SAPORT(&param->srv->intsa), 2);
mdh_final(bctx, hash, &blen);
mdh_free(bctx);
}
memcpy(param->hash, hash, ht->hash_size);
}
struct hashtable dns_table = {dns_index2hash, dns_index2hash, 4, 32};
struct hashtable dns6_table = {dns_index2hash, dns_index2hash, 16, 32};
/* the hosts file, while the system's resolver is the default */
struct hashtable hosts_table = {dns_index2hash, dns_index2hash, 4, 32};
struct hashtable hosts6_table = {dns_index2hash, dns_index2hash, 16, 32};
struct hashtable auth_table = {param2hash_add, param2hash_search, sizeof(struct authcache), 64};
/* users: each configuration has a table of its own, made from this one */
const struct hashtable pwl_template = {char_index2hash, char_index2hash, 64, 64};