]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/dnsmasq/0038-Expand-inotify-code-to-dhcp-hostsdir-dhcp-optsdir-an.patch
dnsmasq: Import more patches from upstream
[ipfire-2.x.git] / src / patches / dnsmasq / 0038-Expand-inotify-code-to-dhcp-hostsdir-dhcp-optsdir-an.patch
CommitLineData
6644c1c7
MT
1From 70d1873dd9e70041ed4bb88c69d5b886b7cc634c Mon Sep 17 00:00:00 2001
2From: Simon Kelley <simon@thekelleys.org.uk>
3Date: Sat, 31 Jan 2015 19:59:29 +0000
d54a2ce4 4Subject: [PATCH 38/78] Expand inotify code to dhcp-hostsdir, dhcp-optsdir and
6644c1c7
MT
5 hostsdir.
6
7---
8 src/cache.c | 81 +++++++++++++++++---------
9 src/dnsmasq.c | 9 ++-
10 src/dnsmasq.h | 14 +++--
11 src/inotify.c | 179 +++++++++++++++++++++++++++++-----------------------------
12 src/option.c | 37 +++++++++---
13 5 files changed, 187 insertions(+), 133 deletions(-)
14
15diff --git a/src/cache.c b/src/cache.c
16index 09b6dbf8087a..abaf25ec0f18 100644
17--- a/src/cache.c
18+++ b/src/cache.c
19@@ -835,27 +835,42 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
20 Only insert each unique address once into this hashing structure.
21
22 This complexity avoids O(n^2) divergent CPU use whilst reading
23- large (10000 entry) hosts files. */
24-
25- /* hash address */
26- for (j = 0, i = 0; i < addrlen; i++)
27- j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
28-
29- for (lookup = rhash[j]; lookup; lookup = lookup->next)
30- if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
31- memcmp(&lookup->addr.addr, addr, addrlen) == 0)
32- {
33- cache->flags &= ~F_REVERSE;
34- break;
35- }
36+ large (10000 entry) hosts files.
37+
38+ Note that we only do this process when bulk-reading hosts files,
39+ for incremental reads, rhash is NULL, and we use cache lookups
40+ instead.
41+ */
42
43- /* maintain address hash chain, insert new unique address */
44- if (!lookup)
45+ if (rhash)
46 {
47- cache->next = rhash[j];
48- rhash[j] = cache;
49+ /* hash address */
50+ for (j = 0, i = 0; i < addrlen; i++)
51+ j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
52+
53+ for (lookup = rhash[j]; lookup; lookup = lookup->next)
54+ if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
55+ memcmp(&lookup->addr.addr, addr, addrlen) == 0)
56+ {
57+ cache->flags &= ~F_REVERSE;
58+ break;
59+ }
60+
61+ /* maintain address hash chain, insert new unique address */
62+ if (!lookup)
63+ {
64+ cache->next = rhash[j];
65+ rhash[j] = cache;
66+ }
67 }
68-
69+ else
70+ {
71+ /* incremental read, lookup in cache */
72+ lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
73+ if (lookup && lookup->flags & F_HOSTS)
74+ cache->flags &= ~F_REVERSE;
75+ }
76+
77 cache->uid = index;
78 memcpy(&cache->addr.addr, addr, addrlen);
79 cache_hash(cache);
80@@ -912,7 +927,7 @@ static int gettok(FILE *f, char *token)
81 }
82 }
83
84-static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
85+int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
86 {
87 FILE *f = fopen(filename, "r");
88 char *token = daemon->namebuff, *domain_suffix = NULL;
89@@ -958,7 +973,7 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
90 addr_count++;
91
92 /* rehash every 1000 names. */
93- if ((name_count - cache_size) > 1000)
94+ if (rhash && ((name_count - cache_size) > 1000))
95 {
96 rehash(name_count);
97 cache_size = name_count;
98@@ -1005,10 +1020,13 @@ static int read_hostsfile(char *filename, unsigned int index, int cache_size, st
99 }
100
101 fclose(f);
102- rehash(name_count);
103-
104- my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
105
106+ if (rhash)
107+ {
108+ rehash(name_count);
109+ my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
110+ }
111+
112 return name_count;
113 }
114
115@@ -1118,14 +1136,19 @@ void cache_reload(void)
116 my_syslog(LOG_INFO, _("cleared cache"));
117 return;
118 }
119-
120+
121 if (!option_bool(OPT_NO_HOSTS))
122 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
123-
124+
125 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
126 for (ah = daemon->addn_hosts; ah; ah = ah->next)
127 if (!(ah->flags & AH_INACTIVE))
128 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
129+
130+#ifdef HAVE_INOTIFY
131+ set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
132+#endif
133+
134 }
135
136 #ifdef HAVE_DHCP
137@@ -1505,7 +1528,13 @@ char *record_source(unsigned int index)
138 for (ah = daemon->addn_hosts; ah; ah = ah->next)
139 if (ah->index == index)
140 return ah->fname;
141-
142+
143+#ifdef HAVE_INOTIFY
144+ for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
145+ if (ah->index == index)
146+ return ah->fname;
147+#endif
148+
149 return "<unknown>";
150 }
151
152diff --git a/src/dnsmasq.c b/src/dnsmasq.c
153index bc4f47170705..2c629fe422aa 100644
154--- a/src/dnsmasq.c
155+++ b/src/dnsmasq.c
156@@ -145,8 +145,8 @@ int main (int argc, char **argv)
157 #endif
158
159 #ifndef HAVE_INOTIFY
160- if (daemon->inotify_hosts)
161- die(_("dhcp-hostsdir not supported on this platform"), NULL, EC_BADCONF);
162+ if (daemon->dynamic_dirs)
163+ die(_("dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"), NULL, EC_BADCONF);
164 #endif
165
166 if (option_bool(OPT_DNSSEC_VALID))
167@@ -324,8 +324,7 @@ int main (int argc, char **argv)
168 }
169
170 #ifdef HAVE_INOTIFY
171- if ((!option_bool(OPT_NO_POLL) && daemon->port != 0) ||
172- daemon->dhcp || daemon->doing_dhcp6)
173+ if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
174 inotify_dnsmasq_init();
175 else
176 daemon->inotifyfd = -1;
177@@ -1400,7 +1399,7 @@ void clear_cache_and_reload(time_t now)
178 dhcp_read_ethers();
179 reread_dhcp();
180 #ifdef HAVE_INOTIFY
181- set_dhcp_inotify();
182+ set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
183 #endif
184 dhcp_update_configs(daemon->dhcp_conf);
185 lease_update_from_configs();
186diff --git a/src/dnsmasq.h b/src/dnsmasq.h
187index 8091634f69db..0c322a93993e 100644
188--- a/src/dnsmasq.h
189+++ b/src/dnsmasq.h
190@@ -554,6 +554,9 @@ struct resolvc {
191 #define AH_DIR 1
192 #define AH_INACTIVE 2
193 #define AH_WD_DONE 4
194+#define AH_HOSTS 8
195+#define AH_DHCP_HST 16
196+#define AH_DHCP_OPT 32
197 struct hostsfile {
198 struct hostsfile *next;
199 int flags;
200@@ -965,7 +968,7 @@ extern struct daemon {
201 int doing_ra, doing_dhcp6;
202 struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
203 struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
204- struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *inotify_hosts;
205+ struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
206 int dhcp_max, tftp_max;
207 int dhcp_server_port, dhcp_client_port;
208 int start_tftp_port, end_tftp_port;
209@@ -1071,6 +1074,8 @@ int cache_make_stat(struct txt_record *t);
210 char *cache_get_name(struct crec *crecp);
211 char *cache_get_cname_target(struct crec *crecp);
212 struct crec *cache_enumerate(int init);
213+int read_hostsfile(char *filename, unsigned int index, int cache_size,
214+ struct crec **rhash, int hashsz);
215
216 /* blockdata.c */
217 #ifdef HAVE_DNSSEC
218@@ -1204,7 +1209,8 @@ void reset_option_bool(unsigned int opt);
219 struct hostsfile *expand_filelist(struct hostsfile *list);
220 char *parse_server(char *arg, union mysockaddr *addr,
221 union mysockaddr *source_addr, char *interface, int *flags);
222-int option_read_hostsfile(char *file);
223+int option_read_dynfile(char *file, int flags);
224+
225 /* forward.c */
226 void reply_query(int fd, int family, time_t now);
227 void receive_query(struct listener *listen, time_t now);
228@@ -1494,7 +1500,5 @@ int detect_loop(char *query, int type);
229 #ifdef HAVE_INOTIFY
230 void inotify_dnsmasq_init();
231 int inotify_check(time_t now);
232-# ifdef HAVE_DHCP
233-void set_dhcp_inotify(void);
234-# endif
235+void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
236 #endif
237diff --git a/src/inotify.c b/src/inotify.c
238index 818fe8eddda4..c537f4c1562a 100644
239--- a/src/inotify.c
240+++ b/src/inotify.c
241@@ -19,11 +19,6 @@
242
243 #include <sys/inotify.h>
244
245-#ifdef HAVE_DHCP
246-static void check_for_dhcp_inotify(struct inotify_event *in, time_t now);
247-#endif
248-
249-
250 /* the strategy is to set a inotify on the directories containing
251 resolv files, for any files in the directory which are close-write
252 or moved into the directory.
253@@ -82,57 +77,28 @@ void inotify_dnsmasq_init()
254 }
255 }
256
257-int inotify_check(time_t now)
258+
259+/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
260+void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
261 {
262- int hit = 0;
263+ struct hostsfile *ah;
264
265- while (1)
266+ for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
267 {
268- int rc;
269- char *p;
270- struct resolvc *res;
271- struct inotify_event *in;
272-
273- while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
274-
275- if (rc <= 0)
276- break;
277-
278- for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
279+ DIR *dir_stream = NULL;
280+ struct dirent *ent;
281+ struct stat buf;
282+
283+ if (!(ah->flags & flag))
284+ continue;
285+
286+ if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
287 {
288- in = (struct inotify_event*)p;
289-
290- for (res = daemon->resolv_files; res; res = res->next)
291- if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
292- hit = 1;
293-
294-#ifdef HAVE_DHCP
295- if (daemon->dhcp || daemon->doing_dhcp6)
296- check_for_dhcp_inotify(in, now);
297-#endif
298+ my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
299+ ah->fname, strerror(errno));
300+ continue;
301 }
302- }
303- return hit;
304-}
305-
306-#ifdef HAVE_DHCP
307-/* initialisation for dhcp-hostdir. Set inotify watch for each directory, and read pre-existing files */
308-void set_dhcp_inotify(void)
309-{
310- struct hostsfile *ah;
311-
312- for (ah = daemon->inotify_hosts; ah; ah = ah->next)
313- {
314- DIR *dir_stream = NULL;
315- struct dirent *ent;
316- struct stat buf;
317-
318- if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
319- {
320- my_syslog(LOG_ERR, _("bad directory in dhcp-hostsdir %s"), ah->fname);
321- continue;
322- }
323-
324+
325 if (!(ah->flags & AH_WD_DONE))
326 {
327 ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
328@@ -142,7 +108,8 @@ void set_dhcp_inotify(void)
329 a race which misses files being added as we start */
330 if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
331 {
332- my_syslog(LOG_ERR, _("failed to create inotify for %s"), ah->fname);
333+ my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
334+ ah->fname, strerror(errno));
335 continue;
336 }
337
338@@ -167,54 +134,90 @@ void set_dhcp_inotify(void)
339
340 /* ignore non-regular files */
341 if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
342- option_read_hostsfile(path);
343-
344+ {
345+ if (ah->flags & AH_HOSTS)
346+ total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
347+#ifdef HAVE_DHCP
348+ else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
349+ option_read_dynfile(path, ah->flags);
350+#endif
351+ }
352+
353 free(path);
354 }
355 }
356 }
357 }
358
359-static void check_for_dhcp_inotify(struct inotify_event *in, time_t now)
360+int inotify_check(time_t now)
361 {
362+ int hit = 0;
363 struct hostsfile *ah;
364
365- /* ignore emacs backups and dotfiles */
366- if (in->len == 0 ||
367- in->name[in->len - 1] == '~' ||
368- (in->name[0] == '#' && in->name[in->len - 1] == '#') ||
369- in->name[0] == '.')
370- return;
371-
372- for (ah = daemon->inotify_hosts; ah; ah = ah->next)
373- if (ah->wd == in->wd)
374- {
375- size_t lendir = strlen(ah->fname);
376- char *path;
377-
378- if ((path = whine_malloc(lendir + in->len + 2)))
379- {
380- strcpy(path, ah->fname);
381- strcat(path, "/");
382- strcat(path, in->name);
383-
384- if (option_read_hostsfile(path))
385+ while (1)
386+ {
387+ int rc;
388+ char *p;
389+ struct resolvc *res;
390+ struct inotify_event *in;
391+
392+ while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
393+
394+ if (rc <= 0)
395+ break;
396+
397+ for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
398+ {
399+ in = (struct inotify_event*)p;
400+
401+ for (res = daemon->resolv_files; res; res = res->next)
402+ if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
403+ hit = 1;
404+
405+ /* ignore emacs backups and dotfiles */
406+ if (in->len == 0 ||
407+ in->name[in->len - 1] == '~' ||
408+ (in->name[0] == '#' && in->name[in->len - 1] == '#') ||
409+ in->name[0] == '.')
410+ continue;
411+
412+ for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
413+ if (ah->wd == in->wd)
414 {
415- /* Propogate the consequences of loading a new dhcp-host */
416- dhcp_update_configs(daemon->dhcp_conf);
417- lease_update_from_configs();
418- lease_update_file(now);
419- lease_update_dns(1);
420+ size_t lendir = strlen(ah->fname);
421+ char *path;
422+
423+ if ((path = whine_malloc(lendir + in->len + 2)))
424+ {
425+ strcpy(path, ah->fname);
426+ strcat(path, "/");
427+ strcat(path, in->name);
428+
429+ if (ah->flags & AH_HOSTS)
430+ read_hostsfile(path, ah->index, 0, NULL, 0);
431+#ifdef HAVE_DHCP
432+ else if (ah->flags & AH_DHCP_HST)
433+ {
434+ if (option_read_dynfile(path, AH_DHCP_HST))
435+ {
436+ /* Propogate the consequences of loading a new dhcp-host */
437+ dhcp_update_configs(daemon->dhcp_conf);
438+ lease_update_from_configs();
439+ lease_update_file(now);
440+ lease_update_dns(1);
441+ }
442+ }
443+ else if (ah->flags & AH_DHCP_OPT)
444+ option_read_dynfile(path, AH_DHCP_OPT);
445+#endif
446+
447+ free(path);
448+ }
449 }
450-
451- free(path);
452- }
453-
454- return;
455- }
456+ }
457+ }
458+ return hit;
459 }
460
461-#endif /* DHCP */
462-
463 #endif /* INOTIFY */
464
465diff --git a/src/option.c b/src/option.c
466index 22e11c37d374..6ef80117cc8c 100644
467--- a/src/option.c
468+++ b/src/option.c
469@@ -150,6 +150,8 @@ struct myoption {
470 #define LOPT_IGNORE_ADDR 338
471 #define LOPT_MINCTTL 339
472 #define LOPT_DHCP_INOTIFY 340
473+#define LOPT_DHOPT_INOTIFY 341
474+#define LOPT_HOST_INOTIFY 342
475
476 #ifdef HAVE_GETOPT_LONG
477 static const struct option opts[] =
478@@ -200,6 +202,7 @@ static const struct myoption opts[] =
479 { "local-ttl", 1, 0, 'T' },
480 { "no-negcache", 0, 0, 'N' },
481 { "addn-hosts", 1, 0, 'H' },
482+ { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
483 { "query-port", 1, 0, 'Q' },
484 { "except-interface", 1, 0, 'I' },
485 { "no-dhcp-interface", 1, 0, '2' },
486@@ -249,6 +252,7 @@ static const struct myoption opts[] =
487 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
488 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
489 { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
490+ { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
491 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
492 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
493 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
494@@ -338,9 +342,11 @@ static struct {
495 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
496 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
497 { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
498+ { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL },
499 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
500 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
501 { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
502+ { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
503 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
504 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
505 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
506@@ -1712,10 +1718,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
507 break;
508 #endif /* HAVE_DHCP */
509
510- case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
511- case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
512- case LOPT_DHCP_INOTIFY: /* dhcp-hostsdir */
513- case 'H': /* --addn-hosts */
514+ case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
515+ case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
516+ case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
517+ case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
518+ case LOPT_HOST_INOTIFY: /* --hostsdir */
519+ case 'H': /* --addn-hosts */
520 {
521 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
522 static unsigned int hosts_index = SRC_AH;
523@@ -1737,10 +1745,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
524 new->next = daemon->dhcp_opts_file;
525 daemon->dhcp_opts_file = new;
526 }
527- else if (option == LOPT_DHCP_INOTIFY)
528+ else
529 {
530- new->next = daemon->inotify_hosts;
531- daemon->inotify_hosts = new;
532+ new->next = daemon->dynamic_dirs;
533+ daemon->dynamic_dirs = new;
534+ if (option == LOPT_DHCP_INOTIFY)
535+ new->flags |= AH_DHCP_HST;
536+ else if (option == LOPT_DHOPT_INOTIFY)
537+ new->flags |= AH_DHCP_OPT;
538+ else if (option == LOPT_HOST_INOTIFY)
539+ new->flags |= AH_HOSTS;
540 }
541
542 break;
543@@ -4052,9 +4066,14 @@ static void read_file(char *file, FILE *f, int hard_opt)
544 }
545
546 #ifdef HAVE_DHCP
547-int option_read_hostsfile(char *file)
548+int option_read_dynfile(char *file, int flags)
549 {
550- return one_file(file, LOPT_BANK);
551+ if (flags & AH_DHCP_HST)
552+ return one_file(file, LOPT_BANK);
553+ else if (flags & AH_DHCP_OPT)
554+ return one_file(file, LOPT_OPTS);
555+
556+ return 0;
557 }
558 #endif
559
560--
5612.1.0
562