resolver: per service, defaultresolve, fakeresolve or sysresolve
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

Each service resolves names the way the last of defaultresolve (the name
servers in force, configured or the system's with the hosts file),
fakeresolve (127.0.0.2) and sysresolve (the C library) read before it
says; the last one in the configuration also applies outside services.
defaultresolve is the new command, and the default.

The name servers and the hosts file no longer depend on the mode: nserver
lines, or the system's, are always in force, so dnspr keeps forwarding;
with fakeresolve it does not, as before. fakeresolver moves to common.c,
which the standalone services link without resolve.c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-21 18:45:48 +03:00
parent 994526dbc4
commit 3d20e1104e
14 changed files with 181 additions and 101 deletions

View File

@ -498,14 +498,6 @@ user), Reply-Message. Use <b>authcache</b> to speedup
authentication. RADIUS feature is currently authentication. RADIUS feature is currently
experimental.</p> experimental.</p>
<p style="margin-left:9%; margin-top: 1em"><b>sysresolve</b>
<br>
Names are resolved by the system routines for name
resolution (the C library), as without <b>nserver</b> before
the system's name servers became the default; the hosts file
is not imported. <b>nserver</b> lines, if any, are still used
by <b>dnspr</b> to forward queries. Of <b>sysresolve</b> and
<b>fakeresolve</b> the last one given applies.</p>
<p style="margin-left:9%; margin-top: 1em"><b>nserver</b> <p style="margin-left:9%; margin-top: 1em"><b>nserver</b>
<i>&lt;ipaddr&gt;</i>[:<i>port</i>][/<i>tcp</i>] <br> <i>&lt;ipaddr&gt;</i>[:<i>port</i>][/<i>tcp</i>] <br>
@ -516,9 +508,7 @@ has to be enclosed in square brackets: <br>
<b>nserver 1.1.1.1</b> <br> <b>nserver 1.1.1.1</b> <br>
<b>nserver [2001:4860:4860::8844]</b> <br> <b>nserver [2001:4860:4860::8844]</b> <br>
<b>nserver [2001:4860:4860::8844]:5353/tcp</b> <br> <b>nserver [2001:4860:4860::8844]:5353/tcp</b> <br>
If none is specified (and there is no <b>fakeresolve</b> or If none is specified, the system's name servers are used: up to 3 from
<b>sysresolve</b>),
the system's name servers are used: up to 3 from
<i>/etc/resolv.conf</i>, on Windows from the registry (those <i>/etc/resolv.conf</i>, on Windows from the registry (those
set for the system, those set for an interface, then those set for the system, those set for an interface, then those
DHCP gave). Names in the hosts file (<i>/etc/hosts</i>, on DHCP gave). Names in the hosts file (<i>/etc/hosts</i>, on
@ -567,12 +557,39 @@ together with <b>dialer</b> command to set up UDL for
dialing.</p> dialing.</p>
<p style="margin-left:9%; margin-top: 1em"><b>defaultresolve</b>
<br>
Names are resolved by the name servers in force: those of
<b>nserver</b> lines, or the system's ones with the hosts file
by default (see <b>nserver</b>). This is the default.</p>
<p style="margin-left:9%; margin-top: 1em"><b>sysresolve</b>
<br>
Names are resolved by the system routines for name
resolution (the C library), as without <b>nserver</b> before
the system's name servers became the default: <b>nsrecord</b>
is not consulted. <b>dnspr</b> still forwards queries to the
name servers in force.</p>
<p style="margin-left:9%; margin-top: 1em"><b>fakeresolve</b> <p style="margin-left:9%; margin-top: 1em"><b>fakeresolve</b>
<br> <br>
All names are resolved to the 127.0.0.2 address. Useful if All names are resolved to the 127.0.0.2 address. Useful if
all requests are redirected to a parent proxy with all requests are redirected to a parent proxy with
<b>http</b>, <b>socks4+</b>, <b>connect+</b> or <b>http</b>, <b>socks4+</b>, <b>connect+</b> or
<b>socks5+</b>.</p> <b>socks5+</b>. <b>dnspr</b> does not forward queries.</p>
<p style="margin-left:9%; margin-top: 1em">Of
<b>defaultresolve</b>, <b>sysresolve</b> and
<b>fakeresolve</b>, the last one given before a service
applies to it, so services can resolve names differently:
<br>
<b>fakeresolve</b> <br>
<b>proxy -p3128</b> <br>
<b>defaultresolve</b> <br>
<b>socks -p1080</b> <br>
The last one in the configuration also applies to names
resolved outside a service, such as those in the
configuration itself, once it is loaded.</p>
<p style="margin-left:9%; margin-top: 1em"><b>dialer</b> <p style="margin-left:9%; margin-top: 1em"><b>dialer</b>
<i>&lt;progname&gt;</i> <br> <i>&lt;progname&gt;</i> <br>

View File

@ -555,7 +555,7 @@ An IPv6 address has to be enclosed in square brackets:
.br .br
\fBnserver [2001:4860:4860::8844]:5353/tcp\fR \fBnserver [2001:4860:4860::8844]:5353/tcp\fR
.br .br
If none is specified (and there is no \fBfakeresolve\fR or \fBsysresolve\fR), the system's name If none is specified, the system's name
servers are used: up to 3 from \fI/etc/resolv.conf\fR, on Windows from the servers are used: up to 3 from \fI/etc/resolv.conf\fR, on Windows from the
registry (those set for the system, those set for an interface, then those registry (those set for the system, those set for an interface, then those
DHCP gave). Names in the hosts file (\fI/etc/hosts\fR, on Windows DHCP gave). Names in the hosts file (\fI/etc/hosts\fR, on Windows
@ -600,20 +600,43 @@ are never consulted. A static record takes precedence over the hosts file. If 0.
is used as a hostaddr host will never resolve, it can be used to is used as a hostaddr host will never resolve, it can be used to
blacklist something. blacklist something.
.br
.B defaultresolve
.br
Names are resolved by the name servers in force: those of \fBnserver\fR
lines, or the system's ones with the hosts file by default (see
\fBnserver\fR). This is the default.
.br .br
.B sysresolve .B sysresolve
.br .br
Names are resolved by the system routines for name resolution (the C Names are resolved by the system routines for name resolution (the C
library), as without \fBnserver\fR before the system's name servers became library), as without \fBnserver\fR before the system's name servers became
the default; the hosts file is not imported. \fBnserver\fR lines, if any, are the default: \fBnsrecord\fR is not consulted. \fBdnspr\fR still forwards
still used by \fBdnspr\fR to forward queries. Of \fBsysresolve\fR and queries to the name servers in force.
\fBfakeresolve\fR the last one given applies.
.br .br
.B fakeresolve .B fakeresolve
.br .br
All names are resolved to the 127.0.0.2 address. Useful if all requests are All names are resolved to the 127.0.0.2 address. Useful if all requests are
redirected to a parent proxy with \fBhttp\fR, \fBsocks4+\fR, \fBconnect+\fR or \fBsocks5+\fR. redirected to a parent proxy with \fBhttp\fR, \fBsocks4+\fR, \fBconnect+\fR or \fBsocks5+\fR.
\fBdnspr\fR does not forward queries.
.br
Of \fBdefaultresolve\fR, \fBsysresolve\fR and \fBfakeresolve\fR, the last
one given before a service applies to it, so services can resolve names
differently:
.br
\fBfakeresolve\fR
.br
\fBproxy -p3128\fR
.br
\fBdefaultresolve\fR
.br
\fBsocks -p1080\fR
.br
The last one in the configuration also applies to names resolved outside
a service, such as those in the configuration itself, once it is loaded.
.br .br
.BR dialer .BR dialer

View File

@ -594,8 +594,8 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
/* numbered before it is read, as a reload numbers the new one */ /* numbered before it is read, as a reload numbers the new one */
conf->version++; conf->version++;
res = readconfig(fp); res = readconfig(fp);
if(!res) confdnscommit(conf); if(!res) confdnscommit();
resolvfunc = conf->resolvfunc; resolvmode = conf->resolvmode;
/* readconfig() names the failing line, which an exit status would cut /* readconfig() names the failing line, which an exit status would cut
to 8 bits: a failed configuration exits with 1 */ to 8 bits: a failed configuration exits with 1 */

View File

@ -570,7 +570,7 @@ int parsehostname(char *hostname, struct clientparam *param, uint16_t port){
if(sp){ if(sp){
port = atoi(sp+1); port = atoi(sp+1);
} }
ret = !getip46(param->srv->family, param->hostname, (struct sockaddr *)&param->req); ret = !getip46m(param->srv->resolvmode, param->srv->family, param->hostname, (struct sockaddr *)&param->req);
if(se) *se = ']'; if(se) *se = ']';
if(sp) *sp = ':'; if(sp) *sp = ':';
*SAPORT(&param->req) = htons(port); *SAPORT(&param->req) = htons(port);
@ -863,7 +863,36 @@ int scanaddr(const unsigned char *s, uint32_t * ip, uint32_t * mask) {
return res; return res;
} }
/* The default resolver: name servers, configured or the system's, or NULL
for the system routines. resolvmode is the configuration's, for names
resolved outside a service; each service has its own. */
RESOLVFUNC resolvfunc = NULL; RESOLVFUNC resolvfunc = NULL;
int resolvmode = RESOLVE_DEFAULT;
uint32_t fakeresolver (int af, unsigned char *name, unsigned char * value){
if(af == AF_INET6){
memset(value, 0, 16);
value[15] = 2;
}
else {
value[0] = 127;
value[1] = 0;
value[2] = 0;
value[3] = 2;
}
return 1;
}
/* The resolver of a mode, NULL for the system routines */
static RESOLVFUNC moderesolver(int mode){
switch(mode){
case RESOLVE_FAKE:
return fakeresolver;
case RESOLVE_SYSTEM:
return NULL;
}
return resolvfunc;
}
#ifndef _WIN32 #ifndef _WIN32
_3proxy_mutex_t gethostbyname_mutex; _3proxy_mutex_t gethostbyname_mutex;
int ghbn_init = 0; int ghbn_init = 0;
@ -887,7 +916,7 @@ struct hostent * my_gethostbyname(char *name, char *buf, struct hostent *hp){
#endif #endif
#ifdef NOIPV6 #ifdef NOIPV6
uint32_t getip(unsigned char *name){ static uint32_t getipm(int mode, unsigned char *name){
uint32_t retval; uint32_t retval;
int i; int i;
int ndots = 0; int ndots = 0;
@ -913,7 +942,7 @@ uint32_t getip(unsigned char *name){
return retval; return retval;
} }
} }
if((tmpresolv=resolvfunc)){ if((tmpresolv=moderesolver(mode))){
return (*tmpresolv)(AF_INET, name, (unsigned char *)&retval)?retval:0; return (*tmpresolv)(AF_INET, name, (unsigned char *)&retval)?retval:0;
} }
#ifndef NOSTDRESOLVE #ifndef NOSTDRESOLVE
@ -937,6 +966,10 @@ uint32_t getip(unsigned char *name){
#endif #endif
return retval; return retval;
} }
uint32_t getip(unsigned char *name){
return getipm(resolvmode, name);
}
#endif #endif
int afdetect(unsigned char *name){ int afdetect(unsigned char *name){
@ -971,7 +1004,8 @@ int afdetect(unsigned char *name){
} }
uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){ /* A name resolved the way a mode says: a service's names with its own */
uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *sa){
#ifndef NOIPV6 #ifndef NOIPV6
int detect; int detect;
#ifndef NOSTDRESOLVE #ifndef NOSTDRESOLVE
@ -984,7 +1018,7 @@ uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){
family = 4; family = 4;
#else #else
((struct sockaddr_in *)sa)->sin_family = AF_INET; ((struct sockaddr_in *)sa)->sin_family = AF_INET;
return (((struct sockaddr_in *)sa)->sin_addr.s_addr = getip(name))? AF_INET:0; return (((struct sockaddr_in *)sa)->sin_addr.s_addr = getipm(mode, name))? AF_INET:0;
#endif #endif
#ifndef NOIPV6 #ifndef NOIPV6
} }
@ -996,7 +1030,7 @@ uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){
return inet_pton(*SAFAMILY(sa), (char *)name, SAADDR(sa))>0? *SAFAMILY(sa) : 0; return inet_pton(*SAFAMILY(sa), (char *)name, SAADDR(sa))>0? *SAFAMILY(sa) : 0;
} }
if((tmpresolv = resolvfunc)){ if((tmpresolv = moderesolver(mode))){
int f = (family == 6 || family == 64)?AF_INET6:AF_INET; int f = (family == 6 || family == 64)?AF_INET6:AF_INET;
*SAFAMILY(sa) = f; *SAFAMILY(sa) = f;
if(tmpresolv(f, name, SAADDR(sa))) return f; if(tmpresolv(f, name, SAADDR(sa))) return f;
@ -1030,6 +1064,10 @@ uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){
#endif #endif
} }
uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa){
return getip46m(resolvmode, family, name, sa);
}
int hascap(const unsigned char *line, const char *cap){ int hascap(const unsigned char *line, const char *cap){
int len = (int)strlen(cap); int len = (int)strlen(cap);
for(; *line; line++) if(!strncasecmp((char *)line, cap, len)) return 1; for(; *line; line++) if(!strncasecmp((char *)line, cap, len)) return 1;

View File

@ -376,7 +376,7 @@ static int h_proxy(int argc, unsigned char ** argv){
childdef.service = S_DNSPR; childdef.service = S_DNSPR;
childdef.helpmessage = " -s - simple DNS forwarding - do not use 3proxy resolver / name cache\n -Fip - fake: answer all A queries with this IP\n"; childdef.helpmessage = " -s - simple DNS forwarding - do not use 3proxy resolver / name cache\n -Fip - fake: answer all A queries with this IP\n";
#ifndef NOIPV6 #ifndef NOIPV6
if(noresolver() || conf->resolvfunc == fakeresolver){ if(noresolver() || conf->resolvmode == RESOLVE_FAKE){
fprintf(stderr, "[line %d] Warning: no nserver/nscache configured, dnspr will not work as expected\n", linenum); fprintf(stderr, "[line %d] Warning: no nserver/nscache configured, dnspr will not work as expected\n", linenum);
} }
#endif #endif
@ -741,8 +741,6 @@ static int h_flushusers(int argc, unsigned char **argv){
force (the process has one list) once it is committed */ force (the process has one list) once it is committed */
static struct nserver cfgns[MAXNSERVERS]; static struct nserver cfgns[MAXNSERVERS];
static int cfgnsn = 0; static int cfgnsn = 0;
/* sysresolve: names resolved by the system routines */
static int cfgsysresolve = 0;
static int h_nserver(int argc, unsigned char **argv){ static int h_nserver(int argc, unsigned char **argv){
char *str; char *str;
@ -760,20 +758,20 @@ static int h_nserver(int argc, unsigned char **argv){
cfgnsn++; cfgnsn++;
} }
else fprintf(stderr, "[line %d] Warning: only %d name servers are used, nserver ignored\n", linenum, MAXNSERVERS); else fprintf(stderr, "[line %d] Warning: only %d name servers are used, nserver ignored\n", linenum, MAXNSERVERS);
conf->resolvfunc = myresolver;
return 0; return 0;
} }
/* The configuration's name servers, or the system's in their place */ /* The configuration's name servers, or the system's in their place */
void confdnscommit(struct extparam *c){ void confdnscommit(void){
sysdnsapply(c, cfgns, cfgnsn, cfgsysresolve); sysdnsapply(cfgns, cfgnsn);
} }
/* Whether names would be resolved slowly: by the C library, or by name /* Whether names would be resolved slowly: by the C library, or by name
servers, the system's taken by default, without a cache */ servers, the system's taken by default, without a cache */
static int noresolver(void){ static int noresolver(void){
if(cfgsysresolve || (!conf->resolvfunc && !sysdnscount())) return 1; if(conf->resolvmode == RESOLVE_FAKE) return 0;
return (!conf->resolvfunc || conf->resolvfunc == myresolver) && !dns_table.poolsize; if(conf->resolvmode == RESOLVE_SYSTEM || (!cfgnsn && !sysdnscount())) return 1;
return !dns_table.poolsize;
} }
static int h_authnserver(int argc, unsigned char **argv){ static int h_authnserver(int argc, unsigned char **argv){
@ -790,14 +788,20 @@ static int h_authnserver(int argc, unsigned char **argv){
return 0; return 0;
} }
/* defaultresolve, fakeresolve, sysresolve: for the services after it,
and, the last one, for names resolved outside a service */
static int h_defaultresolve(int argc, unsigned char **argv){
conf->resolvmode = RESOLVE_DEFAULT;
return 0;
}
static int h_fakeresolve(int argc, unsigned char **argv){ static int h_fakeresolve(int argc, unsigned char **argv){
conf->resolvfunc = fakeresolver; conf->resolvmode = RESOLVE_FAKE;
cfgsysresolve = 0;
return 0; return 0;
} }
static int h_sysresolve(int argc, unsigned char **argv){ static int h_sysresolve(int argc, unsigned char **argv){
cfgsysresolve = 1; conf->resolvmode = RESOLVE_SYSTEM;
return 0; return 0;
} }
@ -2153,6 +2157,7 @@ struct commands commandhandlers[]={
{NULL, "maxconn", h_maxconn, 2, 2}, {NULL, "maxconn", h_maxconn, 2, 2},
{NULL, "flush", h_flush, 1, 1}, {NULL, "flush", h_flush, 1, 1},
{NULL, "nserver", h_nserver, 2, 2}, {NULL, "nserver", h_nserver, 2, 2},
{NULL, "defaultresolve", h_defaultresolve, 1, 1},
{NULL, "fakeresolve", h_fakeresolve, 1, 1}, {NULL, "fakeresolve", h_fakeresolve, 1, 1},
{NULL, "sysresolve", h_sysresolve, 1, 1}, {NULL, "sysresolve", h_sysresolve, 1, 1},
{NULL, "nscache", h_nscache, 2, 2}, {NULL, "nscache", h_nscache, 2, 2},
@ -2543,7 +2548,6 @@ void confbegin(void){
char * args[] = {"auth", "iponly", NULL}; char * args[] = {"auth", "iponly", NULL};
cfgnsn = 0; cfgnsn = 0;
cfgsysresolve = 0;
h_auth(2, (unsigned char **)args); h_auth(2, (unsigned char **)args);
} }
@ -2675,8 +2679,8 @@ int reload (void){
_3proxy_mutex_lock(&confref_mutex); _3proxy_mutex_lock(&confref_mutex);
runconf = new; runconf = new;
_3proxy_mutex_unlock(&confref_mutex); _3proxy_mutex_unlock(&confref_mutex);
confdnscommit(new); confdnscommit();
resolvfunc = new->resolvfunc; resolvmode = new->resolvmode;
/* the new services take over the listening sockets of the old ones on /* the new services take over the listening sockets of the old ones on
the same addresses, which then stop accepting, and start */ the same addresses, which then stop accepting, and start */
for(d = deferred; d; d = d->next) mainclaim(d->service); for(d = deferred; d; d = d->next) mainclaim(d->service);

View File

@ -296,7 +296,7 @@ static int dnsprfirst(struct udploop *u, struct udpsession *ss, unsigned char *q
} }
} }
q->ip = ip; q->ip = ip;
if(ip || !numservers){ if(ip || !numservers || param->srv->resolvmode == RESOLVE_FAKE){
param->res = dnsanswer(u, param, q, buf, len); param->res = dnsanswer(u, param, q, buf, len);
free(buf); free(buf);
return 1; return 1;

View File

@ -712,6 +712,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
srv->backlog = conf->backlog; srv->backlog = conf->backlog;
srv->stacksize = conf->stacksize; srv->stacksize = conf->stacksize;
srv->config = conf; srv->config = conf;
srv->resolvmode = conf->resolvmode;
memcpy(srv->timeouts, conf->timeouts, sizeof(srv->timeouts)); memcpy(srv->timeouts, conf->timeouts, sizeof(srv->timeouts));
srv->filtermaxsize = conf->filtermaxsize; srv->filtermaxsize = conf->filtermaxsize;
srv->parentretries = conf->parentretries; srv->parentretries = conf->parentretries;

View File

@ -205,6 +205,7 @@ size_t threadstacksize(int extra);
#endif #endif
extern RESOLVFUNC resolvfunc; extern RESOLVFUNC resolvfunc;
extern int resolvmode;
extern int wday; extern int wday;
extern time_t basetime; extern time_t basetime;
@ -351,6 +352,7 @@ int scanaddr(const unsigned char *s, uint32_t * ip, uint32_t * mask);
int myinet_ntop(int af, void *src, char *dst, socklen_t size); int myinet_ntop(int af, void *src, char *dst, socklen_t size);
uint32_t getip(unsigned char *name); uint32_t getip(unsigned char *name);
uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa); uint32_t getip46(int family, unsigned char *name, struct sockaddr *sa);
uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *sa);
int afdetect(unsigned char *name); int afdetect(unsigned char *name);
uint32_t myresolver(int, unsigned char *, unsigned char *); uint32_t myresolver(int, unsigned char *, unsigned char *);
uint32_t fakeresolver (int, unsigned char *, unsigned char*); uint32_t fakeresolver (int, unsigned char *, unsigned char*);
@ -435,9 +437,9 @@ int nscacheresolv(int af, unsigned char *name, unsigned char *value, uint32_t *t
void setnservers(const struct nserver *ns, int n); void setnservers(const struct nserver *ns, int n);
void sysdnsinit(void); void sysdnsinit(void);
int sysdnscount(void); int sysdnscount(void);
void sysdnsapply(struct extparam *c, const struct nserver *ns, int n, int sysresolve); void sysdnsapply(const struct nserver *ns, int n);
void sysdnscheck(void); void sysdnscheck(void);
void confdnscommit(struct extparam *c); void confdnscommit(void);
uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth); uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth);
struct ace * copyacl (struct ace *ac); struct ace * copyacl (struct ace *ac);

View File

@ -268,18 +268,18 @@ void applyportranges(struct clientparam * param, struct ace * acentry){
} }
} }
static void chainaddr(struct chain * cur, PROXYSOCKADDRTYPE * sa){ static void chainaddr(struct clientparam * param, struct chain * cur, PROXYSOCKADDRTYPE * sa){
PROXYSOCKADDRTYPE fresh; PROXYSOCKADDRTYPE fresh;
*sa = cur->addr; *sa = cur->addr;
if(resolvfunc != myresolver) return; if(param->srv->resolvmode != RESOLVE_DEFAULT || resolvfunc != myresolver) return;
if(!cur->exthost || SAISNULL(&cur->addr)) return; if(!cur->exthost || SAISNULL(&cur->addr)) return;
#ifdef WITH_UN #ifdef WITH_UN
if(*SAFAMILY(&cur->addr) == AF_UNIX) return; if(*SAFAMILY(&cur->addr) == AF_UNIX) return;
#endif #endif
if(afdetect(cur->exthost) != -1) return; if(afdetect(cur->exthost) != -1) return;
memset(&fresh, 0, sizeof(fresh)); memset(&fresh, 0, sizeof(fresh));
if(!getip46(46, cur->exthost, (struct sockaddr *)&fresh)) return; if(!getip46m(RESOLVE_DEFAULT, 46, cur->exthost, (struct sockaddr *)&fresh)) return;
*SAPORT(&fresh) = *SAPORT(&cur->addr); *SAPORT(&fresh) = *SAPORT(&cur->addr);
*sa = fresh; *sa = fresh;
} }
@ -430,12 +430,12 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
} }
else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) { else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) {
uint16_t port = *SAPORT(&param->sinsr); uint16_t port = *SAPORT(&param->sinsr);
chainaddr(cur, &param->sinsr); chainaddr(param, cur, &param->sinsr);
*SAPORT(&param->sinsr) = port; *SAPORT(&param->sinsr) = port;
} }
else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(&param->sinsr) = *SAPORT(&cur->addr); else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(&param->sinsr) = *SAPORT(&cur->addr);
else { else {
chainaddr(cur, &param->sinsr); chainaddr(param, cur, &param->sinsr);
} }
if(param->operation == UDPASSOC){ if(param->operation == UDPASSOC){
SOCKET s; SOCKET s;
@ -468,7 +468,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
else { else {
PROXYSOCKADDRTYPE next; PROXYSOCKADDRTYPE next;
chainaddr(cur, &next); chainaddr(param, cur, &next);
res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&next, cur->exthost):0; res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&next, cur->exthost):0;
if(res) { if(res) {
parentfail(param, cur); parentfail(param, cur);

View File

@ -255,23 +255,8 @@ uint32_t myresolver(int af, unsigned char * name, unsigned char * value){
return udpresolve(af, name, value, NULL, NULL, 0); return udpresolve(af, name, value, NULL, NULL, 0);
} }
uint32_t fakeresolver (int af, unsigned char *name, unsigned char * value){
memset(value, 0, af == AF_INET6? 16 : 4);
if(af == AF_INET6){
memset(value, 0, 16);
value[15] = 2;
}
else {
value[0] = 127;
value[1] = 0;
value[2] = 0;
value[3] = 2;
}
return 1;
}
/* The system's name servers and hosts file, the default for a configuration /* The system's name servers and hosts file, the default for a configuration
without nserver (or fakeresolve): read at start, before a chroot can hide without nserver: read at start, before a chroot can hide
them, and checked from the main loop for changes, which apply while the them, and checked from the main loop for changes, which apply while the
default is in force. Hosts entries have tables of their own, emptied when default is in force. Hosts entries have tables of their own, emptied when
the default is not in force. Only the main thread works on this. */ the default is not in force. Only the main thread works on this. */
@ -583,34 +568,26 @@ int sysdnscount(void){
return sysdns.n; return sysdns.n;
} }
/* A configuration committed: the name servers of its nserver lines, else, /* A configuration committed: the name servers of its nserver lines, else
with nothing else to resolve names, the system's and its hosts file, read the system's and its hosts file, read again; with none the system
again. Until then those in force stay. With sysresolve the system routines are the default. Until then those in force stay. */
routines resolve names, nserver lines left to dnspr. */ void sysdnsapply(const struct nserver *ns, int n){
void sysdnsapply(struct extparam *c, const struct nserver *ns, int n, int sysresolve){
sysdns.active = 0; sysdns.active = 0;
if(sysresolve){
c->resolvfunc = NULL;
setnservers(ns, n);
hostsremove();
return;
}
if(n){ if(n){
setnservers(ns, n); setnservers(ns, n);
hostsremove(); hostsremove();
return; resolvfunc = myresolver;
}
if(c->resolvfunc){
setnservers(NULL, 0);
hostsremove();
return; return;
} }
sysdnsread(); sysdnsread();
sysdns.checked = curtime; sysdns.checked = curtime;
sysdns.active = 1; sysdns.active = 1;
setnservers(sysdns.ns, sysdns.n); setnservers(sysdns.ns, sysdns.n);
if(!sysdns.n) return; /* the C library, as before */ if(!sysdns.n){ /* the C library, as before */
c->resolvfunc = myresolver; resolvfunc = NULL;
return;
}
resolvfunc = myresolver;
hostsimport(); hostsimport();
} }
@ -627,7 +604,7 @@ void sysdnscheck(void){
setnservers(sysdns.ns, sysdns.n); setnservers(sysdns.ns, sysdns.n);
dolog(NULL, (unsigned char *)"System name servers changed"); dolog(NULL, (unsigned char *)"System name servers changed");
/* none before: the C library resolved until now */ /* none before: the C library resolved until now */
if(!was) conf->resolvfunc = resolvfunc = myresolver; if(!was) resolvfunc = myresolver;
} }
if(resolvfunc == myresolver && ((res & 2) || !was)) hostsimport(); if(resolvfunc == myresolver && ((res & 2) || !was)) hostsimport();
if(res & 2) dolog(NULL, (unsigned char *)"Hosts file changed"); if(res & 2) dolog(NULL, (unsigned char *)"Hosts file changed");

View File

@ -132,7 +132,7 @@ void * sockschild(struct clientparam* param) {
} }
buf[i] = 0; buf[i] = 0;
if(command == 2 && param->srv->family != 6 && (!strcmp((char *)buf, "0.0.0.0") || !strcmp((char *)buf, "0"))) param->req = param->srv->extsa; if(command == 2 && param->srv->family != 6 && (!strcmp((char *)buf, "0.0.0.0") || !strcmp((char *)buf, "0"))) param->req = param->srv->extsa;
else if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100); else if(!getip46m(param->srv->resolvmode, param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100);
param->sinsr = param->req; param->sinsr = param->req;
break; break;
default: default:
@ -158,7 +158,7 @@ void * sockschild(struct clientparam* param) {
if(sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, param->srv->timeouts[STRING_S]) < 0) {RETURN(441);} if(sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, param->srv->timeouts[STRING_S]) < 0) {RETURN(441);}
buf[127] = 0; buf[127] = 0;
if(PARAMSTR(param, hostname, buf)){RETURN(21);} if(PARAMSTR(param, hostname, buf)){RETURN(21);}
if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100); if(!getip46m(param->srv->resolvmode, param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100);
param->sinsr = param->req; param->sinsr = param->req;
} }
} }

