1 /*
2  * Copyright (c) 2008-2020, OARC, Inc.
3  * Copyright (c) 2007-2008, Internet Systems Consortium, Inc.
4  * Copyright (c) 2003-2007, The Measurement Factory, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #include "config.h"
38 
39 #include "config_hooks.h"
40 #include "xmalloc.h"
41 #include "syslog_debug.h"
42 #include "hashtbl.h"
43 #include "pcap.h"
44 #include "compat.h"
45 #include "response_time_index.h"
46 #include "input_mode.h"
47 #include "dnstap.h"
48 
49 #include "knowntlds.inc"
50 
51 #if defined(HAVE_LIBGEOIP) && defined(HAVE_GEOIP_H)
52 #define HAVE_GEOIP 1
53 #include <GeoIP.h>
54 #endif
55 #if defined(HAVE_LIBMAXMINDDB) && defined(HAVE_MAXMINDDB_H)
56 #define HAVE_MAXMINDDB 1
57 #include <maxminddb.h>
58 #endif
59 #include <unistd.h>
60 #include <errno.h>
61 #include <limits.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <strings.h>
65 #include <stdio.h>
66 #include <sys/types.h>
67 #include <pwd.h>
68 #include <grp.h>
69 #include <ctype.h>
70 
71 extern int input_mode;
72 extern int promisc_flag;
73 extern int monitor_flag;
74 extern int immediate_flag;
75 extern int threads_flag;
76 uint64_t   minfree_bytes      = 0;
77 int        output_format_xml  = 0;
78 int        output_format_json = 0;
79 #define MAX_HASH_SIZE 512
80 static hashtbl* dataset_hash         = NULL;
81 uint64_t        statistics_interval  = 60; /* default interval in seconds*/
82 int             dump_reports_on_exit = 0;
83 char*           geoip_v4_dat         = NULL;
84 int             geoip_v4_options     = 0;
85 char*           geoip_v6_dat         = NULL;
86 int             geoip_v6_options     = 0;
87 char*           geoip_asn_v4_dat     = NULL;
88 int             geoip_asn_v4_options = 0;
89 char*           geoip_asn_v6_dat     = NULL;
90 int             geoip_asn_v6_options = 0;
91 int             pcap_buffer_size     = 0;
92 int             no_wait_interval     = 0;
93 int             pt_timeout           = 100;
94 int             drop_ip_fragments    = 0;
95 #ifdef HAVE_GEOIP
96 enum geoip_backend asn_indexer_backend     = geoip_backend_libgeoip;
97 enum geoip_backend country_indexer_backend = geoip_backend_libgeoip;
98 #else
99 #ifdef HAVE_MAXMINDDB
100 enum geoip_backend asn_indexer_backend     = geoip_backend_libmaxminddb;
101 enum geoip_backend country_indexer_backend = geoip_backend_libmaxminddb;
102 #else
103 enum geoip_backend asn_indexer_backend     = geoip_backend_none;
104 enum geoip_backend country_indexer_backend = geoip_backend_none;
105 #endif
106 #endif
107 char* maxminddb_asn     = NULL;
108 char* maxminddb_country = NULL;
109 
110 extern int  ip_local_address(const char*, const char*);
111 extern void pcap_set_match_vlan(int);
112 
open_interface(const char * interface)113 int open_interface(const char* interface)
114 {
115     if (input_mode != INPUT_NONE && input_mode != INPUT_PCAP) {
116         dsyslog(LOG_ERR, "input mode already set");
117         return 0;
118     }
119     input_mode = INPUT_PCAP;
120     dsyslogf(LOG_INFO, "Opening interface %s", interface);
121     Pcap_init(interface, promisc_flag, monitor_flag, immediate_flag, threads_flag, pcap_buffer_size);
122     return 1;
123 }
124 
open_dnstap(enum dnstap_via via,const char * file_or_ip,const char * port,const char * user,const char * group,const char * umask)125 int open_dnstap(enum dnstap_via via, const char* file_or_ip, const char* port, const char* user, const char* group, const char* umask)
126 {
127     int   port_num = -1, mask = -1;
128     uid_t uid = -1;
129     gid_t gid = -1;
130 
131     if (input_mode != INPUT_NONE) {
132         if (input_mode == INPUT_DNSTAP) {
133             dsyslog(LOG_ERR, "only one DNSTAP input can be used at a time");
134         } else {
135             dsyslog(LOG_ERR, "input mode already set");
136         }
137         return 0;
138     }
139     if (port) {
140         port_num = atoi(port);
141         if (port_num < 0 || port_num > 65535) {
142             dsyslog(LOG_ERR, "invalid port for DNSTAP");
143             return 0;
144         }
145         dsyslogf(LOG_INFO, "Opening dnstap %s:%s", file_or_ip, port);
146     } else {
147         dsyslogf(LOG_INFO, "Opening dnstap %s", file_or_ip);
148     }
149     if (user && *user != 0) {
150         struct passwd* pw = getpwnam(user);
151         if (!pw) {
152             dsyslog(LOG_ERR, "invalid USER for DNSTAP UNIX socket, does not exist");
153             return 0;
154         }
155         uid = pw->pw_uid;
156         dsyslogf(LOG_INFO, "Using user %s [%d] for DNSTAP", user, uid);
157     }
158     if (group) {
159         struct group* gr = getgrnam(group);
160         if (!gr) {
161             dsyslog(LOG_ERR, "invalid GROUP for DNSTAP UNIX socket, does not exist");
162             return 0;
163         }
164         gid = gr->gr_gid;
165         dsyslogf(LOG_INFO, "Using group %s [%d] for DNSTAP", group, gid);
166     }
167     if (umask) {
168         unsigned int m;
169         if (sscanf(umask, "%o", &m) != 1) {
170             dsyslog(LOG_ERR, "invalid UMASK for DNSTAP UNIX socket, should be octal");
171             return 0;
172         }
173         if (m > 0777) {
174             dsyslog(LOG_ERR, "invalid UMASK for DNSTAP UNIX socket, too large value, maximum 0777");
175             return 0;
176         }
177         mask = (int)m;
178         dsyslogf(LOG_INFO, "Using umask %04o for DNSTAP", mask);
179     }
180     dnstap_init(via, file_or_ip, port_num, uid, gid, mask);
181     input_mode = INPUT_DNSTAP;
182     return 1;
183 }
184 
set_bpf_program(const char * s)185 int set_bpf_program(const char* s)
186 {
187     extern char* bpf_program_str;
188     dsyslogf(LOG_INFO, "BPF program is: %s", s);
189     if (bpf_program_str)
190         xfree(bpf_program_str);
191     bpf_program_str = xstrdup(s);
192     if (NULL == bpf_program_str)
193         return 0;
194     return 1;
195 }
196 
add_local_address(const char * s,const char * m)197 int add_local_address(const char* s, const char* m)
198 {
199     dsyslogf(LOG_INFO, "adding local address %s%s%s", s, m ? " mask " : "", m ? m : "");
200     return ip_local_address(s, m);
201 }
202 
set_run_dir(const char * dir)203 int set_run_dir(const char* dir)
204 {
205     dsyslogf(LOG_INFO, "setting current directory to %s", dir);
206     if (chdir(dir) < 0) {
207         char errbuf[512];
208         perror(dir);
209         dsyslogf(LOG_ERR, "chdir: %s: %s", dir, dsc_strerror(errno, errbuf, sizeof(errbuf)));
210         return 0;
211     }
212     return 1;
213 }
214 
set_pid_file(const char * s)215 int set_pid_file(const char* s)
216 {
217     extern char* pid_file_name;
218     dsyslogf(LOG_INFO, "PID file is: %s", s);
219     if (pid_file_name)
220         xfree(pid_file_name);
221     pid_file_name = xstrdup(s);
222     if (NULL == pid_file_name)
223         return 0;
224     return 1;
225 }
226 
227 static unsigned int
dataset_hashfunc(const void * key)228 dataset_hashfunc(const void* key)
229 {
230     return hashendian(key, strlen(key), 0);
231 }
232 
233 static int
dataset_cmpfunc(const void * a,const void * b)234 dataset_cmpfunc(const void* a, const void* b)
235 {
236     return strcasecmp(a, b);
237 }
238 
set_statistics_interval(const char * s)239 int set_statistics_interval(const char* s)
240 {
241     dsyslogf(LOG_INFO, "Setting statistics interval to: %s", s);
242     statistics_interval = strtoull(s, NULL, 10);
243     if (statistics_interval == ULLONG_MAX) {
244         char errbuf[512];
245         dsyslogf(LOG_ERR, "strtoull: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
246         return 0;
247     }
248     if (!statistics_interval) {
249         dsyslog(LOG_ERR, "statistics_interval can not be zero");
250         return 0;
251     }
252     return 1;
253 }
254 
255 static int response_time_indexer_used = 0;
256 
add_dataset(const char * name,const char * layer_ignored,const char * firstname,const char * firstindexer,const char * secondname,const char * secondindexer,const char * filtername,dataset_opt opts)257 int add_dataset(const char* name, const char* layer_ignored,
258     const char* firstname, const char* firstindexer,
259     const char* secondname, const char* secondindexer, const char* filtername, dataset_opt opts)
260 {
261     char* dup;
262 
263     if (!strcmp(firstindexer, "response_time") || !strcmp(secondindexer, "response_time")) {
264         if (response_time_indexer_used) {
265             dsyslogf(LOG_ERR, "unable to create dataset %s: response_time indexer already used, can only be used in one dataset", name);
266             return 0;
267         }
268         response_time_indexer_used = 1;
269     }
270 
271     if (!dataset_hash) {
272         if (!(dataset_hash = hash_create(MAX_HASH_SIZE, dataset_hashfunc, dataset_cmpfunc, 0, xfree, xfree))) {
273             dsyslogf(LOG_ERR, "unable to create dataset %s due to internal error", name);
274             return 0;
275         }
276     }
277 
278     if (hash_find(name, dataset_hash)) {
279         dsyslogf(LOG_ERR, "unable to create dataset %s: already exists", name);
280         return 0;
281     }
282 
283     if (!(dup = xstrdup(name))) {
284         dsyslogf(LOG_ERR, "unable to create dataset %s due to internal error", name);
285         return 0;
286     }
287 
288     if (hash_add(dup, dup, dataset_hash)) {
289         xfree(dup);
290         dsyslogf(LOG_ERR, "unable to create dataset %s due to internal error", name);
291         return 0;
292     }
293 
294     dsyslogf(LOG_INFO, "creating dataset %s", name);
295     return dns_message_add_array(name, firstname, firstindexer, secondname, secondindexer, filtername, opts);
296 }
297 
set_bpf_vlan_tag_byte_order(const char * which)298 int set_bpf_vlan_tag_byte_order(const char* which)
299 {
300     extern int vlan_tag_needs_byte_conversion;
301     dsyslogf(LOG_INFO, "bpf_vlan_tag_byte_order is %s", which);
302     if (0 == strcmp(which, "host")) {
303         vlan_tag_needs_byte_conversion = 0;
304         return 1;
305     }
306     if (0 == strcmp(which, "net")) {
307         vlan_tag_needs_byte_conversion = 1;
308         return 1;
309     }
310     dsyslogf(LOG_ERR, "unknown bpf_vlan_tag_byte_order '%s'", which);
311     return 0;
312 }
313 
set_match_vlan(const char * s)314 int set_match_vlan(const char* s)
315 {
316     int i;
317     dsyslogf(LOG_INFO, "match_vlan %s", s);
318     i = atoi(s);
319     if (0 == i && 0 != strcmp(s, "0"))
320         return 0;
321     pcap_set_match_vlan(i);
322     return 1;
323 }
324 
set_minfree_bytes(const char * s)325 int set_minfree_bytes(const char* s)
326 {
327     dsyslogf(LOG_INFO, "minfree_bytes %s", s);
328     minfree_bytes = strtoull(s, NULL, 10);
329     return 1;
330 }
331 
set_output_format(const char * output_format)332 int set_output_format(const char* output_format)
333 {
334     dsyslogf(LOG_INFO, "output_format %s", output_format);
335 
336     if (!strcmp(output_format, "XML")) {
337         output_format_xml = 1;
338         return 1;
339     } else if (!strcmp(output_format, "JSON")) {
340         output_format_json = 1;
341         return 1;
342     }
343 
344     dsyslogf(LOG_ERR, "unknown output format '%s'", output_format);
345     return 0;
346 }
347 
set_dump_reports_on_exit(void)348 void set_dump_reports_on_exit(void)
349 {
350     dsyslog(LOG_INFO, "dump_reports_on_exit");
351 
352     dump_reports_on_exit = 1;
353 }
354 
set_geoip_v4_dat(const char * dat,int options)355 int set_geoip_v4_dat(const char* dat, int options)
356 {
357     char errbuf[512];
358 
359     geoip_v4_options = options;
360     if (geoip_v4_dat)
361         xfree(geoip_v4_dat);
362     if ((geoip_v4_dat = xstrdup(dat))) {
363         dsyslogf(LOG_INFO, "GeoIP v4 dat %s %d", geoip_v4_dat, geoip_v4_options);
364         return 1;
365     }
366 
367     dsyslogf(LOG_ERR, "unable to set GeoIP v4 dat, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
368     return 0;
369 }
370 
set_geoip_v6_dat(const char * dat,int options)371 int set_geoip_v6_dat(const char* dat, int options)
372 {
373     char errbuf[512];
374 
375     geoip_v6_options = options;
376     if (geoip_v6_dat)
377         xfree(geoip_v6_dat);
378     if ((geoip_v6_dat = xstrdup(dat))) {
379         dsyslogf(LOG_INFO, "GeoIP v6 dat %s %d", geoip_v6_dat, geoip_v6_options);
380         return 1;
381     }
382 
383     dsyslogf(LOG_ERR, "unable to set GeoIP v6 dat, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
384     return 0;
385 }
386 
set_geoip_asn_v4_dat(const char * dat,int options)387 int set_geoip_asn_v4_dat(const char* dat, int options)
388 {
389     char errbuf[512];
390 
391     geoip_asn_v4_options = options;
392     if (geoip_asn_v4_dat)
393         xfree(geoip_asn_v4_dat);
394     if ((geoip_asn_v4_dat = xstrdup(dat))) {
395         dsyslogf(LOG_INFO, "GeoIP ASN v4 dat %s %d", geoip_asn_v4_dat, geoip_asn_v4_options);
396         return 1;
397     }
398 
399     dsyslogf(LOG_ERR, "unable to set GeoIP ASN v4 dat, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
400     return 0;
401 }
402 
set_geoip_asn_v6_dat(const char * dat,int options)403 int set_geoip_asn_v6_dat(const char* dat, int options)
404 {
405     char errbuf[512];
406 
407     geoip_asn_v6_options = options;
408     if (geoip_asn_v6_dat)
409         xfree(geoip_asn_v6_dat);
410     if ((geoip_asn_v6_dat = xstrdup(dat))) {
411         dsyslogf(LOG_INFO, "GeoIP ASN v6 dat %s %d", geoip_asn_v6_dat, geoip_asn_v6_options);
412         return 1;
413     }
414 
415     dsyslogf(LOG_ERR, "unable to set GeoIP ASN v6 dat, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
416     return 0;
417 }
418 
set_asn_indexer_backend(enum geoip_backend backend)419 int set_asn_indexer_backend(enum geoip_backend backend)
420 {
421     switch (backend) {
422     case geoip_backend_libgeoip:
423         dsyslog(LOG_INFO, "asn_indexer using GeoIP backend");
424         break;
425     case geoip_backend_libmaxminddb:
426         dsyslog(LOG_INFO, "asn_indexer using MaxMind DB backend");
427         break;
428     default:
429         return 0;
430     }
431 
432     asn_indexer_backend = backend;
433 
434     return 1;
435 }
436 
set_country_indexer_backend(enum geoip_backend backend)437 int set_country_indexer_backend(enum geoip_backend backend)
438 {
439     switch (backend) {
440     case geoip_backend_libgeoip:
441         dsyslog(LOG_INFO, "country_indexer using GeoIP backend");
442         break;
443     case geoip_backend_libmaxminddb:
444         dsyslog(LOG_INFO, "country_indexer using MaxMind DB backend");
445         break;
446     default:
447         return 0;
448     }
449 
450     country_indexer_backend = backend;
451 
452     return 1;
453 }
454 
set_maxminddb_asn(const char * file)455 int set_maxminddb_asn(const char* file)
456 {
457     char errbuf[512];
458 
459     if (maxminddb_asn)
460         xfree(maxminddb_asn);
461     if ((maxminddb_asn = xstrdup(file))) {
462         dsyslogf(LOG_INFO, "Maxmind ASN database %s", maxminddb_asn);
463         return 1;
464     }
465 
466     dsyslogf(LOG_ERR, "unable to set Maxmind ASN database, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
467     return 0;
468 }
469 
set_maxminddb_country(const char * file)470 int set_maxminddb_country(const char* file)
471 {
472     char errbuf[512];
473 
474     if (maxminddb_country)
475         xfree(maxminddb_country);
476     if ((maxminddb_country = xstrdup(file))) {
477         dsyslogf(LOG_INFO, "Maxmind ASN database %s", maxminddb_country);
478         return 1;
479     }
480 
481     dsyslogf(LOG_ERR, "unable to set Maxmind ASN database, strdup: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
482     return 0;
483 }
484 
set_pcap_buffer_size(const char * s)485 int set_pcap_buffer_size(const char* s)
486 {
487     dsyslogf(LOG_INFO, "Setting pcap buffer size to: %s", s);
488     pcap_buffer_size = atoi(s);
489     if (pcap_buffer_size < 0) {
490         dsyslog(LOG_ERR, "pcap_buffer_size can not be negative");
491         return 0;
492     }
493     return 1;
494 }
495 
set_no_wait_interval(void)496 void set_no_wait_interval(void)
497 {
498     dsyslog(LOG_INFO, "not waiting on interval sync to start");
499 
500     no_wait_interval = 1;
501 }
502 
set_pt_timeout(const char * s)503 int set_pt_timeout(const char* s)
504 {
505     dsyslogf(LOG_INFO, "Setting pcap-thread timeout to: %s", s);
506     pt_timeout = atoi(s);
507     if (pt_timeout < 0) {
508         dsyslog(LOG_ERR, "pcap-thread timeout can not be negative");
509         return 0;
510     }
511     return 1;
512 }
513 
set_drop_ip_fragments(void)514 void set_drop_ip_fragments(void)
515 {
516     dsyslog(LOG_INFO, "dropping ip fragments");
517 
518     drop_ip_fragments = 1;
519 }
520 
set_dns_port(const char * s)521 int set_dns_port(const char* s)
522 {
523     int port;
524     dsyslogf(LOG_INFO, "dns_port %s", s);
525     port = atoi(s);
526     if (port < 0 || port > 65535) {
527         dsyslog(LOG_ERR, "invalid dns_port");
528         return 0;
529     }
530     port53 = port;
531     return 1;
532 }
533 
set_response_time_mode(const char * s)534 int set_response_time_mode(const char* s)
535 {
536     if (!strcmp(s, "bucket")) {
537         response_time_set_mode(response_time_bucket);
538     } else if (!strcmp(s, "log10")) {
539         response_time_set_mode(response_time_log10);
540     } else if (!strcmp(s, "log2")) {
541         response_time_set_mode(response_time_log2);
542     } else {
543         dsyslogf(LOG_ERR, "invalid response time mode %s", s);
544         return 0;
545     }
546     dsyslogf(LOG_INFO, "set response time mode to %s", s);
547     return 1;
548 }
549 
set_response_time_max_queries(const char * s)550 int set_response_time_max_queries(const char* s)
551 {
552     int max_queries = atoi(s);
553     if (max_queries < 1) {
554         dsyslogf(LOG_ERR, "invalid response time max queries %s", s);
555         return 0;
556     }
557     response_time_set_max_queries(max_queries);
558     dsyslogf(LOG_INFO, "set response time max queries to %d", max_queries);
559     return 1;
560 }
561 
set_response_time_full_mode(const char * s)562 int set_response_time_full_mode(const char* s)
563 {
564     if (!strcmp(s, "drop_query")) {
565         response_time_set_full_mode(response_time_drop_query);
566     } else if (!strcmp(s, "drop_oldest")) {
567         response_time_set_full_mode(response_time_drop_oldest);
568     } else {
569         dsyslogf(LOG_ERR, "invalid response time full mode %s", s);
570         return 0;
571     }
572     dsyslogf(LOG_INFO, "set response time full mode to %s", s);
573     return 1;
574 }
575 
set_response_time_max_seconds(const char * s)576 int set_response_time_max_seconds(const char* s)
577 {
578     int max_seconds = atoi(s);
579     if (max_seconds < 1) {
580         dsyslogf(LOG_ERR, "invalid response time max seconds %s", s);
581         return 0;
582     }
583     response_time_set_max_sec(max_seconds);
584     dsyslogf(LOG_INFO, "set response time max seconds to %d", max_seconds);
585     return 1;
586 }
587 
set_response_time_max_sec_mode(const char * s)588 int set_response_time_max_sec_mode(const char* s)
589 {
590     if (!strcmp(s, "ceil")) {
591         response_time_set_max_sec_mode(response_time_ceil);
592     } else if (!strcmp(s, "timed_out")) {
593         response_time_set_max_sec_mode(response_time_timed_out);
594     } else {
595         dsyslogf(LOG_ERR, "invalid response time max sec mode %s", s);
596         return 0;
597     }
598     dsyslogf(LOG_INFO, "set response time max sec mode to %s", s);
599     return 1;
600 }
601 
set_response_time_bucket_size(const char * s)602 int set_response_time_bucket_size(const char* s)
603 {
604     int bucket_size = atoi(s);
605     if (bucket_size < 1) {
606         dsyslogf(LOG_ERR, "invalid response time bucket size %s", s);
607         return 0;
608     }
609     response_time_set_bucket_size(bucket_size);
610     dsyslogf(LOG_INFO, "set response time bucket size to %d", bucket_size);
611     return 1;
612 }
613 
614 const char** KnownTLDS = KnownTLDS_static;
615 
load_knowntlds(const char * file)616 int load_knowntlds(const char* file)
617 {
618     FILE*  fp;
619     char * buffer        = 0, *p;
620     size_t bufsize       = 0;
621     char** new_KnownTLDS = 0;
622     size_t new_size      = 0;
623 
624     if (KnownTLDS != KnownTLDS_static) {
625         dsyslog(LOG_ERR, "Known TLDs already loaded once");
626         return 0;
627     }
628 
629     if (!(fp = fopen(file, "r"))) {
630         dsyslogf(LOG_ERR, "unable to open %s", file);
631         return 0;
632     }
633 
634     if (!(new_KnownTLDS = xrealloc(new_KnownTLDS, (new_size + 1) * sizeof(char*)))) {
635         dsyslog(LOG_ERR, "out of memory");
636         return 0;
637     }
638     new_KnownTLDS[new_size] = ".";
639     new_size++;
640 
641     while (getline(&buffer, &bufsize, fp) > 0 && buffer) {
642         for (p = buffer; *p; p++) {
643             if (*p == '\r' || *p == '\n') {
644                 *p = 0;
645                 break;
646             }
647             *p = tolower(*p);
648         }
649         if (buffer[0] == '#') {
650             continue;
651         }
652 
653         if (!(new_KnownTLDS = xrealloc(new_KnownTLDS, (new_size + 1) * sizeof(char*)))) {
654             dsyslog(LOG_ERR, "out of memory");
655             return 0;
656         }
657         new_KnownTLDS[new_size] = xstrdup(buffer);
658         if (!new_KnownTLDS[new_size]) {
659             dsyslog(LOG_ERR, "out of memory");
660             return 0;
661         }
662         new_size++;
663     }
664     free(buffer);
665     fclose(fp);
666 
667     if (!(new_KnownTLDS = xrealloc(new_KnownTLDS, (new_size + 1) * sizeof(char*)))) {
668         dsyslog(LOG_ERR, "out of memory");
669         return 0;
670     }
671     new_KnownTLDS[new_size] = 0;
672 
673     KnownTLDS = (const char**)new_KnownTLDS;
674     dsyslogf(LOG_INFO, "loaded %zd known TLDs from %s", new_size - 1, file);
675 
676     return 1;
677 }
678