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