blob: 789bdd4aaa4c9637108559aab51b2d840b2a6455 [file] [log] [blame]
Simon Kelley59546082012-01-06 20:02:04 +00001/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley73a08a22009-02-05 20:28:08 +000012
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley1a6bca82008-07-11 11:11:42 +010017/* The SURF random number generator was taken from djbdns-1.05, by
Simon Kelley7622fc02009-06-04 20:32:05 +010018 Daniel J Bernstein, which is public domain. */
Simon Kelley1a6bca82008-07-11 11:11:42 +010019
20
Simon Kelley9e4abcb2004-01-22 19:47:41 +000021#include "dnsmasq.h"
22
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010023#ifdef HAVE_BROKEN_RTC
24#include <sys/times.h>
25#endif
26
Simon Kelley572b41e2011-02-18 18:11:18 +000027#if defined(LOCALEDIR) || defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +010028#include <idna.h>
29#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +010030
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031#ifdef HAVE_ARC4RANDOM
Simon Kelley1a6bca82008-07-11 11:11:42 +010032void rand_init(void)
33{
34 return;
35}
Simon Kelley9e4abcb2004-01-22 19:47:41 +000036
37unsigned short rand16(void)
38{
Simon Kelley1a6bca82008-07-11 11:11:42 +010039 return (unsigned short) (arc4random() >> 15);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000040}
41
Simon Kelley1a6bca82008-07-11 11:11:42 +010042#else
43
44/* SURF random number generator */
45
Simon Kelley572b41e2011-02-18 18:11:18 +000046static u32 seed[32];
47static u32 in[12];
48static u32 out[8];
Simon Kelley1a6bca82008-07-11 11:11:42 +010049
50void rand_init()
51{
52 int fd = open(RANDFILE, O_RDONLY);
53
54 if (fd == -1 ||
55 !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
56 !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
57 die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
58
59 close(fd);
60}
61
62#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
63#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
64
65static void surf(void)
66{
Simon Kelley572b41e2011-02-18 18:11:18 +000067 u32 t[12]; u32 x; u32 sum = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010068 int r; int i; int loop;
69
70 for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
71 for (i = 0;i < 8;++i) out[i] = seed[24 + i];
72 x = t[11];
73 for (loop = 0;loop < 2;++loop) {
74 for (r = 0;r < 16;++r) {
75 sum += 0x9e3779b9;
76 MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
77 MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
78 MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
79 }
80 for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
81 }
82}
83
84unsigned short rand16(void)
85{
86 static int outleft = 0;
87
88 if (!outleft) {
89 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
90 surf();
91 outleft = 8;
92 }
93
94 return (unsigned short) out[--outleft];
95}
96
97#endif
98
Simon Kelley1f15b812009-10-13 17:49:32 +010099static int check_name(char *in)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000100{
Simon Kelley1f15b812009-10-13 17:49:32 +0100101 /* remove trailing .
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000102 also fail empty string and label > 63 chars */
Simon Kelley1f15b812009-10-13 17:49:32 +0100103 size_t dotgap = 0, l = strlen(in);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000104 char c;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100105 int nowhite = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100106
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000107 if (l == 0 || l > MAXDNAME) return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100108
109 if (in[l-1] == '.')
Simon Kelleya2226412004-05-13 20:27:08 +0100110 {
111 if (l == 1) return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100112 in[l-1] = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100113 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000114
Simon Kelley1f15b812009-10-13 17:49:32 +0100115 for (; (c = *in); in++)
Simon Kelley3d8df262005-08-29 12:19:27 +0100116 {
117 if (c == '.')
118 dotgap = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100119 else if (++dotgap > MAXLABEL)
Simon Kelley3d8df262005-08-29 12:19:27 +0100120 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000121 else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100122 /* iscntrl only gives expected results for ascii */
123 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000124#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
125 else if (!isascii((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100126 return 0;
127#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100128 else if (c != ' ')
129 nowhite = 1;
Simon Kelley3d8df262005-08-29 12:19:27 +0100130 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100131
132 if (!nowhite)
133 return 0;
134
135 return 1;
136}
137
138/* Hostnames have a more limited valid charset than domain names
139 so check for legal char a-z A-Z 0-9 - _
140 Note that this may receive a FQDN, so only check the first label
141 for the tighter criteria. */
142int legal_hostname(char *name)
143{
144 char c;
145
146 if (!check_name(name))
147 return 0;
148
149 for (; (c = *name); name++)
150 /* check for legal char a-z A-Z 0-9 - _ . */
151 {
152 if ((c >= 'A' && c <= 'Z') ||
153 (c >= 'a' && c <= 'z') ||
154 (c >= '0' && c <= '9') ||
155 c == '-' || c == '_')
156 continue;
157
158 /* end of hostname part */
159 if (c == '.')
160 return 1;
161
162 return 0;
163 }
164
165 return 1;
166}
167
168char *canonicalise(char *in, int *nomem)
169{
170 char *ret = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000171#if defined(LOCALEDIR) || defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +0100172 int rc;
173#endif
174
175 if (nomem)
176 *nomem = 0;
177
178 if (!check_name(in))
179 return NULL;
180
Simon Kelley572b41e2011-02-18 18:11:18 +0000181#if defined(LOCALEDIR) || defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +0100182 if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
183 {
184 if (ret)
185 free(ret);
186
187 if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
188 {
189 my_syslog(LOG_ERR, _("failed to allocate memory"));
190 *nomem = 1;
191 }
192
193 return NULL;
194 }
195#else
196 if ((ret = whine_malloc(strlen(in)+1)))
197 strcpy(ret, in);
198 else if (nomem)
199 *nomem = 1;
200#endif
201
202 return ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000203}
204
Simon Kelley3d8df262005-08-29 12:19:27 +0100205unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
206{
207 int j;
208
209 while (sval && *sval)
210 {
211 unsigned char *cp = p++;
212 for (j = 0; *sval && (*sval != '.'); sval++, j++)
213 *p++ = *sval;
214 *cp = j;
215 if (*sval)
216 sval++;
217 }
218 return p;
219}
220
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000221/* for use during startup */
Simon Kelley0a852542005-03-23 20:28:59 +0000222void *safe_malloc(size_t size)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000223{
224 void *ret = malloc(size);
225
226 if (!ret)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100227 die(_("could not get memory"), NULL, EC_NOMEM);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000228
229 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100230}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000231
Simon Kelley1a6bca82008-07-11 11:11:42 +0100232void safe_pipe(int *fd, int read_noblock)
233{
234 if (pipe(fd) == -1 ||
235 !fix_fd(fd[1]) ||
236 (read_noblock && !fix_fd(fd[0])))
237 die(_("cannot create pipe: %s"), NULL, EC_MISC);
238}
239
Simon Kelley5aabfc72007-08-29 11:24:47 +0100240void *whine_malloc(size_t size)
241{
242 void *ret = malloc(size);
243
244 if (!ret)
245 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
246
247 return ret;
248}
249
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000250int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
251{
252 if (s1->sa.sa_family == s2->sa.sa_family)
253 {
254 if (s1->sa.sa_family == AF_INET &&
255 s1->in.sin_port == s2->in.sin_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100256 s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000257 return 1;
258#ifdef HAVE_IPV6
259 if (s1->sa.sa_family == AF_INET6 &&
260 s1->in6.sin6_port == s2->in6.sin6_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100261 IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000262 return 1;
263#endif
264 }
265 return 0;
266}
267
268int sa_len(union mysockaddr *addr)
269{
270#ifdef HAVE_SOCKADDR_SA_LEN
271 return addr->sa.sa_len;
272#else
273#ifdef HAVE_IPV6
274 if (addr->sa.sa_family == AF_INET6)
275 return sizeof(addr->in6);
276 else
277#endif
278 return sizeof(addr->in);
279#endif
280}
281
282/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
Simon Kelley3d8df262005-08-29 12:19:27 +0100283int hostname_isequal(char *a, char *b)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000284{
285 unsigned int c1, c2;
286
287 do {
Simon Kelley3d8df262005-08-29 12:19:27 +0100288 c1 = (unsigned char) *a++;
289 c2 = (unsigned char) *b++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000290
291 if (c1 >= 'A' && c1 <= 'Z')
292 c1 += 'a' - 'A';
293 if (c2 >= 'A' && c2 <= 'Z')
294 c2 += 'a' - 'A';
295
296 if (c1 != c2)
297 return 0;
298 } while (c1);
299
300 return 1;
301}
302
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100303time_t dnsmasq_time(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000304{
305#ifdef HAVE_BROKEN_RTC
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100306 struct tms dummy;
307 static long tps = 0;
308
309 if (tps == 0)
310 tps = sysconf(_SC_CLK_TCK);
311
312 return (time_t)(times(&dummy)/tps);
Simon Kelley44a2a312004-03-10 20:04:35 +0000313#else
Simon Kelley44a2a312004-03-10 20:04:35 +0000314 return time(NULL);
315#endif
316}
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100317
318int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
319{
320 return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
321}
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100322
Simon Kelleyc72daea2012-01-05 21:33:27 +0000323#ifdef HAVE_IPV6
324int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
325{
326 int pfbytes = prefixlen >> 3;
327 int pfbits = prefixlen & 7;
328
329 if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
330 return 0;
331
332 if (pfbits == 0 ||
333 (a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
334 return 1;
335
336 return 0;
337}
338
Simon Kelley52b92f42012-01-22 16:05:15 +0000339/* return least signigicant 64 bits if IPv6 address */
340u64 addr6part(struct in6_addr *addr)
341{
342 int i;
343 u64 ret = 0;
344
345 for (i = 8; i < 16; i++)
346 ret = (ret << 8) + addr->s6_addr[i];
347
348 return ret;
349}
350
351void setaddr6part(struct in6_addr *addr, u64 host)
352{
353 int i;
354
355 for (i = 15; i >= 8; i--)
356 {
357 addr->s6_addr[i] = host;
358 host = host >> 8;
359 }
360}
361
Simon Kelleyc72daea2012-01-05 21:33:27 +0000362#endif
363
364
Simon Kelley3d8df262005-08-29 12:19:27 +0100365/* returns port number from address */
366int prettyprint_addr(union mysockaddr *addr, char *buf)
367{
368 int port = 0;
369
370#ifdef HAVE_IPV6
371 if (addr->sa.sa_family == AF_INET)
372 {
373 inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
374 port = ntohs(addr->in.sin_port);
375 }
376 else if (addr->sa.sa_family == AF_INET6)
377 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100378 char name[IF_NAMESIZE];
Simon Kelley3d8df262005-08-29 12:19:27 +0100379 inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
Simon Kelley7de060b2011-08-26 17:24:52 +0100380 if (addr->in6.sin6_scope_id != 0 &&
381 if_indextoname(addr->in6.sin6_scope_id, name) &&
382 strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
383 {
384 strcat(buf, "%");
385 strcat(buf, name);
386 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100387 port = ntohs(addr->in6.sin6_port);
388 }
389#else
390 strcpy(buf, inet_ntoa(addr->in.sin_addr));
391 port = ntohs(addr->in.sin_port);
392#endif
393
394 return port;
395}
396
Simon Kelley0a852542005-03-23 20:28:59 +0000397void prettyprint_time(char *buf, unsigned int t)
398{
399 if (t == 0xffffffff)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000400 sprintf(buf, _("infinite"));
Simon Kelley0a852542005-03-23 20:28:59 +0000401 else
402 {
403 unsigned int x, p = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100404 if ((x = t/86400))
405 p += sprintf(&buf[p], "%dd", x);
406 if ((x = (t/3600)%24))
Simon Kelley0a852542005-03-23 20:28:59 +0000407 p += sprintf(&buf[p], "%dh", x);
408 if ((x = (t/60)%60))
409 p += sprintf(&buf[p], "%dm", x);
410 if ((x = t%60))
411 p += sprintf(&buf[p], "%ds", x);
412 }
413}
414
415
Simon Kelley28866e92011-02-14 20:19:14 +0000416/* in may equal out, when maxlen may be -1 (No max len).
417 Return -1 for extraneous no-hex chars found. */
Simon Kelleycdeda282006-03-16 20:16:06 +0000418int parse_hex(char *in, unsigned char *out, int maxlen,
419 unsigned int *wildcard_mask, int *mac_type)
Simon Kelley0a852542005-03-23 20:28:59 +0000420{
421 int mask = 0, i = 0;
422 char *r;
Simon Kelleycdeda282006-03-16 20:16:06 +0000423
424 if (mac_type)
425 *mac_type = 0;
426
Simon Kelley0a852542005-03-23 20:28:59 +0000427 while (maxlen == -1 || i < maxlen)
428 {
Simon Kelley28866e92011-02-14 20:19:14 +0000429 for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000430 if (*r != '*' && !isxdigit((unsigned char)*r))
Simon Kelley28866e92011-02-14 20:19:14 +0000431 return -1;
432
Simon Kelley0a852542005-03-23 20:28:59 +0000433 if (*r == 0)
434 maxlen = i;
Simon Kelleycdeda282006-03-16 20:16:06 +0000435
Simon Kelley0a852542005-03-23 20:28:59 +0000436 if (r != in )
437 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000438 if (*r == '-' && i == 0 && mac_type)
439 {
440 *r = 0;
441 *mac_type = strtol(in, NULL, 16);
442 mac_type = NULL;
443 }
Simon Kelley0a852542005-03-23 20:28:59 +0000444 else
Simon Kelleycdeda282006-03-16 20:16:06 +0000445 {
446 *r = 0;
447 mask = mask << 1;
448 if (strcmp(in, "*") == 0)
449 mask |= 1;
450 else
451 out[i] = strtol(in, NULL, 16);
452 i++;
453 }
Simon Kelley0a852542005-03-23 20:28:59 +0000454 }
455 in = r+1;
456 }
457
458 if (wildcard_mask)
459 *wildcard_mask = mask;
460
461 return i;
462}
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100463
Simon Kelley7622fc02009-06-04 20:32:05 +0100464/* return 0 for no match, or (no matched octets) + 1 */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100465int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
466{
Simon Kelley7622fc02009-06-04 20:32:05 +0100467 int i, count;
468 for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
469 if (!(mask & 1))
470 {
471 if (a[i] == b[i])
472 count++;
473 else
474 return 0;
475 }
476 return count;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100477}
478
479/* _note_ may copy buffer */
480int expand_buf(struct iovec *iov, size_t size)
481{
482 void *new;
483
Simon Kelley824af852008-02-12 20:43:05 +0000484 if (size <= (size_t)iov->iov_len)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100485 return 1;
486
Simon Kelley5aabfc72007-08-29 11:24:47 +0100487 if (!(new = whine_malloc(size)))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100488 {
489 errno = ENOMEM;
490 return 0;
491 }
492
493 if (iov->iov_base)
494 {
495 memcpy(new, iov->iov_base, iov->iov_len);
496 free(iov->iov_base);
497 }
498
499 iov->iov_base = new;
500 iov->iov_len = size;
501
502 return 1;
503}
Simon Kelley7cebd202006-05-06 14:13:33 +0100504
Simon Kelley5aabfc72007-08-29 11:24:47 +0100505char *print_mac(char *buff, unsigned char *mac, int len)
Simon Kelley7cebd202006-05-06 14:13:33 +0100506{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100507 char *p = buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100508 int i;
509
510 if (len == 0)
511 sprintf(p, "<null>");
512 else
513 for (i = 0; i < len; i++)
514 p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
515
Simon Kelley5aabfc72007-08-29 11:24:47 +0100516 return buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100517}
Simon Kelley16972692006-10-16 20:04:18 +0100518
519void bump_maxfd(int fd, int *max)
520{
521 if (fd > *max)
522 *max = fd;
523}
524
Simon Kelley5aabfc72007-08-29 11:24:47 +0100525int retry_send(void)
526{
527 struct timespec waiter;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000528 if (errno == EAGAIN || errno == EWOULDBLOCK)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100529 {
530 waiter.tv_sec = 0;
531 waiter.tv_nsec = 10000;
532 nanosleep(&waiter, NULL);
533 return 1;
534 }
535
536 if (errno == EINTR)
537 return 1;
538
539 return 0;
540}
541
Simon Kelley16972692006-10-16 20:04:18 +0100542int read_write(int fd, unsigned char *packet, int size, int rw)
543{
544 ssize_t n, done;
545
546 for (done = 0; done < size; done += n)
547 {
548 retry:
549 if (rw)
550 n = read(fd, &packet[done], (size_t)(size - done));
551 else
552 n = write(fd, &packet[done], (size_t)(size - done));
553
554 if (n == 0)
555 return 0;
556 else if (n == -1)
557 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100558 if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
Simon Kelley16972692006-10-16 20:04:18 +0100559 goto retry;
560 else
561 return 0;
562 }
563 }
564 return 1;
565}
Simon Kelley1a6bca82008-07-11 11:11:42 +0100566