]>
Commit | Line | Data |
---|---|---|
45e65f1d | 1 | diff --git a/Makefile b/Makefile |
7a35d102 | 2 | index 58a7975..616c6b7 100644 |
45e65f1d MT |
3 | --- a/Makefile |
4 | +++ b/Makefile | |
5 | @@ -69,7 +69,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \ | |
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 \ | |
7a35d102 MT |
9 | - domain.o dnssec.o blockdata.o tables.o loop.o |
10 | + domain.o dnssec.o blockdata.o tables.o loop.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 | |
7a35d102 | 15 | index 2c3a498..77a7046 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 | |
37 | @@ -1110,7 +1113,7 @@ void cache_reload(void) | |
38 | total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); | |
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; | |
46 | @@ -1188,7 +1191,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, | |
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))) | |
55 | @@ -1253,7 +1256,11 @@ void cache_add_dhcp_entry(char *host_name, int prot, | |
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 | |
7a35d102 | 68 | index f4a89fc..a448ec4 100644 |
45e65f1d MT |
69 | --- a/src/dnsmasq.c |
70 | +++ b/src/dnsmasq.c | |
7a35d102 | 71 | @@ -940,6 +940,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 | } | |
81 | ||
82 | if (FD_ISSET(piperead, &rset)) | |
83 | diff --git a/src/dnsmasq.h b/src/dnsmasq.h | |
7a35d102 | 84 | index e74b15a..4a35168 100644 |
45e65f1d MT |
85 | --- a/src/dnsmasq.h |
86 | +++ b/src/dnsmasq.h | |
7a35d102 | 87 | @@ -1463,9 +1463,13 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases); |
45e65f1d MT |
88 | void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases); |
89 | #endif | |
7a35d102 | 90 | |
45e65f1d MT |
91 | +/* isc.c */ |
92 | +#ifdef HAVE_ISC_READER | |
93 | +void load_dhcp(time_t now); | |
94 | +#endif | |
7a35d102 MT |
95 | + |
96 | /* loop.c */ | |
97 | #ifdef HAVE_LOOP | |
98 | void loop_send_probes(); | |
99 | int detect_loop(char *query, int type); | |
100 | #endif | |
101 | - | |
45e65f1d MT |
102 | diff --git a/src/isc.c b/src/isc.c |
103 | new file mode 100644 | |
3da4cc02 | 104 | index 0000000..5106442 |
45e65f1d MT |
105 | --- /dev/null |
106 | +++ b/src/isc.c | |
3da4cc02 | 107 | @@ -0,0 +1,251 @@ |
45e65f1d MT |
108 | +/* dnsmasq is Copyright (c) 2014 John Volpe, Simon Kelley and |
109 | + Michael Tremer | |
110 | + | |
111 | + This program is free software; you can redistribute it and/or modify | |
112 | + it under the terms of the GNU General Public License as published by | |
113 | + the Free Software Foundation; version 2 dated June, 1991, or | |
114 | + (at your option) version 3 dated 29 June, 2007. | |
115 | + | |
116 | + This program is distributed in the hope that it will be useful, | |
117 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
118 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
119 | + GNU General Public License for more details. | |
120 | + | |
121 | + You should have received a copy of the GNU General Public License | |
122 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | |
123 | + | |
124 | + Code in this file is based on contributions by John Volpe and | |
125 | + Simon Kelley. Updated for recent versions of dnsmasq by | |
126 | + Michael Tremer. | |
127 | +*/ | |
128 | + | |
129 | +#include "dnsmasq.h" | |
130 | + | |
131 | +#ifdef HAVE_ISC_READER | |
132 | +#define MAXTOK 50 | |
133 | + | |
134 | +struct isc_dhcp_lease { | |
135 | + char* name; | |
136 | + char* fqdn; | |
137 | + time_t expires; | |
138 | + struct in_addr addr; | |
139 | + struct isc_dhcp_lease* next; | |
140 | +}; | |
141 | + | |
3da4cc02 | 142 | +static struct isc_dhcp_lease* dhcp_lease_new(const char* hostname) { |
45e65f1d MT |
143 | + struct isc_dhcp_lease* lease = whine_malloc(sizeof(*lease)); |
144 | + | |
3da4cc02 MT |
145 | + lease->name = strdup(hostname); |
146 | + if (daemon->domain_suffix) { | |
147 | + asprintf(&lease->fqdn, "%s.%s", hostname, daemon->domain_suffix); | |
148 | + } | |
149 | + lease->expires = 0; | |
45e65f1d MT |
150 | + lease->next = NULL; |
151 | + | |
152 | + return lease; | |
153 | +} | |
154 | + | |
155 | +static void dhcp_lease_free(struct isc_dhcp_lease* lease) { | |
156 | + if (!lease) | |
157 | + return; | |
158 | + | |
159 | + if (lease->name) | |
160 | + free(lease->name); | |
161 | + if (lease->fqdn) | |
162 | + free(lease->fqdn); | |
163 | + free(lease); | |
164 | +} | |
165 | + | |
166 | +static int next_token(char* token, int buffsize, FILE* fp) { | |
167 | + int c, count = 0; | |
168 | + char* cp = token; | |
169 | + | |
170 | + while ((c = getc(fp)) != EOF) { | |
171 | + if (c == '#') { | |
172 | + do { | |
173 | + c = getc(fp); | |
174 | + } while (c != '\n' && c != EOF); | |
175 | + } | |
176 | + | |
177 | + if (c == ' ' || c == '\t' || c == '\n' || c == ';') { | |
178 | + if (count) | |
179 | + break; | |
180 | + } else if ((c != '"') && (count < buffsize - 1)) { | |
181 | + *cp++ = c; | |
182 | + count++; | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + *cp = 0; | |
187 | + return count ? 1 : 0; | |
188 | +} | |
189 | + | |
3da4cc02 MT |
190 | +static long get_utc_offset() { |
191 | + time_t t = time(NULL); | |
192 | + struct tm* time_struct = localtime(&t); | |
193 | + | |
194 | + return time_struct->tm_gmtoff; | |
195 | +} | |
196 | + | |
45e65f1d MT |
197 | +static time_t parse_lease_time(const char* token_date, const char* token_time) { |
198 | + time_t time = (time_t)(-1); | |
199 | + struct tm lease_time; | |
200 | + | |
45e65f1d | 201 | + if (sscanf(token_date, "%d/%d/%d", &lease_time.tm_year, &lease_time.tm_mon, &lease_time.tm_mday) == 3) { |
3da4cc02 MT |
202 | + lease_time.tm_year -= 1900; |
203 | + lease_time.tm_mon -= 1; | |
204 | + | |
45e65f1d | 205 | + if (sscanf(token_time, "%d:%d:%d", &lease_time.tm_hour, &lease_time.tm_min, &lease_time.tm_sec) == 3) { |
3da4cc02 | 206 | + time = mktime(&lease_time) + get_utc_offset(); |
45e65f1d MT |
207 | + } |
208 | + } | |
209 | + | |
210 | + return time; | |
211 | +} | |
212 | + | |
3da4cc02 MT |
213 | +static struct isc_dhcp_lease* find_lease(const char* hostname, struct isc_dhcp_lease* leases) { |
214 | + struct isc_dhcp_lease* lease = leases; | |
215 | + | |
216 | + while (lease) { | |
217 | + if (strcmp(hostname, lease->name) == 0) { | |
218 | + return lease; | |
219 | + } | |
220 | + lease = lease->next; | |
221 | + } | |
222 | + | |
223 | + return NULL; | |
224 | +} | |
225 | + | |
45e65f1d MT |
226 | +static off_t lease_file_size = (off_t)0; |
227 | +static ino_t lease_file_inode = (ino_t)0; | |
228 | + | |
229 | +void load_dhcp(time_t now) { | |
230 | + struct isc_dhcp_lease* leases = NULL; | |
231 | + | |
232 | + struct stat statbuf; | |
233 | + if (stat(daemon->lease_file, &statbuf) == -1) { | |
234 | + return; | |
235 | + } | |
236 | + | |
237 | + /* Do nothing if the lease file has not changed. */ | |
238 | + if ((statbuf.st_size <= lease_file_size) && (statbuf.st_ino == lease_file_inode)) | |
239 | + return; | |
240 | + | |
241 | + lease_file_size = statbuf.st_size; | |
242 | + lease_file_inode = statbuf.st_ino; | |
243 | + | |
244 | + FILE* fp = fopen(daemon->lease_file, "r"); | |
245 | + if (!fp) { | |
246 | + my_syslog(LOG_ERR, _("failed to load %s:%s"), daemon->lease_file, strerror(errno)); | |
247 | + return; | |
248 | + } | |
249 | + | |
250 | + my_syslog(LOG_INFO, _("reading %s"), daemon->lease_file); | |
251 | + | |
252 | + char* hostname = daemon->namebuff; | |
253 | + struct in_addr host_address; | |
254 | + time_t time_starts = -1; | |
255 | + time_t time_ends = -1; | |
256 | + int nomem; | |
257 | + | |
258 | + char token[MAXTOK]; | |
259 | + while ((next_token(token, MAXTOK, fp))) { | |
260 | + if (strcmp(token, "lease") == 0) { | |
261 | + hostname[0] = '\0'; | |
262 | + | |
263 | + if (next_token(token, MAXTOK, fp) && ((host_address.s_addr = inet_addr(token)) != (in_addr_t)-1)) { | |
264 | + if (next_token(token, MAXTOK, fp) && *token == '{') { | |
265 | + while (next_token(token, MAXTOK, fp) && *token != '}') { | |
266 | + if ((strcmp(token, "client-hostname") == 0) || (strcmp(token, "hostname") == 0)) { | |
267 | + if (next_token(hostname, MAXDNAME, fp)) { | |
268 | + if (!canonicalise(hostname, &nomem)) { | |
269 | + *hostname = 0; | |
270 | + my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file); | |
271 | + } | |
272 | + } | |
273 | + } else if ((strcmp(token, "starts") == 0) || (strcmp(token, "ends") == 0)) { | |
274 | + char token_date[MAXTOK]; | |
275 | + char token_time[MAXTOK]; | |
276 | + | |
277 | + int is_starts = strcmp(token, "starts") == 0; | |
278 | + | |
279 | + // Throw away the weekday and parse the date. | |
280 | + if (next_token(token, MAXTOK, fp) && next_token(token_date, MAXTOK, fp) && next_token(token_time, MAXTOK, fp)) { | |
281 | + time_t time = parse_lease_time(token_date, token_time); | |
282 | + | |
283 | + if (is_starts) | |
284 | + time_starts = time; | |
285 | + else | |
286 | + time_ends = time; | |
287 | + } | |
288 | + } | |
289 | + } | |
290 | + | |
291 | + if (!*hostname) | |
292 | + continue; | |
293 | + | |
294 | + if ((time_starts == -1) || (time_ends == -1)) | |
295 | + continue; | |
296 | + | |
297 | + if (difftime(now, time_ends) > 0) | |
298 | + continue; | |
299 | + | |
300 | + char* dot = strchr(hostname, '.'); | |
301 | + if (dot) { | |
302 | + if (!daemon->domain_suffix || hostname_isequal(dot + 1, daemon->domain_suffix)) { | |
303 | + my_syslog(LOG_WARNING, | |
304 | + _("Ignoring DHCP lease for %s because it has an illegal domain part"), | |
305 | + hostname); | |
306 | + continue; | |
307 | + } | |
308 | + *dot = 0; | |
309 | + } | |
310 | + | |
3da4cc02 MT |
311 | + // Search for an existing lease in the list |
312 | + // with the given host name and update the data | |
313 | + // if needed. | |
314 | + struct isc_dhcp_lease* lease = find_lease(hostname, leases); | |
45e65f1d | 315 | + |
3da4cc02 MT |
316 | + // If no lease already exists, we create a new one |
317 | + // and append it to the list. | |
318 | + if (!lease) { | |
319 | + lease = dhcp_lease_new(hostname); | |
45e65f1d | 320 | + |
3da4cc02 | 321 | + lease->next = leases; |
45e65f1d | 322 | + leases = lease; |
3da4cc02 MT |
323 | + } |
324 | + | |
325 | + // Only update more recent leases. | |
326 | + if (lease->expires > time_ends) | |
327 | + continue; | |
328 | + | |
329 | + lease->addr = host_address; | |
330 | + lease->expires = time_ends; | |
45e65f1d MT |
331 | + } |
332 | + } | |
333 | + } | |
334 | + } | |
335 | + | |
336 | + fclose(fp); | |
337 | + | |
338 | + // Drop all entries. | |
339 | + cache_unhash_dhcp(); | |
340 | + | |
341 | + while (leases) { | |
342 | + struct isc_dhcp_lease *lease = leases; | |
343 | + leases = lease->next; | |
344 | + | |
345 | + if (lease->fqdn) { | |
346 | + cache_add_dhcp_entry(lease->fqdn, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires); | |
347 | + } | |
348 | + | |
349 | + if (lease->name) { | |
350 | + cache_add_dhcp_entry(lease->name, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires); | |
351 | + } | |
352 | + | |
353 | + // Cleanup | |
354 | + dhcp_lease_free(lease); | |
355 | + } | |
356 | +} | |
357 | + | |
358 | +#endif | |
359 | diff --git a/src/option.c b/src/option.c | |
7a35d102 | 360 | index 45d8875..29c9ee5 100644 |
45e65f1d MT |
361 | --- a/src/option.c |
362 | +++ b/src/option.c | |
7a35d102 | 363 | @@ -1669,7 +1669,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma |
45e65f1d MT |
364 | ret_err(_("bad MX target")); |
365 | break; | |
366 | ||
367 | -#ifdef HAVE_DHCP | |
368 | +#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER) | |
369 | case 'l': /* --dhcp-leasefile */ | |
370 | daemon->lease_file = opt_string_alloc(arg); | |
371 | break; |