View File

@ -503,6 +503,11 @@ struct nserver {
}; };
#define MAXNSERVERS 3 #define MAXNSERVERS 3
/* how a service resolves names: defaultresolve (the name servers in force,
configured or the system's), fakeresolve, sysresolve (the C library) */
#define RESOLVE_DEFAULT 0
#define RESOLVE_FAKE 1
#define RESOLVE_SYSTEM 2
#define MAXRADIUS 5 #define MAXRADIUS 5
struct radserver { struct radserver {
@ -644,6 +649,7 @@ struct srvparam {
int transparent; int transparent;
int nfilters, nreqfilters, nconnectfilters, nafterauthfilters, nhdrfilterscli, nhdrfilterssrv, npredatfilters, ndatfilterscli, ndatfilterssrv; int nfilters, nreqfilters, nconnectfilters, nafterauthfilters, nhdrfilterscli, nhdrfilterssrv, npredatfilters, ndatfilterscli, ndatfilterssrv;
int family; int family;
int resolvmode; /* RESOLVE_* */
int stacksize; int stacksize;
struct extparam *config; /* the configuration it was started with */ struct extparam *config; /* the configuration it was started with */
int timeouts[12]; /* conf.timeouts as they were when the service started */ int timeouts[12]; /* conf.timeouts as they were when the service started */
@ -928,7 +934,7 @@ struct extparam {
int refs; int refs;
struct hashtable pwl_table; /* users */ struct hashtable pwl_table; /* users */
int havelog; /* log was configured */ int havelog; /* log was configured */
RESOLVFUNC resolvfunc; /* nserver or fakeresolve, in force once committed */ int resolvmode; /* RESOLVE_*: the last read, each service taking the one read before it */
}; };
struct property { struct property {

View File

@ -273,7 +273,7 @@ int udpsockmap(struct clientparam *param, int timeo)
dstnamebuf[sz] = 0; dstnamebuf[sz] = 0;
dstname = dstnamebuf; dstname = dstnamebuf;
i = 5 + sz; i = 5 + sz;
if (!getip46(param->srv->family, (unsigned char *)dstnamebuf, if (!getip46m(param->srv->resolvmode, param->srv->family, (unsigned char *)dstnamebuf,
(struct sockaddr *)&dst)) { (struct sockaddr *)&dst)) {
if (!nhops) return 100; if (!nhops) return 100;
memset(&dst, 0, sizeof(dst)); memset(&dst, 0, sizeof(dst));

View File

@ -1,6 +1,7 @@
"""The system's name servers and hosts file as the default resolver: with """The system's name servers and hosts file as the default resolver: with
no nserver in a configuration, names in the hosts file are answered from no nserver in a configuration, names in the hosts file are answered from
it; with nserver lines, or sysresolve (the system routines), it is not.""" it; with nserver lines it is not. Each service resolves names the way the
last of defaultresolve, sysresolve and fakeresolve before it says."""
import os import os
import re import re
@ -82,25 +83,36 @@ def run(t):
t.ne(["127.0.0.1"], t.dns_query(other, "localhost") or [], t.ne(["127.0.0.1"], t.dns_query(other, "localhost") or [],
"with nserver, the hosts file is not used") "with nserver, the hosts file is not used")
# sysresolve: the system routines resolve names, and nothing is imported # each service resolves the way the command before it says: fake (to
# for dnspr to answer from # 127.0.0.2, where the server is not), the system routines (no
sysport, proxy, srv = t.free_port(), t.free_port(), t.free_port() # nsrecord) or the default (the system's name servers, and nsrecord)
t.start("sysdns_sysresolve", f""" fake, system, default, srv = t.free_port(), t.free_port(), t.free_port(), t.free_port()
t.start("sysdns_modes", f"""
log log
nscache 1024
nsrecord only3proxy.test 127.0.0.1
flush flush
sysresolve
auth iponly auth iponly
allow * allow *
dnspr -p{sysport} fakeresolve
proxy -p{proxy} proxy -p{fake}
sysresolve
proxy -p{system}
defaultresolve
proxy -p{default}
flush flush
auth iponly auth iponly
allow * allow *
http echo * /echo** http echo * /echo**
httpsrv -p{srv} httpsrv -i127.0.0.1 -p{srv}
""", ports=[proxy, srv]) """, ports=[fake, system, default, srv])
wait(t, sysport, "localhost") t.eq(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{default}").status,
t.ne(["127.0.0.1"], t.dns_query(sysport, "localhost") or [], "defaultresolve: a name of the hosts file resolves")
"with sysresolve, dnspr has no hosts file names") t.eq(200, t.http(f"http://only3proxy.test:{srv}/echo", proxy=f"127.0.0.1:{default}").status,
t.eq(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{proxy}").status, "and an nsrecord name")
"and names resolve through the system routines") t.eq(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{system}").status,
"sysresolve: names resolve through the system routines")
t.ne(200, t.http(f"http://only3proxy.test:{srv}/echo", proxy=f"127.0.0.1:{system}").status,
"which know no nsrecord name")
t.ne(200, t.http(f"http://localhost:{srv}/echo", proxy=f"127.0.0.1:{fake}").status,
"fakeresolve: every name is 127.0.0.2, in a service before the others")