Define order of reading files when --addn-hosts given a directory.

Also applies to --dhcp-hostsfile and --dhcp-optsfile though it is
less useful there.
This commit is contained in:
Simon Kelley
2021-08-12 16:48:54 +01:00
parent a1729deed3
commit 2f2d59b35c
3 changed files with 51 additions and 19 deletions

View File

@@ -86,6 +86,12 @@ version 2.86
conntrack is configured. Thanks to Yick Xie for spotting conntrack is configured. Thanks to Yick Xie for spotting
the lack of this. the lack of this.
When --dhcp-hostsfile --dhcp-optsfile and --addn-hosts are
given a directory as argument, define the order in which
files within that directory are read (alphabetical order
of filename). Thanks to Ed Wildgoose for the initial patch
and motivation for this.
version 2.85 version 2.85
Fix problem with DNS retries in 2.83/2.84. Fix problem with DNS retries in 2.83/2.84.

View File

@@ -55,7 +55,8 @@ Don't read the hostnames in /etc/hosts.
.B \-H, --addn-hosts=<file> .B \-H, --addn-hosts=<file>
Additional hosts file. Read the specified file as well as /etc/hosts. If \fB--no-hosts\fP is given, read Additional hosts file. Read the specified file as well as /etc/hosts. If \fB--no-hosts\fP is given, read
only the specified file. This option may be repeated for more than one only the specified file. This option may be repeated for more than one
additional hosts file. If a directory is given, then read all the files contained in that directory. additional hosts file. If a directory is given, then read all the files contained in that directory
in alphabetical order.
.TP .TP
.B --hostsdir=<path> .B --hostsdir=<path>
Read all the hosts files contained in the directory. New or changed files Read all the hosts files contained in the directory. New or changed files
@@ -1165,7 +1166,7 @@ has both wired and wireless interfaces.
.TP .TP
.B --dhcp-hostsfile=<path> .B --dhcp-hostsfile=<path>
Read DHCP host information from the specified file. If a directory Read DHCP host information from the specified file. If a directory
is given, then read all the files contained in that directory. The file contains is given, then read all the files contained in that directory in alphabetical order. The file contains
information about one host per line. The format of a line is the same information about one host per line. The format of a line is the same
as text to the right of '=' in \fB--dhcp-host\fP. The advantage of storing DHCP host information as text to the right of '=' in \fB--dhcp-host\fP. The advantage of storing DHCP host information
in this file is that it can be changed without re-starting dnsmasq: in this file is that it can be changed without re-starting dnsmasq:
@@ -1173,7 +1174,7 @@ the file will be re-read when dnsmasq receives SIGHUP.
.TP .TP
.B --dhcp-optsfile=<path> .B --dhcp-optsfile=<path>
Read DHCP option information from the specified file. If a directory Read DHCP option information from the specified file. If a directory
is given, then read all the files contained in that directory. The advantage of is given, then read all the files contained in that directory in alphabetical order. The advantage of
using this option is the same as for \fB--dhcp-hostsfile\fP: the using this option is the same as for \fB--dhcp-hostsfile\fP: the
\fB--dhcp-optsfile\fP will be re-read when dnsmasq receives SIGHUP. Note that \fB--dhcp-optsfile\fP will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a it is possible to encode the information in a
@@ -1188,7 +1189,8 @@ directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP. the directory are read automatically, without the need to send SIGHUP.
If a file is deleted or changed after it has been read by dnsmasq, then the If a file is deleted or changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq receives a SIGHUP, or host record it contained will remain until dnsmasq receives a SIGHUP, or
is restarted; ie host records are only added dynamically. is restarted; ie host records are only added dynamically. The order in which the
files in a directory are read is not defined.
.TP .TP
.B --dhcp-optsdir=<path> .B --dhcp-optsdir=<path>
This is equivalent to \fB--dhcp-optsfile\fP, with the differences noted for \fB--dhcp-hostsdir\fP. This is equivalent to \fB--dhcp-optsfile\fP, with the differences noted for \fB--dhcp-hostsdir\fP.

View File

@@ -5027,15 +5027,33 @@ static int one_file(char *file, int hard_opt)
return 1; return 1;
} }
static int file_filter(const struct dirent *ent)
{
size_t lenfile = strlen(ent->d_name);
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
return 0;
return 1;
}
/* expand any name which is a directory */ /* expand any name which is a directory */
struct hostsfile *expand_filelist(struct hostsfile *list) struct hostsfile *expand_filelist(struct hostsfile *list)
{ {
unsigned int i; unsigned int i;
struct hostsfile *ah; int entcnt, n;
struct hostsfile *ah, *last, *next, **up;
struct dirent **namelist;
/* find largest used index */ /* find largest used index */
for (i = SRC_AH, ah = list; ah; ah = ah->next) for (i = SRC_AH, ah = list; ah; ah = ah->next)
{ {
last = ah;
if (i <= ah->index) if (i <= ah->index)
i = ah->index + 1; i = ah->index + 1;
@@ -5051,46 +5069,48 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
struct stat buf; struct stat buf;
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode)) if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
{ {
DIR *dir_stream;
struct dirent *ent; struct dirent *ent;
/* don't read this as a file */ /* don't read this as a file */
ah->flags |= AH_INACTIVE; ah->flags |= AH_INACTIVE;
if (!(dir_stream = opendir(ah->fname))) entcnt = scandir(ah->fname, &namelist, file_filter, alphasort);
if (entcnt < 0)
my_syslog(LOG_ERR, _("cannot access directory %s: %s"), my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
ah->fname, strerror(errno)); ah->fname, strerror(errno));
else else
{ {
while ((ent = readdir(dir_stream))) for (n = 0; n < entcnt; n++)
{ {
ent = namelist[n];
size_t lendir = strlen(ah->fname); size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name); size_t lenfile = strlen(ent->d_name);
struct hostsfile *ah1; struct hostsfile *ah1;
char *path; char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
/* see if we have an existing record. /* see if we have an existing record.
dir is ah->fname dir is ah->fname
file is ent->d_name file is ent->d_name
path to match is ah1->fname */ path to match is ah1->fname */
for (ah1 = list; ah1; ah1 = ah1->next) for (up = &list, ah1 = list; ah1; ah1 = next)
{ {
next = ah1->next;
if (lendir < strlen(ah1->fname) && if (lendir < strlen(ah1->fname) &&
strstr(ah1->fname, ah->fname) == ah1->fname && strstr(ah1->fname, ah->fname) == ah1->fname &&
ah1->fname[lendir] == '/' && ah1->fname[lendir] == '/' &&
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0) strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
{ {
ah1->flags &= ~AH_INACTIVE; ah1->flags &= ~AH_INACTIVE;
/* If found, remove from list to re-insert at the end.
Unless it's already at the end. */
if (last != ah1)
*up = next;
break; break;
} }
up = &ah1->next;
} }
/* make new record */ /* make new record */
@@ -5111,17 +5131,21 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
ah1->fname = path; ah1->fname = path;
ah1->index = i++; ah1->index = i++;
ah1->flags = AH_DIR; ah1->flags = AH_DIR;
ah1->next = list;
list = ah1;
} }
/* Edge case, may be the last in the list anyway */
if (last != ah1)
last->next = ah1;
ah1->next = NULL;
last = ah1;
/* inactivate record if not regular file */ /* inactivate record if not regular file */
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode)) if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
ah1->flags |= AH_INACTIVE; ah1->flags |= AH_INACTIVE;
} }
closedir(dir_stream);
} }
free(namelist);
} }
} }