1
|
/*-
|
2
|
* Copyright (c) 2010 Ermal Lu?i <eri@pfsense.org>
|
3
|
* All rights reserved.
|
4
|
*
|
5
|
* Redistribution and use in source and binary forms, with or without
|
6
|
* modification, are permitted provided that the following conditions
|
7
|
* are met:
|
8
|
* 1. Redistributions of source code must retain the above copyright
|
9
|
* notice, this list of conditions and the following disclaimer.
|
10
|
* 2. Redistributions in binary form must reproduce the above copyright
|
11
|
* notice, this list of conditions and the following disclaimer in the
|
12
|
* documentation and/or other materials provided with the distribution.
|
13
|
*
|
14
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
15
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
18
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
19
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
20
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
21
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
22
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
23
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
24
|
* SUCH DAMAGE.
|
25
|
*/
|
26
|
|
27
|
|
28
|
/*
|
29
|
* The parsing code is taken from dnsmasq isc.c file and modified to work
|
30
|
* in this code.
|
31
|
*/
|
32
|
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
33
|
|
34
|
This program is free software; you can redistribute it and/or modify
|
35
|
it under the terms of the GNU General Public License as published by
|
36
|
the Free Software Foundation; version 2 dated June, 1991, or
|
37
|
(at your option) version 3 dated 29 June, 2007.
|
38
|
|
39
|
This program is distributed in the hope that it will be useful,
|
40
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
41
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
42
|
GNU General Public License for more details.
|
43
|
|
44
|
You should have received a copy of the GNU General Public License
|
45
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
46
|
*/
|
47
|
/* Code in this file is based on contributions by John Volpe. */
|
48
|
|
49
|
#include <sys/types.h>
|
50
|
#include <sys/socket.h>
|
51
|
#include <sys/event.h>
|
52
|
#include <sys/time.h>
|
53
|
#include <sys/stat.h>
|
54
|
#include <sys/queue.h>
|
55
|
|
56
|
#include <netinet/in.h>
|
57
|
#include <arpa/nameser.h>
|
58
|
#include <arpa/inet.h>
|
59
|
|
60
|
#include <syslog.h>
|
61
|
#include <stdarg.h>
|
62
|
#include <time.h>
|
63
|
#include <signal.h>
|
64
|
|
65
|
#define _WITH_DPRINTF
|
66
|
#include <stdio.h>
|
67
|
#include <stdlib.h>
|
68
|
#include <string.h>
|
69
|
#include <fcntl.h>
|
70
|
#include <unistd.h>
|
71
|
|
72
|
#include <errno.h>
|
73
|
|
74
|
#define MAXTOK 64
|
75
|
#define PIDFILE "/var/run/dhcpleases.pid"
|
76
|
|
77
|
struct isc_lease {
|
78
|
char *name, *fqdn;
|
79
|
time_t expires;
|
80
|
struct in_addr addr;
|
81
|
LIST_ENTRY(isc_lease) next;
|
82
|
};
|
83
|
|
84
|
LIST_HEAD(isc_leases, isc_lease) leases =
|
85
|
LIST_HEAD_INITIALIZER(leases);
|
86
|
static char *leasefile = NULL;
|
87
|
static char *pidfile = NULL;
|
88
|
static char *HOSTS = NULL;
|
89
|
static FILE *fp = NULL;
|
90
|
static char *domain_suffix = NULL;
|
91
|
static char *command = NULL;
|
92
|
static size_t hostssize = 0;
|
93
|
static size_t foreground = 0;
|
94
|
|
95
|
static int fexist(char *);
|
96
|
static int fsize(char *);
|
97
|
static int legal_char(char);
|
98
|
static int canonicalise(char *);
|
99
|
static int hostname_isequal(char *, char *);
|
100
|
static int next_token (char *, int, FILE *);
|
101
|
static time_t convert_time(struct tm);
|
102
|
static int load_dhcp(time_t);
|
103
|
|
104
|
static int write_status(void);
|
105
|
static void cleanup(void);
|
106
|
static void signal_process(void);
|
107
|
static void handle_signal(int);
|
108
|
|
109
|
/* Check if file exists */
|
110
|
static int
|
111
|
fexist(char * filename)
|
112
|
{
|
113
|
struct stat buf;
|
114
|
|
115
|
if (( stat (filename, &buf)) < 0)
|
116
|
return (0);
|
117
|
|
118
|
if (! S_ISREG(buf.st_mode))
|
119
|
return (0);
|
120
|
|
121
|
return(1);
|
122
|
}
|
123
|
|
124
|
static int
|
125
|
fsize(char * filename)
|
126
|
{
|
127
|
struct stat buf;
|
128
|
|
129
|
if (( stat (filename, &buf)) < 0)
|
130
|
return (-1);
|
131
|
|
132
|
if (! S_ISREG(buf.st_mode))
|
133
|
return (-1);
|
134
|
|
135
|
return(buf.st_size);
|
136
|
}
|
137
|
|
138
|
/*
|
139
|
* check for legal char a-z A-Z 0-9 -
|
140
|
* (also / , used for RFC2317 and _ used in windows queries
|
141
|
* and space, for DNS-SD stuff)
|
142
|
*/
|
143
|
static int
|
144
|
legal_char(char c) {
|
145
|
if ((c >= 'A' && c <= 'Z') ||
|
146
|
(c >= 'a' && c <= 'z') ||
|
147
|
(c >= '0' && c <= '9') ||
|
148
|
c == '-' || c == '/' || c == '_' || c == ' ')
|
149
|
return (1);
|
150
|
return (0);
|
151
|
}
|
152
|
|
153
|
/*
|
154
|
* check for legal chars and remove trailing .
|
155
|
* also fail empty string and label > 63 chars
|
156
|
*/
|
157
|
static int
|
158
|
canonicalise(char *s) {
|
159
|
size_t dotgap = 0, l = strlen(s);
|
160
|
char c;
|
161
|
int nowhite = 0;
|
162
|
|
163
|
if (l == 0 || l > MAXDNAME)
|
164
|
return (0);
|
165
|
|
166
|
if (s[l-1] == '.') {
|
167
|
if (l == 1)
|
168
|
return (0);
|
169
|
s[l-1] = 0;
|
170
|
}
|
171
|
|
172
|
while ((c = *s)) {
|
173
|
if (c == '.')
|
174
|
dotgap = 0;
|
175
|
else if (!legal_char(c) || (++dotgap > MAXLABEL))
|
176
|
return (0);
|
177
|
else if (c != ' ')
|
178
|
nowhite = 1;
|
179
|
s++;
|
180
|
}
|
181
|
|
182
|
return (nowhite);
|
183
|
}
|
184
|
|
185
|
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
|
186
|
static int
|
187
|
hostname_isequal(char *a, char *b) {
|
188
|
unsigned int c1, c2;
|
189
|
|
190
|
do {
|
191
|
c1 = (unsigned char) *a++;
|
192
|
c2 = (unsigned char) *b++;
|
193
|
|
194
|
if (c1 >= 'A' && c1 <= 'Z')
|
195
|
c1 += 'a' - 'A';
|
196
|
if (c2 >= 'A' && c2 <= 'Z')
|
197
|
c2 += 'a' - 'A';
|
198
|
|
199
|
if (c1 != c2)
|
200
|
return 0;
|
201
|
} while (c1);
|
202
|
|
203
|
return (1);
|
204
|
}
|
205
|
|
206
|
static int
|
207
|
next_token (char *token, int buffsize, FILE * fp)
|
208
|
{
|
209
|
int c, count = 0;
|
210
|
char *cp = token;
|
211
|
|
212
|
while((c = getc(fp)) != EOF) {
|
213
|
if (c == '#')
|
214
|
do {
|
215
|
c = getc(fp);
|
216
|
} while (c != '\n' && c != EOF);
|
217
|
|
218
|
if (c == ' ' || c == '\t' || c == '\n' || c == ';') {
|
219
|
if (count)
|
220
|
break;
|
221
|
} else if ((c != '"') && (count<buffsize-1)) {
|
222
|
*cp++ = c;
|
223
|
count++;
|
224
|
}
|
225
|
}
|
226
|
*cp = 0;
|
227
|
#if DEBUG
|
228
|
printf("|TOEN: %s, %d\n", token, count);
|
229
|
#endif
|
230
|
return count ? 1 : 0;
|
231
|
}
|
232
|
|
233
|
/*
|
234
|
* There doesn't seem to be a universally available library function
|
235
|
* which converts broken-down _GMT_ time to seconds-in-epoch.
|
236
|
* The following was borrowed from ISC dhcpd sources, where
|
237
|
* it is noted that it might not be entirely accurate for odd seconds.
|
238
|
* Since we're trying to get the same answer as dhcpd, that's just
|
239
|
* fine here.
|
240
|
*/
|
241
|
static time_t
|
242
|
convert_time(struct tm lease_time) {
|
243
|
static const int months [11] = { 31, 59, 90, 120, 151, 181,
|
244
|
212, 243, 273, 304, 334 };
|
245
|
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
|
246
|
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
|
247
|
(lease_time.tm_mon > 1 /* Days in months this year */
|
248
|
? months [lease_time.tm_mon - 2]
|
249
|
: 0) +
|
250
|
(lease_time.tm_mon > 2 && /* Leap day this year */
|
251
|
!((lease_time.tm_year - 1972) & 3)) +
|
252
|
lease_time.tm_mday - 1) * 24) + /* Day of month */
|
253
|
lease_time.tm_hour) * 60) +
|
254
|
lease_time.tm_min) * 60) + lease_time.tm_sec;
|
255
|
|
256
|
return (time);
|
257
|
}
|
258
|
|
259
|
static int
|
260
|
load_dhcp(time_t now) {
|
261
|
char namebuff[256];
|
262
|
char *hostname = namebuff, *suffix = NULL;
|
263
|
char token[MAXTOK], *dot;
|
264
|
struct in_addr host_address;
|
265
|
time_t ttd, tts;
|
266
|
struct isc_lease *lease, *tmp;
|
267
|
|
268
|
rewind(fp);
|
269
|
LIST_INIT(&leases);
|
270
|
|
271
|
while ((next_token(token, MAXTOK, fp))) {
|
272
|
if (strcmp(token, "lease") == 0) {
|
273
|
*hostname = 0;
|
274
|
ttd = tts = (time_t)(-1);
|
275
|
if (next_token(token, MAXTOK, fp) &&
|
276
|
(inet_pton(AF_INET, token, &host_address))) {
|
277
|
if (next_token(token, MAXTOK, fp) && *token == '{') {
|
278
|
while (next_token(token, MAXTOK, fp) && *token != '}') {
|
279
|
#if DEBUG
|
280
|
printf("token: %s\n", token);
|
281
|
#endif
|
282
|
if ((strcmp(token, "client-hostname") == 0) ||
|
283
|
(strcmp(token, "hostname") == 0)) {
|
284
|
if (next_token(hostname, MAXDNAME, fp)) {
|
285
|
if (*hostname == '}') {
|
286
|
*hostname = 0;
|
287
|
} else if (!canonicalise(hostname)) {
|
288
|
if (foreground)
|
289
|
printf("bad name(%s) in %s\n", hostname, leasefile);
|
290
|
else
|
291
|
syslog(LOG_ERR, "bad name in %s", leasefile);
|
292
|
*hostname = 0;
|
293
|
}
|
294
|
}
|
295
|
} else if ((strcmp(token, "ends") == 0) ||
|
296
|
(strcmp(token, "starts") == 0)) {
|
297
|
struct tm lease_time;
|
298
|
int is_ends = (strcmp(token, "ends") == 0);
|
299
|
if (next_token(token, MAXTOK, fp) && /* skip weekday */
|
300
|
next_token(token, MAXTOK, fp) && /* Get date from lease file */
|
301
|
sscanf (token, "%d/%d/%d",
|
302
|
&lease_time.tm_year,
|
303
|
&lease_time.tm_mon,
|
304
|
&lease_time.tm_mday) == 3 &&
|
305
|
next_token(token, MAXTOK, fp) &&
|
306
|
sscanf (token, "%d:%d:%d:",
|
307
|
&lease_time.tm_hour,
|
308
|
&lease_time.tm_min,
|
309
|
&lease_time.tm_sec) == 3) {
|
310
|
if (is_ends)
|
311
|
ttd = convert_time(lease_time);
|
312
|
else
|
313
|
tts = convert_time(lease_time);
|
314
|
}
|
315
|
}
|
316
|
}
|
317
|
}
|
318
|
|
319
|
/* missing info? */
|
320
|
if (!*hostname)
|
321
|
continue;
|
322
|
if (ttd == (time_t)(-1))
|
323
|
ttd = (time_t)0;
|
324
|
|
325
|
/* We use 0 as infinite in ttd */
|
326
|
if ((tts != -1) && (ttd == tts - 1))
|
327
|
ttd = (time_t)0;
|
328
|
|
329
|
if ((dot = strchr(hostname, '.'))) {
|
330
|
if (!domain_suffix || hostname_isequal(dot+1, domain_suffix)) {
|
331
|
if (foreground)
|
332
|
printf("Other suffix in DHCP lease for %s", hostname);
|
333
|
else
|
334
|
syslog(LOG_WARNING, "Other suffix in DHCP lease for %s", hostname);
|
335
|
|
336
|
suffix = (dot + 1);
|
337
|
*dot = 0;
|
338
|
} else
|
339
|
suffix = domain_suffix;
|
340
|
} else
|
341
|
suffix = domain_suffix;
|
342
|
|
343
|
LIST_FOREACH(lease, &leases, next) {
|
344
|
if (hostname_isequal(lease->name, hostname)) {
|
345
|
lease->expires = ttd;
|
346
|
lease->addr = host_address;
|
347
|
break;
|
348
|
}
|
349
|
}
|
350
|
|
351
|
if (!lease) {
|
352
|
if ((lease = malloc(sizeof(struct isc_lease))) == NULL)
|
353
|
continue;
|
354
|
lease->expires = ttd;
|
355
|
lease->addr = host_address;
|
356
|
lease->fqdn = NULL;
|
357
|
lease->name = NULL;
|
358
|
LIST_INSERT_HEAD(&leases, lease, next);
|
359
|
} else if (lease->fqdn != NULL)
|
360
|
free(lease->fqdn);
|
361
|
|
362
|
if (foreground)
|
363
|
printf("Found hostname: %s.%s\n", hostname, suffix);
|
364
|
|
365
|
if (asprintf(&lease->name, "%s", hostname) < 0) {
|
366
|
LIST_REMOVE(lease, next);
|
367
|
if (lease->name != NULL)
|
368
|
free(lease->name);
|
369
|
if (lease->fqdn != NULL)
|
370
|
free(lease->fqdn);
|
371
|
free(lease);
|
372
|
}
|
373
|
if (asprintf(&lease->fqdn, "%s.%s", hostname, suffix) < 0) {
|
374
|
LIST_REMOVE(lease, next);
|
375
|
if (lease->name != NULL)
|
376
|
free(lease->name);
|
377
|
if (lease->fqdn != NULL)
|
378
|
free(lease->fqdn);
|
379
|
free(lease);
|
380
|
}
|
381
|
}
|
382
|
}
|
383
|
}
|
384
|
|
385
|
/* prune expired leases */
|
386
|
LIST_FOREACH_SAFE(lease, &leases, next, tmp) {
|
387
|
if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0) {
|
388
|
if (lease->name)
|
389
|
free(lease->name);
|
390
|
if (lease->fqdn)
|
391
|
free(lease->fqdn);
|
392
|
LIST_REMOVE(lease, next);
|
393
|
free(lease);
|
394
|
}
|
395
|
}
|
396
|
|
397
|
return (0);
|
398
|
}
|
399
|
|
400
|
static int
|
401
|
write_status() {
|
402
|
struct isc_lease *lease;
|
403
|
struct stat tmp;
|
404
|
size_t tmpsize;
|
405
|
int fd;
|
406
|
|
407
|
fd = open(HOSTS, O_RDWR | O_CREAT | O_FSYNC);
|
408
|
if (fd < 0)
|
409
|
return 1;
|
410
|
if (fstat(fd, &tmp) < 0)
|
411
|
tmpsize = hostssize;
|
412
|
else
|
413
|
tmpsize = tmp.st_size;
|
414
|
if (tmpsize < hostssize) {
|
415
|
if (foreground)
|
416
|
printf("%s changed size from original!", HOSTS);
|
417
|
else
|
418
|
syslog(LOG_WARNING, "%s changed size from original!", HOSTS);
|
419
|
hostssize = tmpsize;
|
420
|
}
|
421
|
ftruncate(fd, hostssize);
|
422
|
if (lseek(fd, 0, SEEK_END) < 0) {
|
423
|
close(fd);
|
424
|
return 2;
|
425
|
}
|
426
|
/* write the tmp hosts file */
|
427
|
dprintf(fd, "\n# dhcpleases automatically entered\n"); /* put a blank line just to be on safe side */
|
428
|
LIST_FOREACH(lease, &leases, next) {
|
429
|
if (foreground)
|
430
|
printf("%s\t%s %s\t\t# dynamic entry from dhcpd.leases\n", inet_ntoa(lease->addr),
|
431
|
lease->fqdn ? lease->fqdn : "empty", lease->name ? lease->name : "empty");
|
432
|
else
|
433
|
dprintf(fd, "%s\t%s %s\t\t# dynamic entry from dhcpd.leases\n", inet_ntoa(lease->addr),
|
434
|
lease->fqdn ? lease->fqdn : "empty", lease->name ? lease->name : "empty");
|
435
|
}
|
436
|
close(fd);
|
437
|
|
438
|
return (0);
|
439
|
}
|
440
|
|
441
|
static void
|
442
|
cleanup() {
|
443
|
struct isc_lease *lease, *tmp;
|
444
|
|
445
|
LIST_FOREACH_SAFE(lease, &leases, next, tmp) {
|
446
|
if (lease->fqdn)
|
447
|
free(lease->fqdn);
|
448
|
if (lease->name)
|
449
|
free(lease->name);
|
450
|
LIST_REMOVE(lease, next);
|
451
|
free(lease);
|
452
|
}
|
453
|
|
454
|
return;
|
455
|
}
|
456
|
|
457
|
static void
|
458
|
signal_process() {
|
459
|
FILE *fd;
|
460
|
size_t size = 0;
|
461
|
char *pid = NULL, *pc;
|
462
|
int c, pidno;
|
463
|
|
464
|
if (pidfile == NULL)
|
465
|
goto error;
|
466
|
size = fsize(pidfile);
|
467
|
if (size < 0)
|
468
|
goto error;
|
469
|
|
470
|
fd = fopen(pidfile, "r");
|
471
|
if (fd == NULL)
|
472
|
goto error;
|
473
|
|
474
|
pid = calloc(size, size);
|
475
|
if (pid == NULL) {
|
476
|
fclose(fd);
|
477
|
goto error;
|
478
|
}
|
479
|
pc = pid;
|
480
|
while ((c = getc(fd)) != EOF) {
|
481
|
if (c == '\n')
|
482
|
break;
|
483
|
*pc++ = c;
|
484
|
}
|
485
|
fclose(fd);
|
486
|
|
487
|
pidno = atoi(pid);
|
488
|
free(pid);
|
489
|
|
490
|
syslog(LOG_INFO, "Sending HUP signal to dns daemon(%u)", pidno);
|
491
|
if (kill((pid_t)pidno, SIGHUP) < 0)
|
492
|
goto error;
|
493
|
|
494
|
return;
|
495
|
error:
|
496
|
syslog(LOG_ERR, "Could not deliver signal HUP to process because its pidfile does not exist, %m.");
|
497
|
return;
|
498
|
}
|
499
|
|
500
|
static void
|
501
|
handle_signal(int sig) {
|
502
|
size_t size;
|
503
|
|
504
|
switch(sig) {
|
505
|
case SIGHUP:
|
506
|
size = fsize(HOSTS);
|
507
|
if (hostssize < 0)
|
508
|
break; /* XXX: exit?! */
|
509
|
else
|
510
|
hostssize = size;
|
511
|
break;
|
512
|
case SIGTERM:
|
513
|
unlink(PIDFILE);
|
514
|
cleanup();
|
515
|
exit(0);
|
516
|
break;
|
517
|
default:
|
518
|
syslog(LOG_WARNING, "unhandled signal");
|
519
|
}
|
520
|
}
|
521
|
|
522
|
int
|
523
|
main(int argc, char **argv) {
|
524
|
struct kevent evlist; /* events we want to monitor */
|
525
|
struct kevent chlist; /* events that were triggered */
|
526
|
struct sigaction sa;
|
527
|
time_t now;
|
528
|
int kq, nev, leasefd = 0, pidf, ch;
|
529
|
|
530
|
if (argc != 5) {
|
531
|
}
|
532
|
|
533
|
while ((ch = getopt(argc, argv, "c:d:fp:h:l:")) != -1) {
|
534
|
switch (ch) {
|
535
|
case 'c':
|
536
|
command = optarg;
|
537
|
break;
|
538
|
case 'd':
|
539
|
domain_suffix = optarg;
|
540
|
break;
|
541
|
case 'f':
|
542
|
foreground = 1;
|
543
|
break;
|
544
|
case 'p':
|
545
|
pidfile = optarg;
|
546
|
break;
|
547
|
case 'h':
|
548
|
HOSTS = optarg;
|
549
|
break;
|
550
|
case 'l':
|
551
|
leasefile = optarg;
|
552
|
break;
|
553
|
default:
|
554
|
perror("Wrong number of arguments given."); /* XXX: usage */
|
555
|
exit(2);
|
556
|
/* NOTREACHED */
|
557
|
}
|
558
|
}
|
559
|
argc -= optind;
|
560
|
argv += optind;
|
561
|
|
562
|
if (leasefile == NULL) {
|
563
|
syslog(LOG_ERR, "lease file is mandatory as parameter");
|
564
|
perror("lease file is mandatory as parameter");
|
565
|
exit(1);
|
566
|
}
|
567
|
if (!fexist(leasefile)) {
|
568
|
syslog(LOG_ERR, "lease file needs to exist before starting dhcpleases");
|
569
|
perror("lease file needs to exist before starting dhcpleases");
|
570
|
exit(1);
|
571
|
}
|
572
|
if (domain_suffix == NULL) {
|
573
|
syslog(LOG_ERR, "a domain suffix is not passed as argument using 'local' as suffix");
|
574
|
domain_suffix = "local";
|
575
|
}
|
576
|
|
577
|
if (pidfile == NULL && !foreground) {
|
578
|
syslog(LOG_ERR, "pidfile argument not passed it is mandatory");
|
579
|
perror("pidfile argument not passed it is mandatory");
|
580
|
exit(1);
|
581
|
}
|
582
|
|
583
|
if (!foreground) {
|
584
|
if (HOSTS == NULL) {
|
585
|
syslog(LOG_ERR, "You need to specify the hosts file path.");
|
586
|
perror("You need to specify the hosts file path.");
|
587
|
exit(8);
|
588
|
}
|
589
|
if (!fexist(HOSTS)) {
|
590
|
syslog(LOG_ERR, "Hosts file %s does not exist!", HOSTS);
|
591
|
perror("Hosts file passed as parameter does not exist");
|
592
|
exit(8);
|
593
|
}
|
594
|
|
595
|
if ((hostssize = fsize(HOSTS)) < 0) {
|
596
|
syslog(LOG_ERR, "Error while getting %s file size.", HOSTS);
|
597
|
perror("Error while getting /etc/hosts file size.");
|
598
|
exit(6);
|
599
|
}
|
600
|
|
601
|
closefrom(3);
|
602
|
|
603
|
if (daemon(0, 0) < 0) {
|
604
|
syslog(LOG_ERR, "Could not daemonize");
|
605
|
perror("Could not daemonize");
|
606
|
exit(4);
|
607
|
}
|
608
|
}
|
609
|
|
610
|
reopen:
|
611
|
leasefd = open(leasefile, O_RDONLY);
|
612
|
if (leasefd < 0) {
|
613
|
syslog(LOG_ERR, "Could not get descriptor");
|
614
|
perror("Could not get descriptor");
|
615
|
exit(6);
|
616
|
}
|
617
|
|
618
|
fp = fdopen(leasefd, "r");
|
619
|
if (fp == NULL) {
|
620
|
syslog(LOG_ERR, "could not open leases file");
|
621
|
perror("could not open leases file");
|
622
|
exit(5);
|
623
|
}
|
624
|
|
625
|
if (!foreground) {
|
626
|
pidf = open(PIDFILE, O_RDWR | O_CREAT | O_FSYNC);
|
627
|
if (pidf < 0)
|
628
|
syslog(LOG_ERR, "could not write pid file, %m");
|
629
|
else {
|
630
|
ftruncate(pidf, 0);
|
631
|
dprintf(pidf, "%u\n", getpid());
|
632
|
close(pidf);
|
633
|
}
|
634
|
|
635
|
/*
|
636
|
* Catch SIGHUP in order to reread configuration file.
|
637
|
*/
|
638
|
sa.sa_handler = handle_signal;
|
639
|
sa.sa_flags = SA_SIGINFO|SA_RESTART;
|
640
|
sigemptyset(&sa.sa_mask);
|
641
|
if (sigaction(SIGHUP, &sa, NULL) < 0) {
|
642
|
syslog(LOG_ERR, "unable to set signal handler, %m");
|
643
|
exit(9);
|
644
|
}
|
645
|
if (sigaction(SIGTERM, &sa, NULL) < 0) {
|
646
|
syslog(LOG_ERR, "unable to set signal handler, %m");
|
647
|
exit(10);
|
648
|
}
|
649
|
|
650
|
/* Create a new kernel event queue */
|
651
|
if ((kq = kqueue()) == -1)
|
652
|
exit(1);
|
653
|
}
|
654
|
|
655
|
now = time(NULL);
|
656
|
if (command == NULL) {
|
657
|
load_dhcp(now);
|
658
|
|
659
|
write_status();
|
660
|
//syslog(LOG_INFO, "written temp hosts file after modification event.");
|
661
|
|
662
|
cleanup();
|
663
|
//syslog(LOG_INFO, "Cleaned up.");
|
664
|
|
665
|
if (!foreground)
|
666
|
signal_process();
|
667
|
}
|
668
|
|
669
|
if (!foreground) {
|
670
|
/* Initialise kevent structure */
|
671
|
EV_SET(&chlist, leasefd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE | EV_ONESHOT,
|
672
|
NOTE_WRITE | NOTE_ATTRIB | NOTE_DELETE | NOTE_RENAME | NOTE_LINK, 0, NULL);
|
673
|
/* Loop forever */
|
674
|
for (;;) {
|
675
|
nev = kevent(kq, &chlist, 1, &evlist, 1, NULL);
|
676
|
if (nev == -1) {
|
677
|
syslog(LOG_ERR, "kqueue error: unkown");
|
678
|
close(leasefd);
|
679
|
goto reopen;
|
680
|
} else if (nev > 0) {
|
681
|
if (evlist.flags & EV_ERROR) {
|
682
|
syslog(LOG_ERR, "EV_ERROR: %s\n", strerror(evlist.data));
|
683
|
close(leasefd);
|
684
|
goto reopen;
|
685
|
}
|
686
|
if ((evlist.fflags & NOTE_DELETE) || (evlist.fflags & NOTE_RENAME)) {
|
687
|
close(leasefd);
|
688
|
goto reopen;
|
689
|
}
|
690
|
now = time(NULL);
|
691
|
if (command != NULL)
|
692
|
system(command);
|
693
|
else {
|
694
|
load_dhcp(now);
|
695
|
|
696
|
write_status();
|
697
|
//syslog(LOG_INFO, "written temp hosts file after modification event.");
|
698
|
|
699
|
cleanup();
|
700
|
//syslog(LOG_INFO, "Cleaned up.");
|
701
|
|
702
|
signal_process();
|
703
|
}
|
704
|
}
|
705
|
}
|
706
|
}
|
707
|
|
708
|
fclose(fp);
|
709
|
unlink(PIDFILE);
|
710
|
return (0);
|
711
|
}
|