]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/util.c
import of dnsmasq-2.28.tar.gz
[people/ms/dnsmasq.git] / src / util.c
CommitLineData
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
44unsigned 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
92int 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
105int 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
131unsigned 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 148void *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 158static 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
172void 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
180void 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
187int 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
205int 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 220int 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 240time_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
255int 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
260int 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 */
278int 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
301void 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
321int 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
364int 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 */
375int 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}