]>
Commit | Line | Data |
---|---|---|
0a852541 | 1 | /* dnsmasq is Copyright (c) 2000 - 2005 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 | |
5 | the Free Software Foundation; version 2 dated June, 1991. | |
6 | ||
7 | This program is distributed in the hope that it will be useful, | |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | GNU General Public License for more details. | |
11 | */ | |
12 | ||
13 | ||
a222641c | 14 | /* Some code in this file contributed by Rob Funk. */ |
9e4abcb5 SK |
15 | |
16 | #include "dnsmasq.h" | |
17 | ||
5e9e0efb SK |
18 | #ifdef HAVE_BROKEN_RTC |
19 | #include <sys/times.h> | |
20 | #endif | |
21 | ||
9e4abcb5 SK |
22 | /* Prefer arc4random(3) over random(3) over rand(3) */ |
23 | /* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */ | |
24 | #ifdef HAVE_ARC4RANDOM | |
25 | # define rand() arc4random() | |
26 | # define srand(s) (void)0 | |
27 | # define RANDFILE (NULL) | |
28 | #else | |
29 | # ifdef HAVE_RANDOM | |
30 | # define rand() random() | |
31 | # define srand(s) srandom(s) | |
32 | # endif | |
33 | # ifdef HAVE_DEV_URANDOM | |
34 | # define RANDFILE "/dev/urandom" | |
35 | # else | |
36 | # ifdef HAVE_DEV_RANDOM | |
37 | # define RANDFILE "/dev/random" | |
38 | # else | |
39 | # define RANDFILE (NULL) | |
40 | # endif | |
41 | # endif | |
42 | #endif | |
43 | ||
44 | unsigned short rand16(void) | |
45 | { | |
46 | static int been_seeded = 0; | |
47 | const char *randfile = RANDFILE; | |
48 | ||
49 | if (! been_seeded) | |
50 | { | |
51 | int fd, n = 0; | |
52 | unsigned int c = 0, seed = 0, badseed; | |
53 | char sbuf[sizeof(seed)]; | |
54 | char *s; | |
55 | struct timeval now; | |
56 | ||
57 | /* get the bad seed as a backup */ | |
58 | /* (but we'd rather have something more random) */ | |
59 | gettimeofday(&now, NULL); | |
60 | badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16); | |
61 | ||
62 | fd = open(randfile, O_RDONLY); | |
63 | if (fd < 0) | |
64 | seed = badseed; | |
65 | else | |
66 | { | |
67 | s = (char *) &seed; | |
44a2a316 SK |
68 | while ((c < sizeof(seed)) && |
69 | ((n = read(fd, sbuf, sizeof(seed)) > 0))) | |
9e4abcb5 SK |
70 | { |
71 | memcpy(s, sbuf, n); | |
72 | s += n; | |
73 | c += n; | |
74 | } | |
75 | if (n < 0) | |
44a2a316 | 76 | seed = badseed; |
9e4abcb5 SK |
77 | close(fd); |
78 | } | |
79 | ||
80 | srand(seed); | |
81 | been_seeded = 1; | |
82 | } | |
83 | ||
84 | /* Some rand() implementations have less randomness in low bits | |
85 | * than in high bits, so we only pay attention to the high ones. | |
86 | * But most implementations don't touch the high bit, so we | |
87 | * ignore that one. | |
88 | */ | |
89 | return( (unsigned short) (rand() >> 15) ); | |
90 | } | |
91 | ||
92 | int legal_char(char c) | |
93 | { | |
94 | /* check for legal char a-z A-Z 0-9 - | |
95 | (also / , used for RFC2317 and _ used in windows queries) */ | |
96 | if ((c >= 'A' && c <= 'Z') || | |
97 | (c >= 'a' && c <= 'z') || | |
98 | (c >= '0' && c <= '9') || | |
99 | c == '-' || c == '/' || c == '_') | |
100 | return 1; | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
105 | int canonicalise(char *s) | |
106 | { | |
a222641c | 107 | /* check for legal chars and remove trailing . |
f6b7dc47 | 108 | also fail empty string and label > 63 chars */ |
0a852541 | 109 | size_t dotgap = 0, l = strlen(s); |
9e4abcb5 SK |
110 | char c; |
111 | ||
f6b7dc47 | 112 | if (l == 0 || l > MAXDNAME) return 0; |
a222641c SK |
113 | |
114 | if (s[l-1] == '.') | |
115 | { | |
116 | if (l == 1) return 0; | |
117 | s[l-1] = 0; | |
118 | } | |
f6b7dc47 | 119 | |
3d8df260 SK |
120 | while ((c = *s)) |
121 | { | |
122 | if (c == '.') | |
123 | dotgap = 0; | |
124 | else if (!legal_char(c) || (++dotgap > MAXLABEL)) | |
125 | return 0; | |
126 | s++; | |
127 | } | |
9e4abcb5 SK |
128 | return 1; |
129 | } | |
130 | ||
3d8df260 SK |
131 | unsigned char *do_rfc1035_name(unsigned char *p, char *sval) |
132 | { | |
133 | int j; | |
134 | ||
135 | while (sval && *sval) | |
136 | { | |
137 | unsigned char *cp = p++; | |
138 | for (j = 0; *sval && (*sval != '.'); sval++, j++) | |
139 | *p++ = *sval; | |
140 | *cp = j; | |
141 | if (*sval) | |
142 | sval++; | |
143 | } | |
144 | return p; | |
145 | } | |
146 | ||
9e4abcb5 | 147 | /* for use during startup */ |
0a852541 | 148 | void *safe_malloc(size_t size) |
9e4abcb5 SK |
149 | { |
150 | void *ret = malloc(size); | |
151 | ||
152 | if (!ret) | |
b8187c80 | 153 | die(_("could not get memory"), NULL); |
9e4abcb5 SK |
154 | |
155 | return ret; | |
3d8df260 | 156 | } |
9e4abcb5 | 157 | |
0a852541 | 158 | static void log_err(char *message, char *arg1) |
9e4abcb5 SK |
159 | { |
160 | char *errmess = strerror(errno); | |
161 | ||
162 | if (!arg1) | |
163 | arg1 = errmess; | |
164 | ||
165 | fprintf(stderr, "dnsmasq: "); | |
166 | fprintf(stderr, message, arg1, errmess); | |
167 | fprintf(stderr, "\n"); | |
168 | ||
169 | syslog(LOG_CRIT, message, arg1, errmess); | |
170 | } | |
171 | ||
0a852541 SK |
172 | void complain(char *message, int lineno, char *file) |
173 | { | |
174 | char buff[256]; | |
175 | ||
b8187c80 | 176 | sprintf(buff, _("%s at line %d of %%s"), message, lineno); |
3d8df260 | 177 | log_err(buff, file); |
0a852541 SK |
178 | } |
179 | ||
9e4abcb5 SK |
180 | void die(char *message, char *arg1) |
181 | { | |
0a852541 | 182 | log_err(message, arg1); |
b8187c80 | 183 | syslog(LOG_CRIT, _("FAILED to start up")); |
9e4abcb5 SK |
184 | exit(1); |
185 | } | |
186 | ||
187 | int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2) | |
188 | { | |
189 | if (s1->sa.sa_family == s2->sa.sa_family) | |
190 | { | |
191 | if (s1->sa.sa_family == AF_INET && | |
192 | s1->in.sin_port == s2->in.sin_port && | |
5e9e0efb | 193 | s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr) |
9e4abcb5 SK |
194 | return 1; |
195 | #ifdef HAVE_IPV6 | |
196 | if (s1->sa.sa_family == AF_INET6 && | |
197 | s1->in6.sin6_port == s2->in6.sin6_port && | |
5e9e0efb | 198 | IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr)) |
9e4abcb5 SK |
199 | return 1; |
200 | #endif | |
201 | } | |
202 | return 0; | |
203 | } | |
204 | ||
205 | int sa_len(union mysockaddr *addr) | |
206 | { | |
207 | #ifdef HAVE_SOCKADDR_SA_LEN | |
208 | return addr->sa.sa_len; | |
209 | #else | |
210 | #ifdef HAVE_IPV6 | |
211 | if (addr->sa.sa_family == AF_INET6) | |
212 | return sizeof(addr->in6); | |
213 | else | |
214 | #endif | |
215 | return sizeof(addr->in); | |
216 | #endif | |
217 | } | |
218 | ||
219 | /* don't use strcasecmp and friends here - they may be messed up by LOCALE */ | |
3d8df260 | 220 | int hostname_isequal(char *a, char *b) |
9e4abcb5 SK |
221 | { |
222 | unsigned int c1, c2; | |
223 | ||
224 | do { | |
3d8df260 SK |
225 | c1 = (unsigned char) *a++; |
226 | c2 = (unsigned char) *b++; | |
9e4abcb5 SK |
227 | |
228 | if (c1 >= 'A' && c1 <= 'Z') | |
229 | c1 += 'a' - 'A'; | |
230 | if (c2 >= 'A' && c2 <= 'Z') | |
231 | c2 += 'a' - 'A'; | |
232 | ||
233 | if (c1 != c2) | |
234 | return 0; | |
235 | } while (c1); | |
236 | ||
237 | return 1; | |
238 | } | |
239 | ||
5e9e0efb | 240 | time_t dnsmasq_time(void) |
44a2a316 SK |
241 | { |
242 | #ifdef HAVE_BROKEN_RTC | |
5e9e0efb SK |
243 | struct tms dummy; |
244 | static long tps = 0; | |
245 | ||
246 | if (tps == 0) | |
247 | tps = sysconf(_SC_CLK_TCK); | |
248 | ||
249 | return (time_t)(times(&dummy)/tps); | |
44a2a316 | 250 | #else |
44a2a316 SK |
251 | return time(NULL); |
252 | #endif | |
253 | } | |
a84fa1d0 SK |
254 | |
255 | int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) | |
256 | { | |
257 | return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); | |
258 | } | |
fd9fa481 SK |
259 | |
260 | int retry_send(void) | |
261 | { | |
262 | struct timespec waiter; | |
263 | if (errno == EAGAIN) | |
264 | { | |
265 | waiter.tv_sec = 0; | |
266 | waiter.tv_nsec = 10000; | |
267 | nanosleep(&waiter, NULL); | |
268 | return 1; | |
269 | } | |
270 | ||
271 | if (errno == EINTR) | |
272 | return 1; | |
273 | ||
274 | return 0; | |
275 | } | |
0a852541 | 276 | |
3d8df260 SK |
277 | /* returns port number from address */ |
278 | int prettyprint_addr(union mysockaddr *addr, char *buf) | |
279 | { | |
280 | int port = 0; | |
281 | ||
282 | #ifdef HAVE_IPV6 | |
283 | if (addr->sa.sa_family == AF_INET) | |
284 | { | |
285 | inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN); | |
286 | port = ntohs(addr->in.sin_port); | |
287 | } | |
288 | else if (addr->sa.sa_family == AF_INET6) | |
289 | { | |
290 | inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN); | |
291 | port = ntohs(addr->in6.sin6_port); | |
292 | } | |
293 | #else | |
294 | strcpy(buf, inet_ntoa(addr->in.sin_addr)); | |
295 | port = ntohs(addr->in.sin_port); | |
296 | #endif | |
297 | ||
298 | return port; | |
299 | } | |
300 | ||
0a852541 SK |
301 | void prettyprint_time(char *buf, unsigned int t) |
302 | { | |
303 | if (t == 0xffffffff) | |
b8187c80 | 304 | sprintf(buf, _("infinite")); |
0a852541 SK |
305 | else |
306 | { | |
307 | unsigned int x, p = 0; | |
3d8df260 SK |
308 | if ((x = t/86400)) |
309 | p += sprintf(&buf[p], "%dd", x); | |
310 | if ((x = (t/3600)%24)) | |
0a852541 SK |
311 | p += sprintf(&buf[p], "%dh", x); |
312 | if ((x = (t/60)%60)) | |
313 | p += sprintf(&buf[p], "%dm", x); | |
314 | if ((x = t%60)) | |
315 | p += sprintf(&buf[p], "%ds", x); | |
316 | } | |
317 | } | |
318 | ||
319 | ||
320 | /* in may equal out, when maxlen may be -1 (No max len). */ | |
cdeda28f SK |
321 | int parse_hex(char *in, unsigned char *out, int maxlen, |
322 | unsigned int *wildcard_mask, int *mac_type) | |
0a852541 SK |
323 | { |
324 | int mask = 0, i = 0; | |
325 | char *r; | |
cdeda28f SK |
326 | |
327 | if (mac_type) | |
328 | *mac_type = 0; | |
329 | ||
0a852541 SK |
330 | while (maxlen == -1 || i < maxlen) |
331 | { | |
332 | for (r = in; *r != 0 && *r != ':' && *r != '-'; r++); | |
333 | if (*r == 0) | |
334 | maxlen = i; | |
cdeda28f | 335 | |
0a852541 SK |
336 | if (r != in ) |
337 | { | |
cdeda28f SK |
338 | if (*r == '-' && i == 0 && mac_type) |
339 | { | |
340 | *r = 0; | |
341 | *mac_type = strtol(in, NULL, 16); | |
342 | mac_type = NULL; | |
343 | } | |
0a852541 | 344 | else |
cdeda28f SK |
345 | { |
346 | *r = 0; | |
347 | mask = mask << 1; | |
348 | if (strcmp(in, "*") == 0) | |
349 | mask |= 1; | |
350 | else | |
351 | out[i] = strtol(in, NULL, 16); | |
352 | i++; | |
353 | } | |
0a852541 SK |
354 | } |
355 | in = r+1; | |
356 | } | |
357 | ||
358 | if (wildcard_mask) | |
359 | *wildcard_mask = mask; | |
360 | ||
361 | return i; | |
362 | } | |
5e9e0efb SK |
363 | |
364 | int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask) | |
365 | { | |
366 | int i; | |
367 | for (i = len - 1; i >= 0; i--, mask = mask >> 1) | |
368 | if (!(mask & 1) && a[i] != b[i]) | |
369 | return 0; | |
370 | ||
371 | return 1; | |
372 | } | |
373 | ||
374 | /* _note_ may copy buffer */ | |
375 | int expand_buf(struct iovec *iov, size_t size) | |
376 | { | |
377 | void *new; | |
378 | ||
379 | if (size <= iov->iov_len) | |
380 | return 1; | |
381 | ||
382 | if (!(new = malloc(size))) | |
383 | { | |
384 | errno = ENOMEM; | |
385 | return 0; | |
386 | } | |
387 | ||
388 | if (iov->iov_base) | |
389 | { | |
390 | memcpy(new, iov->iov_base, iov->iov_len); | |
391 | free(iov->iov_base); | |
392 | } | |
393 | ||
394 | iov->iov_base = new; | |
395 | iov->iov_len = size; | |
396 | ||
397 | return 1; | |
398 | } | |
7cebd20f SK |
399 | |
400 | char *print_mac(struct daemon *daemon, unsigned char *mac, int len) | |
401 | { | |
402 | char *p = daemon->namebuff; | |
403 | int i; | |
404 | ||
405 | if (len == 0) | |
406 | sprintf(p, "<null>"); | |
407 | else | |
408 | for (i = 0; i < len; i++) | |
409 | p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":"); | |
410 | ||
411 | return daemon->namebuff; | |
412 | } |