]>
Commit | Line | Data |
---|---|---|
45e65f1d | 1 | diff --git a/Makefile b/Makefile |
32e321b2 | 2 | index 2910320b6452..0a76ce3c5154 100644 |
45e65f1d MT |
3 | --- a/Makefile |
4 | +++ b/Makefile | |
32e321b2 | 5 | @@ -73,7 +73,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \ |
45e65f1d MT |
6 | dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ |
7 | helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ | |
8 | dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ | |
32e321b2 MT |
9 | - domain.o dnssec.o blockdata.o tables.o loop.o inotify.o |
10 | + domain.o dnssec.o blockdata.o tables.o loop.o inotify.o isc.o | |
45e65f1d MT |
11 | |
12 | hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ | |
13 | dns-protocol.h radv-protocol.h ip6addr.h | |
14 | diff --git a/src/cache.c b/src/cache.c | |
32e321b2 | 15 | index 117ae279fd4e..6ee7ee362e6c 100644 |
45e65f1d MT |
16 | --- a/src/cache.c |
17 | +++ b/src/cache.c | |
18 | @@ -17,7 +17,7 @@ | |
19 | #include "dnsmasq.h" | |
20 | ||
21 | static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL; | |
22 | -#ifdef HAVE_DHCP | |
23 | +#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER) | |
24 | static struct crec *dhcp_spare = NULL; | |
25 | #endif | |
26 | static struct crec *new_chain = NULL; | |
27 | @@ -222,6 +222,9 @@ static void cache_free(struct crec *crecp) | |
28 | crecp->flags &= ~F_BIGNAME; | |
29 | } | |
30 | ||
31 | + if (crecp->flags & F_DHCP) | |
32 | + free(crecp->name.namep); | |
33 | + | |
34 | #ifdef HAVE_DNSSEC | |
35 | cache_blockdata_free(crecp); | |
36 | #endif | |
32e321b2 MT |
37 | @@ -1151,7 +1154,7 @@ void cache_reload(void) |
38 | ||
45e65f1d MT |
39 | } |
40 | ||
41 | -#ifdef HAVE_DHCP | |
42 | +#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER) | |
43 | struct in_addr a_record_from_hosts(char *name, time_t now) | |
44 | { | |
45 | struct crec *crecp = NULL; | |
32e321b2 | 46 | @@ -1229,7 +1232,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, |
45e65f1d MT |
47 | addrlen = sizeof(struct in6_addr); |
48 | } | |
49 | #endif | |
50 | - | |
51 | + | |
52 | inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN); | |
53 | ||
54 | while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME))) | |
32e321b2 | 55 | @@ -1294,7 +1297,11 @@ void cache_add_dhcp_entry(char *host_name, int prot, |
45e65f1d MT |
56 | else |
57 | crec->ttd = ttd; | |
58 | crec->addr.addr = *host_address; | |
59 | +#ifdef HAVE_ISC_READER | |
60 | + crec->name.namep = strdup(host_name); | |
61 | +#else | |
62 | crec->name.namep = host_name; | |
63 | +#endif | |
64 | crec->uid = next_uid(); | |
65 | cache_hash(crec); | |
66 | ||
67 | diff --git a/src/dnsmasq.c b/src/dnsmasq.c | |
32e321b2 | 68 | index e903a24c8105..eefc7f939933 100644 |
45e65f1d MT |
69 | --- a/src/dnsmasq.c |
70 | +++ b/src/dnsmasq.c | |
32e321b2 | 71 | @@ -970,6 +970,11 @@ int main (int argc, char **argv) |
45e65f1d MT |
72 | |
73 | poll_resolv(0, daemon->last_resolv != 0, now); | |
74 | daemon->last_resolv = now; | |
75 | + | |
76 | +#ifdef HAVE_ISC_READER | |
77 | + if (daemon->lease_file && !daemon->dhcp) | |
78 | + load_dhcp(now); | |
79 | +#endif | |
80 | } | |
32e321b2 MT |
81 | #endif |
82 | ||
45e65f1d | 83 | diff --git a/src/dnsmasq.h b/src/dnsmasq.h |
32e321b2 | 84 | index 89e758b56a0a..c5edd6fdf7f5 100644 |
45e65f1d MT |
85 | --- a/src/dnsmasq.h |
86 | +++ b/src/dnsmasq.h | |
32e321b2 MT |
87 | @@ -1502,3 +1502,8 @@ void inotify_dnsmasq_init(); |
88 | int inotify_check(time_t now); | |
89 | void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz); | |
45e65f1d | 90 | #endif |
32e321b2 | 91 | + |
45e65f1d MT |
92 | +/* isc.c */ |
93 | +#ifdef HAVE_ISC_READER | |
94 | +void load_dhcp(time_t now); | |
95 | +#endif | |
96 | diff --git a/src/isc.c b/src/isc.c | |
97 | new file mode 100644 | |
32e321b2 | 98 | index 000000000000..51064426f17f |
45e65f1d MT |
99 | --- /dev/null |
100 | +++ b/src/isc.c | |
3da4cc02 | 101 | @@ -0,0 +1,251 @@ |
45e65f1d MT |
102 | +/* dnsmasq is Copyright (c) 2014 John Volpe, Simon Kelley and |
103 | + Michael Tremer | |
104 | + | |
105 | + This program is free software; you can redistribute it and/or modify | |
106 | + it under the terms of the GNU General Public License as published by | |
107 | + the Free Software Foundation; version 2 dated June, 1991, or | |
108 | + (at your option) version 3 dated 29 June, 2007. | |
109 | + | |
110 | + This program is distributed in the hope that it will be useful, | |
111 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
112 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
113 | + GNU General Public License for more details. | |
114 | + | |
115 | + You should have received a copy of the GNU General Public License | |
116 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
117 | + | |
118 | + Code in this file is based on contributions by John Volpe and | |
119 | + Simon Kelley. Updated for recent versions of dnsmasq by | |
120 | + Michael Tremer. | |
121 | +*/ | |
122 | + | |
123 | +#include "dnsmasq.h" | |
124 | + | |
125 | +#ifdef HAVE_ISC_READER | |
126 | +#define MAXTOK 50 | |
127 | + | |
128 | +struct isc_dhcp_lease { | |
129 | + char* name; | |
130 | + char* fqdn; | |
131 | + time_t expires; | |
132 | + struct in_addr addr; | |
133 | + struct isc_dhcp_lease* next; | |
134 | +}; | |
135 | + | |
3da4cc02 | 136 | +static struct isc_dhcp_lease* dhcp_lease_new(const char* hostname) { |
45e65f1d MT |
137 | + struct isc_dhcp_lease* lease = whine_malloc(sizeof(*lease)); |
138 | + | |
3da4cc02 MT |
139 | + lease->name = strdup(hostname); |
140 | + if (daemon->domain_suffix) { | |
141 | + asprintf(&lease->fqdn, "%s.%s", hostname, daemon->domain_suffix); | |
142 | + } | |
143 | + lease->expires = 0; | |
45e65f1d MT |
144 | + lease->next = NULL; |
145 | + | |
146 | + return lease; | |
147 | +} | |
148 | + | |
149 | +static void dhcp_lease_free(struct isc_dhcp_lease* lease) { | |
150 | + if (!lease) | |
151 | + return; | |
152 | + | |
153 | + if (lease->name) | |
154 | + free(lease->name); | |
155 | + if (lease->fqdn) | |
156 | + free(lease->fqdn); | |
157 | + free(lease); | |
158 | +} | |
159 | + | |
160 | +static int next_token(char* token, int buffsize, FILE* fp) { | |
161 | + int c, count = 0; | |
162 | + char* cp = token; | |
163 | + | |
164 | + while ((c = getc(fp)) != EOF) { | |
165 | + if (c == '#') { | |
166 | + do { | |
167 | + c = getc(fp); | |
168 | + } while (c != '\n' && c != EOF); | |
169 | + } | |
170 | + | |
171 | + if (c == ' ' || c == '\t' || c == '\n' || c == ';') { | |
172 | + if (count) | |
173 | + break; | |
174 | + } else if ((c != '"') && (count < buffsize - 1)) { | |
175 | + *cp++ = c; | |
176 | + count++; | |
177 | + } | |
178 | + } | |
179 | + | |
180 | + *cp = 0; | |
181 | + return count ? 1 : 0; | |
182 | +} | |
183 | + | |
3da4cc02 MT |
184 | +static long get_utc_offset() { |
185 | + time_t t = time(NULL); | |
186 | + struct tm* time_struct = localtime(&t); | |
187 | + | |
188 | + return time_struct->tm_gmtoff; | |
189 | +} | |
190 | + | |
45e65f1d MT |
191 | +static time_t parse_lease_time(const char* token_date, const char* token_time) { |
192 | + time_t time = (time_t)(-1); | |
193 | + struct tm lease_time; | |
194 | + | |
45e65f1d | 195 | + if (sscanf(token_date, "%d/%d/%d", &lease_time.tm_year, &lease_time.tm_mon, &lease_time.tm_mday) == 3) { |
3da4cc02 MT |
196 | + lease_time.tm_year -= 1900; |
197 | + lease_time.tm_mon -= 1; | |
198 | + | |
45e65f1d | 199 | + if (sscanf(token_time, "%d:%d:%d", &lease_time.tm_hour, &lease_time.tm_min, &lease_time.tm_sec) == 3) { |
3da4cc02 | 200 | + time = mktime(&lease_time) + get_utc_offset(); |
45e65f1d MT |
201 | + } |
202 | + } | |
203 | + | |
204 | + return time; | |
205 | +} | |
206 | + | |
3da4cc02 MT |
207 | +static struct isc_dhcp_lease* find_lease(const char* hostname, struct isc_dhcp_lease* leases) { |
208 | + struct isc_dhcp_lease* lease = leases; | |
209 | + | |
210 | + while (lease) { | |
211 | + if (strcmp(hostname, lease->name) == 0) { | |
212 | + return lease; | |
213 | + } | |
214 | + lease = lease->next; | |
215 | + } | |
216 | + | |
217 | + return NULL; | |
218 | +} | |
219 | + | |
45e65f1d MT |
220 | +static off_t lease_file_size = (off_t)0; |
221 | +static ino_t lease_file_inode = (ino_t)0; | |
222 | + | |
223 | +void load_dhcp(time_t now) { | |
224 | + struct isc_dhcp_lease* leases = NULL; | |
225 | + | |
226 | + struct stat statbuf; | |
227 | + if (stat(daemon->lease_file, &statbuf) == -1) { | |
228 | + return; | |
229 | + } | |
230 | + | |
231 | + /* Do nothing if the lease file has not changed. */ | |
232 | + if ((statbuf.st_size <= lease_file_size) && (statbuf.st_ino == lease_file_inode)) | |
233 | + return; | |
234 | + | |
235 | + lease_file_size = statbuf.st_size; | |
236 | + lease_file_inode = statbuf.st_ino; | |
237 | + | |
238 | + FILE* fp = fopen(daemon->lease_file, "r"); | |
239 | + if (!fp) { | |
240 | + my_syslog(LOG_ERR, _("failed to load %s:%s"), daemon->lease_file, strerror(errno)); | |
241 | + return; | |
242 | + } | |
243 | + | |
244 | + my_syslog(LOG_INFO, _("reading %s"), daemon->lease_file); | |
245 | + | |
246 | + char* hostname = daemon->namebuff; | |
247 | + struct in_addr host_address; | |
248 | + time_t time_starts = -1; | |
249 | + time_t time_ends = -1; | |
250 | + int nomem; | |
251 | + | |
252 | + char token[MAXTOK]; | |
253 | + while ((next_token(token, MAXTOK, fp))) { | |
254 | + if (strcmp(token, "lease") == 0) { | |
255 | + hostname[0] = '\0'; | |
256 | + | |
257 | + if (next_token(token, MAXTOK, fp) && ((host_address.s_addr = inet_addr(token)) != (in_addr_t)-1)) { | |
258 | + if (next_token(token, MAXTOK, fp) && *token == '{') { | |
259 | + while (next_token(token, MAXTOK, fp) && *token != '}') { | |
260 | + if ((strcmp(token, "client-hostname") == 0) || (strcmp(token, "hostname") == 0)) { | |
261 | + if (next_token(hostname, MAXDNAME, fp)) { | |
262 | + if (!canonicalise(hostname, &nomem)) { | |
263 | + *hostname = 0; | |
264 | + my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file); | |
265 | + } | |
266 | + } | |
267 | + } else if ((strcmp(token, "starts") == 0) || (strcmp(token, "ends") == 0)) { | |
268 | + char token_date[MAXTOK]; | |
269 | + char token_time[MAXTOK]; | |
270 | + | |
271 | + int is_starts = strcmp(token, "starts") == 0; | |
272 | + | |
273 | + // Throw away the weekday and parse the date. | |
274 | + if (next_token(token, MAXTOK, fp) && next_token(token_date, MAXTOK, fp) && next_token(token_time, MAXTOK, fp)) { | |
275 | + time_t time = parse_lease_time(token_date, token_time); | |
276 | + | |
277 | + if (is_starts) | |
278 | + time_starts = time; | |
279 | + else | |
280 | + time_ends = time; | |
281 | + } | |
282 | + } | |
283 | + } | |
284 | + | |
285 | + if (!*hostname) | |
286 | + continue; | |
287 | + | |
288 | + if ((time_starts == -1) || (time_ends == -1)) | |
289 | + continue; | |
290 | + | |
291 | + if (difftime(now, time_ends) > 0) | |
292 | + continue; | |
293 | + | |
294 | + char* dot = strchr(hostname, '.'); | |
295 | + if (dot) { | |
296 | + if (!daemon->domain_suffix || hostname_isequal(dot + 1, daemon->domain_suffix)) { | |
297 | + my_syslog(LOG_WARNING, | |
298 | + _("Ignoring DHCP lease for %s because it has an illegal domain part"), | |
299 | + hostname); | |
300 | + continue; | |
301 | + } | |
302 | + *dot = 0; | |
303 | + } | |
304 | + | |
3da4cc02 MT |
305 | + // Search for an existing lease in the list |
306 | + // with the given host name and update the data | |
307 | + // if needed. | |
308 | + struct isc_dhcp_lease* lease = find_lease(hostname, leases); | |
45e65f1d | 309 | + |
3da4cc02 MT |
310 | + // If no lease already exists, we create a new one |
311 | + // and append it to the list. | |
312 | + if (!lease) { | |
313 | + lease = dhcp_lease_new(hostname); | |
45e65f1d | 314 | + |
3da4cc02 | 315 | + lease->next = leases; |
45e65f1d | 316 | + leases = lease; |
3da4cc02 MT |
317 | + } |
318 | + | |
319 | + // Only update more recent leases. | |
320 | + if (lease->expires > time_ends) | |
321 | + continue; | |
322 | + | |
323 | + lease->addr = host_address; | |
324 | + lease->expires = time_ends; | |
45e65f1d MT |
325 | + } |
326 | + } | |
327 | + } | |
328 | + } | |
329 | + | |
330 | + fclose(fp); | |
331 | + | |
332 | + // Drop all entries. | |
333 | + cache_unhash_dhcp(); | |
334 | + | |
335 | + while (leases) { | |
336 | + struct isc_dhcp_lease *lease = leases; | |
337 | + leases = lease->next; | |
338 | + | |
339 | + if (lease->fqdn) { | |
340 | + cache_add_dhcp_entry(lease->fqdn, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires); | |
341 | + } | |
342 | + | |
343 | + if (lease->name) { | |
344 | + cache_add_dhcp_entry(lease->name, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires); | |
345 | + } | |
346 | + | |
347 | + // Cleanup | |
348 | + dhcp_lease_free(lease); | |
349 | + } | |
350 | +} | |
351 | + | |
352 | +#endif | |
353 | diff --git a/src/option.c b/src/option.c | |
32e321b2 | 354 | index cb4e76ba0aa2..f6420fcbb7ab 100644 |
45e65f1d MT |
355 | --- a/src/option.c |
356 | +++ b/src/option.c | |
32e321b2 | 357 | @@ -1693,7 +1693,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma |
45e65f1d MT |
358 | ret_err(_("bad MX target")); |
359 | break; | |
360 | ||
361 | -#ifdef HAVE_DHCP | |
362 | +#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER) | |
363 | case 'l': /* --dhcp-leasefile */ | |
364 | daemon->lease_file = opt_string_alloc(arg); | |
365 | break; |