]>
Commit | Line | Data |
---|---|---|
28866e95 | 1 | /* dnsmasq is Copyright (c) 2000-2011 Simon Kelley |
9e4abcb5 SK |
2 | |
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 | |
824af85b SK |
5 | the Free Software Foundation; version 2 dated June, 1991, or |
6 | (at your option) version 3 dated 29 June, 2007. | |
7 | ||
9e4abcb5 SK |
8 | 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. | |
73a08a24 SK |
12 | |
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/>. | |
9e4abcb5 SK |
15 | */ |
16 | ||
1a6bca81 | 17 | /* The SURF random number generator was taken from djbdns-1.05, by |
7622fc06 | 18 | Daniel J Bernstein, which is public domain. */ |
1a6bca81 SK |
19 | |
20 | ||
9e4abcb5 SK |
21 | #include "dnsmasq.h" |
22 | ||
5e9e0efb SK |
23 | #ifdef HAVE_BROKEN_RTC |
24 | #include <sys/times.h> | |
25 | #endif | |
26 | ||
572b41eb | 27 | #if defined(LOCALEDIR) || defined(HAVE_IDN) |
1f15b81d SK |
28 | #include <idna.h> |
29 | #endif | |
1a6bca81 | 30 | |
9e4abcb5 | 31 | #ifdef HAVE_ARC4RANDOM |
1a6bca81 SK |
32 | void rand_init(void) |
33 | { | |
34 | return; | |
35 | } | |
9e4abcb5 SK |
36 | |
37 | unsigned short rand16(void) | |
38 | { | |
1a6bca81 SK |
39 | return (unsigned short) (arc4random() >> 15); |
40 | } | |
41 | ||
42 | #else | |
43 | ||
44 | /* SURF random number generator */ | |
45 | ||
572b41eb SK |
46 | static u32 seed[32]; |
47 | static u32 in[12]; | |
48 | static u32 out[8]; | |
1a6bca81 SK |
49 | |
50 | void rand_init() | |
51 | { | |
52 | int fd = open(RANDFILE, O_RDONLY); | |
9e4abcb5 | 53 | |
1a6bca81 SK |
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)); | |
9e4abcb5 | 64 | |
1a6bca81 SK |
65 | static void surf(void) |
66 | { | |
572b41eb | 67 | u32 t[12]; u32 x; u32 sum = 0; |
1a6bca81 SK |
68 | 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) | |
9e4abcb5 | 79 | } |
1a6bca81 SK |
80 | for (i = 0;i < 8;++i) out[i] ^= t[i + 4]; |
81 | } | |
82 | } | |
83 | ||
84 | unsigned 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]; | |
9e4abcb5 SK |
95 | } |
96 | ||
1a6bca81 SK |
97 | #endif |
98 | ||
1f15b81d | 99 | static int check_name(char *in) |
9e4abcb5 | 100 | { |
1f15b81d | 101 | /* remove trailing . |
f6b7dc47 | 102 | also fail empty string and label > 63 chars */ |
1f15b81d | 103 | size_t dotgap = 0, l = strlen(in); |
9e4abcb5 | 104 | char c; |
5aabfc78 | 105 | int nowhite = 0; |
1f15b81d | 106 | |
f6b7dc47 | 107 | if (l == 0 || l > MAXDNAME) return 0; |
1f15b81d SK |
108 | |
109 | if (in[l-1] == '.') | |
a222641c SK |
110 | { |
111 | if (l == 1) return 0; | |
1f15b81d | 112 | in[l-1] = 0; |
a222641c | 113 | } |
f6b7dc47 | 114 | |
1f15b81d | 115 | for (; (c = *in); in++) |
3d8df260 SK |
116 | { |
117 | if (c == '.') | |
118 | dotgap = 0; | |
1f15b81d | 119 | else if (++dotgap > MAXLABEL) |
3d8df260 | 120 | return 0; |
572b41eb | 121 | else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) |
1f15b81d SK |
122 | /* iscntrl only gives expected results for ascii */ |
123 | return 0; | |
572b41eb SK |
124 | #if !defined(LOCALEDIR) && !defined(HAVE_IDN) |
125 | else if (!isascii((unsigned char)c)) | |
1f15b81d SK |
126 | return 0; |
127 | #endif | |
5aabfc78 SK |
128 | else if (c != ' ') |
129 | nowhite = 1; | |
3d8df260 | 130 | } |
1f15b81d SK |
131 | |
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. */ | |
142 | int 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 | ||
168 | char *canonicalise(char *in, int *nomem) | |
169 | { | |
170 | char *ret = NULL; | |
572b41eb | 171 | #if defined(LOCALEDIR) || defined(HAVE_IDN) |
1f15b81d SK |
172 | int rc; |
173 | #endif | |
174 | ||
175 | if (nomem) | |
176 | *nomem = 0; | |
177 | ||
178 | if (!check_name(in)) | |
179 | return NULL; | |
180 | ||
572b41eb | 181 | #if defined(LOCALEDIR) || defined(HAVE_IDN) |
1f15b81d SK |
182 | 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; | |
9e4abcb5 SK |
203 | } |
204 | ||
3d8df260 SK |
205 | unsigned 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 | ||
9e4abcb5 | 221 | /* for use during startup */ |
0a852541 | 222 | void *safe_malloc(size_t size) |
9e4abcb5 SK |
223 | { |
224 | void *ret = malloc(size); | |
225 | ||
226 | if (!ret) | |
5aabfc78 | 227 | die(_("could not get memory"), NULL, EC_NOMEM); |
9e4abcb5 SK |
228 | |
229 | return ret; | |
3d8df260 | 230 | } |
9e4abcb5 | 231 | |
1a6bca81 SK |
232 | void 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 | ||
5aabfc78 SK |
240 | void *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 | ||
9e4abcb5 SK |
250 | int 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 && | |
5e9e0efb | 256 | s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr) |
9e4abcb5 SK |
257 | return 1; |
258 | #ifdef HAVE_IPV6 | |
259 | if (s1->sa.sa_family == AF_INET6 && | |
260 | s1->in6.sin6_port == s2->in6.sin6_port && | |
5e9e0efb | 261 | IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr)) |
9e4abcb5 SK |
262 | return 1; |
263 | #endif | |
264 | } | |
265 | return 0; | |
266 | } | |
267 | ||
268 | int 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 */ | |
3d8df260 | 283 | int hostname_isequal(char *a, char *b) |
9e4abcb5 SK |
284 | { |
285 | unsigned int c1, c2; | |
286 | ||
287 | do { | |
3d8df260 SK |
288 | c1 = (unsigned char) *a++; |
289 | c2 = (unsigned char) *b++; | |
9e4abcb5 SK |
290 | |
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 | ||
5e9e0efb | 303 | time_t dnsmasq_time(void) |
44a2a316 SK |
304 | { |
305 | #ifdef HAVE_BROKEN_RTC | |
5e9e0efb SK |
306 | 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); | |
44a2a316 | 313 | #else |
44a2a316 SK |
314 | return time(NULL); |
315 | #endif | |
316 | } | |
a84fa1d0 SK |
317 | |
318 | int 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 | } | |
fd9fa481 | 322 | |
c72daea8 SK |
323 | #ifdef HAVE_IPV6 |
324 | int 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 | ||
339 | #endif | |
340 | ||
341 | ||
3d8df260 SK |
342 | /* returns port number from address */ |
343 | int prettyprint_addr(union mysockaddr *addr, char *buf) | |
344 | { | |
345 | int port = 0; | |
346 | ||
347 | #ifdef HAVE_IPV6 | |
348 | if (addr->sa.sa_family == AF_INET) | |
349 | { | |
350 | inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN); | |
351 | port = ntohs(addr->in.sin_port); | |
352 | } | |
353 | else if (addr->sa.sa_family == AF_INET6) | |
354 | { | |
7de060b0 | 355 | char name[IF_NAMESIZE]; |
3d8df260 | 356 | inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN); |
7de060b0 SK |
357 | if (addr->in6.sin6_scope_id != 0 && |
358 | if_indextoname(addr->in6.sin6_scope_id, name) && | |
359 | strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN) | |
360 | { | |
361 | strcat(buf, "%"); | |
362 | strcat(buf, name); | |
363 | } | |
3d8df260 SK |
364 | port = ntohs(addr->in6.sin6_port); |
365 | } | |
366 | #else | |
367 | strcpy(buf, inet_ntoa(addr->in.sin_addr)); | |
368 | port = ntohs(addr->in.sin_port); | |
369 | #endif | |
370 | ||
371 | return port; | |
372 | } | |
373 | ||
0a852541 SK |
374 | void prettyprint_time(char *buf, unsigned int t) |
375 | { | |
376 | if (t == 0xffffffff) | |
b8187c80 | 377 | sprintf(buf, _("infinite")); |
0a852541 SK |
378 | else |
379 | { | |
380 | unsigned int x, p = 0; | |
3d8df260 SK |
381 | if ((x = t/86400)) |
382 | p += sprintf(&buf[p], "%dd", x); | |
383 | if ((x = (t/3600)%24)) | |
0a852541 SK |
384 | p += sprintf(&buf[p], "%dh", x); |
385 | if ((x = (t/60)%60)) | |
386 | p += sprintf(&buf[p], "%dm", x); | |
387 | if ((x = t%60)) | |
388 | p += sprintf(&buf[p], "%ds", x); | |
389 | } | |
390 | } | |
391 | ||
392 | ||
28866e95 SK |
393 | /* in may equal out, when maxlen may be -1 (No max len). |
394 | Return -1 for extraneous no-hex chars found. */ | |
cdeda28f SK |
395 | int parse_hex(char *in, unsigned char *out, int maxlen, |
396 | unsigned int *wildcard_mask, int *mac_type) | |
0a852541 SK |
397 | { |
398 | int mask = 0, i = 0; | |
399 | char *r; | |
cdeda28f SK |
400 | |
401 | if (mac_type) | |
402 | *mac_type = 0; | |
403 | ||
0a852541 SK |
404 | while (maxlen == -1 || i < maxlen) |
405 | { | |
28866e95 | 406 | for (r = in; *r != 0 && *r != ':' && *r != '-'; r++) |
572b41eb | 407 | if (*r != '*' && !isxdigit((unsigned char)*r)) |
28866e95 SK |
408 | return -1; |
409 | ||
0a852541 SK |
410 | if (*r == 0) |
411 | maxlen = i; | |
cdeda28f | 412 | |
0a852541 SK |
413 | if (r != in ) |
414 | { | |
cdeda28f SK |
415 | if (*r == '-' && i == 0 && mac_type) |
416 | { | |
417 | *r = 0; | |
418 | *mac_type = strtol(in, NULL, 16); | |
419 | mac_type = NULL; | |
420 | } | |
0a852541 | 421 | else |
cdeda28f SK |
422 | { |
423 | *r = 0; | |
424 | mask = mask << 1; | |
425 | if (strcmp(in, "*") == 0) | |
426 | mask |= 1; | |
427 | else | |
428 | out[i] = strtol(in, NULL, 16); | |
429 | i++; | |
430 | } | |
0a852541 SK |
431 | } |
432 | in = r+1; | |
433 | } | |
434 | ||
435 | if (wildcard_mask) | |
436 | *wildcard_mask = mask; | |
437 | ||
438 | return i; | |
439 | } | |
5e9e0efb | 440 | |
7622fc06 | 441 | /* return 0 for no match, or (no matched octets) + 1 */ |
5e9e0efb SK |
442 | int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask) |
443 | { | |
7622fc06 SK |
444 | int i, count; |
445 | for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1) | |
446 | if (!(mask & 1)) | |
447 | { | |
448 | if (a[i] == b[i]) | |
449 | count++; | |
450 | else | |
451 | return 0; | |
452 | } | |
453 | return count; | |
5e9e0efb SK |
454 | } |
455 | ||
456 | /* _note_ may copy buffer */ | |
457 | int expand_buf(struct iovec *iov, size_t size) | |
458 | { | |
459 | void *new; | |
460 | ||
824af85b | 461 | if (size <= (size_t)iov->iov_len) |
5e9e0efb SK |
462 | return 1; |
463 | ||
5aabfc78 | 464 | if (!(new = whine_malloc(size))) |
5e9e0efb SK |
465 | { |
466 | errno = ENOMEM; | |
467 | return 0; | |
468 | } | |
469 | ||
470 | if (iov->iov_base) | |
471 | { | |
472 | memcpy(new, iov->iov_base, iov->iov_len); | |
473 | free(iov->iov_base); | |
474 | } | |
475 | ||
476 | iov->iov_base = new; | |
477 | iov->iov_len = size; | |
478 | ||
479 | return 1; | |
480 | } | |
7cebd20f | 481 | |
5aabfc78 | 482 | char *print_mac(char *buff, unsigned char *mac, int len) |
7cebd20f | 483 | { |
5aabfc78 | 484 | char *p = buff; |
7cebd20f SK |
485 | int i; |
486 | ||
487 | if (len == 0) | |
488 | sprintf(p, "<null>"); | |
489 | else | |
490 | for (i = 0; i < len; i++) | |
491 | p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":"); | |
492 | ||
5aabfc78 | 493 | return buff; |
7cebd20f | 494 | } |
1697269c SK |
495 | |
496 | void bump_maxfd(int fd, int *max) | |
497 | { | |
498 | if (fd > *max) | |
499 | *max = fd; | |
500 | } | |
501 | ||
5aabfc78 SK |
502 | int retry_send(void) |
503 | { | |
504 | struct timespec waiter; | |
c72daea8 | 505 | if (errno == EAGAIN || errno == EWOULDBLOCK) |
5aabfc78 SK |
506 | { |
507 | waiter.tv_sec = 0; | |
508 | waiter.tv_nsec = 10000; | |
509 | nanosleep(&waiter, NULL); | |
510 | return 1; | |
511 | } | |
512 | ||
513 | if (errno == EINTR) | |
514 | return 1; | |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
1697269c SK |
519 | int read_write(int fd, unsigned char *packet, int size, int rw) |
520 | { | |
521 | ssize_t n, done; | |
522 | ||
523 | for (done = 0; done < size; done += n) | |
524 | { | |
525 | retry: | |
526 | if (rw) | |
527 | n = read(fd, &packet[done], (size_t)(size - done)); | |
528 | else | |
529 | n = write(fd, &packet[done], (size_t)(size - done)); | |
530 | ||
531 | if (n == 0) | |
532 | return 0; | |
533 | else if (n == -1) | |
534 | { | |
5aabfc78 | 535 | if (retry_send() || errno == ENOMEM || errno == ENOBUFS) |
1697269c SK |
536 | goto retry; |
537 | else | |
538 | return 0; | |
539 | } | |
540 | } | |
541 | return 1; | |
542 | } | |
1a6bca81 | 543 |