blob: c210add2b1b3d5caff9e5e474470ac55ca5b6a0a [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 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 Kelley1a6bca82008-07-11 11:11:42 +010031/* SURF random number generator */
32
Simon Kelley572b41e2011-02-18 18:11:18 +000033static u32 seed[32];
34static u32 in[12];
35static u32 out[8];
Simon Kelley6586e832013-11-07 14:20:13 +000036static int outleft = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010037
38void rand_init()
39{
40 int fd = open(RANDFILE, O_RDONLY);
41
42 if (fd == -1 ||
43 !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
44 !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
45 die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
46
47 close(fd);
48}
49
50#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
51#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
52
53static void surf(void)
54{
Simon Kelley572b41e2011-02-18 18:11:18 +000055 u32 t[12]; u32 x; u32 sum = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010056 int r; int i; int loop;
57
58 for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
59 for (i = 0;i < 8;++i) out[i] = seed[24 + i];
60 x = t[11];
61 for (loop = 0;loop < 2;++loop) {
62 for (r = 0;r < 16;++r) {
63 sum += 0x9e3779b9;
64 MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
65 MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
66 MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
67 }
68 for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
69 }
70}
71
72unsigned short rand16(void)
73{
Simon Kelley6586e832013-11-07 14:20:13 +000074 if (!outleft)
75 {
76 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
77 surf();
78 outleft = 8;
79 }
80
81 return (unsigned short) out[--outleft];
82}
83
84u64 rand64(void)
85{
Simon Kelley1a6bca82008-07-11 11:11:42 +010086 static int outleft = 0;
87
Simon Kelley6586e832013-11-07 14:20:13 +000088 if (outleft < 2)
89 {
90 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
91 surf();
92 outleft = 8;
93 }
94
95 outleft -= 2;
Simon Kelley1a6bca82008-07-11 11:11:42 +010096
Simon Kelley6586e832013-11-07 14:20:13 +000097 return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
Simon Kelley1a6bca82008-07-11 11:11:42 +010098}
99
Simon Kelley1f15b812009-10-13 17:49:32 +0100100static int check_name(char *in)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000101{
Simon Kelley1f15b812009-10-13 17:49:32 +0100102 /* remove trailing .
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000103 also fail empty string and label > 63 chars */
Simon Kelley1f15b812009-10-13 17:49:32 +0100104 size_t dotgap = 0, l = strlen(in);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000105 char c;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 int nowhite = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100107
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000108 if (l == 0 || l > MAXDNAME) return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100109
110 if (in[l-1] == '.')
Simon Kelleya2226412004-05-13 20:27:08 +0100111 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100112 in[l-1] = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000113 nowhite = 1;
Simon Kelleya2226412004-05-13 20:27:08 +0100114 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000115
Simon Kelley1f15b812009-10-13 17:49:32 +0100116 for (; (c = *in); in++)
Simon Kelley3d8df262005-08-29 12:19:27 +0100117 {
118 if (c == '.')
119 dotgap = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100120 else if (++dotgap > MAXLABEL)
Simon Kelley3d8df262005-08-29 12:19:27 +0100121 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000122 else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100123 /* iscntrl only gives expected results for ascii */
124 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000125#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
126 else if (!isascii((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100127 return 0;
128#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100129 else if (c != ' ')
130 nowhite = 1;
Simon Kelley3d8df262005-08-29 12:19:27 +0100131 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100132
133 if (!nowhite)
134 return 0;
135
136 return 1;
137}
138
139/* Hostnames have a more limited valid charset than domain names
140 so check for legal char a-z A-Z 0-9 - _
141 Note that this may receive a FQDN, so only check the first label
142 for the tighter criteria. */
143int legal_hostname(char *name)
144{
145 char c;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100146 int first;
Simon Kelley1f15b812009-10-13 17:49:32 +0100147
148 if (!check_name(name))
149 return 0;
150
Simon Kelley7abb69b2013-04-29 10:52:16 +0100151 for (first = 1; (c = *name); name++, first = 0)
Simon Kelley1f15b812009-10-13 17:49:32 +0100152 /* check for legal char a-z A-Z 0-9 - _ . */
153 {
154 if ((c >= 'A' && c <= 'Z') ||
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100155 (c >= 'a' && c <= 'z') ||
156 (c >= '0' && c <= '9'))
Simon Kelley1f15b812009-10-13 17:49:32 +0100157 continue;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100158
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100159 if (!first && (c == '-' || c == '_'))
Simon Kelley7abb69b2013-04-29 10:52:16 +0100160 continue;
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100161
Simon Kelley1f15b812009-10-13 17:49:32 +0100162 /* end of hostname part */
163 if (c == '.')
164 return 1;
165
166 return 0;
167 }
168
169 return 1;
170}
171
172char *canonicalise(char *in, int *nomem)
173{
174 char *ret = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000175#if defined(LOCALEDIR) || defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +0100176 int rc;
177#endif
178
179 if (nomem)
180 *nomem = 0;
181
182 if (!check_name(in))
183 return NULL;
184
Simon Kelley572b41e2011-02-18 18:11:18 +0000185#if defined(LOCALEDIR) || defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +0100186 if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
187 {
188 if (ret)
189 free(ret);
190
191 if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
192 {
193 my_syslog(LOG_ERR, _("failed to allocate memory"));
194 *nomem = 1;
195 }
196
197 return NULL;
198 }
199#else
200 if ((ret = whine_malloc(strlen(in)+1)))
201 strcpy(ret, in);
202 else if (nomem)
203 *nomem = 1;
204#endif
205
206 return ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000207}
208
Simon Kelley3d8df262005-08-29 12:19:27 +0100209unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
210{
211 int j;
212
213 while (sval && *sval)
214 {
215 unsigned char *cp = p++;
216 for (j = 0; *sval && (*sval != '.'); sval++, j++)
217 *p++ = *sval;
218 *cp = j;
219 if (*sval)
220 sval++;
221 }
222 return p;
223}
224
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000225/* for use during startup */
Simon Kelley0a852542005-03-23 20:28:59 +0000226void *safe_malloc(size_t size)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000227{
228 void *ret = malloc(size);
229
230 if (!ret)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100231 die(_("could not get memory"), NULL, EC_NOMEM);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000232
233 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100234}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000235
Simon Kelley1a6bca82008-07-11 11:11:42 +0100236void safe_pipe(int *fd, int read_noblock)
237{
238 if (pipe(fd) == -1 ||
239 !fix_fd(fd[1]) ||
240 (read_noblock && !fix_fd(fd[0])))
241 die(_("cannot create pipe: %s"), NULL, EC_MISC);
242}
243
Simon Kelley5aabfc72007-08-29 11:24:47 +0100244void *whine_malloc(size_t size)
245{
246 void *ret = malloc(size);
247
248 if (!ret)
249 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
250
251 return ret;
252}
253
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000254int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
255{
256 if (s1->sa.sa_family == s2->sa.sa_family)
257 {
258 if (s1->sa.sa_family == AF_INET &&
259 s1->in.sin_port == s2->in.sin_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100260 s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000261 return 1;
262#ifdef HAVE_IPV6
263 if (s1->sa.sa_family == AF_INET6 &&
264 s1->in6.sin6_port == s2->in6.sin6_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100265 IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000266 return 1;
267#endif
268 }
269 return 0;
270}
271
272int sa_len(union mysockaddr *addr)
273{
274#ifdef HAVE_SOCKADDR_SA_LEN
275 return addr->sa.sa_len;
276#else
277#ifdef HAVE_IPV6
278 if (addr->sa.sa_family == AF_INET6)
279 return sizeof(addr->in6);
280 else
281#endif
282 return sizeof(addr->in);
283#endif
284}
285
286/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
Simon Kelleyc99df932012-10-12 13:39:04 +0100287int hostname_isequal(const char *a, const char *b)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000288{
289 unsigned int c1, c2;
290
291 do {
Simon Kelley3d8df262005-08-29 12:19:27 +0100292 c1 = (unsigned char) *a++;
293 c2 = (unsigned char) *b++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000294
295 if (c1 >= 'A' && c1 <= 'Z')
296 c1 += 'a' - 'A';
297 if (c2 >= 'A' && c2 <= 'Z')
298 c2 += 'a' - 'A';
299
300 if (c1 != c2)
301 return 0;
302 } while (c1);
303
304 return 1;
305}
306
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100307time_t dnsmasq_time(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000308{
309#ifdef HAVE_BROKEN_RTC
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100310 struct tms dummy;
311 static long tps = 0;
312
313 if (tps == 0)
314 tps = sysconf(_SC_CLK_TCK);
315
316 return (time_t)(times(&dummy)/tps);
Simon Kelley44a2a312004-03-10 20:04:35 +0000317#else
Simon Kelley44a2a312004-03-10 20:04:35 +0000318 return time(NULL);
319#endif
320}
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100321
322int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
323{
324 return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
325}
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100326
Simon Kelleyc72daea2012-01-05 21:33:27 +0000327#ifdef HAVE_IPV6
328int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
329{
330 int pfbytes = prefixlen >> 3;
331 int pfbits = prefixlen & 7;
332
333 if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
334 return 0;
335
336 if (pfbits == 0 ||
Simon Kelleyc64b7f62012-05-18 10:19:59 +0100337 (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000338 return 1;
339
340 return 0;
341}
342
Simon Kelley52b92f42012-01-22 16:05:15 +0000343/* return least signigicant 64 bits if IPv6 address */
344u64 addr6part(struct in6_addr *addr)
345{
346 int i;
347 u64 ret = 0;
348
349 for (i = 8; i < 16; i++)
350 ret = (ret << 8) + addr->s6_addr[i];
351
352 return ret;
353}
354
355void setaddr6part(struct in6_addr *addr, u64 host)
356{
357 int i;
358
359 for (i = 15; i >= 8; i--)
360 {
361 addr->s6_addr[i] = host;
362 host = host >> 8;
363 }
364}
365
Simon Kelleyc72daea2012-01-05 21:33:27 +0000366#endif
367
368
Simon Kelley3d8df262005-08-29 12:19:27 +0100369/* returns port number from address */
370int prettyprint_addr(union mysockaddr *addr, char *buf)
371{
372 int port = 0;
373
374#ifdef HAVE_IPV6
375 if (addr->sa.sa_family == AF_INET)
376 {
377 inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
378 port = ntohs(addr->in.sin_port);
379 }
380 else if (addr->sa.sa_family == AF_INET6)
381 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100382 char name[IF_NAMESIZE];
Simon Kelley3d8df262005-08-29 12:19:27 +0100383 inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
Simon Kelley7de060b2011-08-26 17:24:52 +0100384 if (addr->in6.sin6_scope_id != 0 &&
385 if_indextoname(addr->in6.sin6_scope_id, name) &&
386 strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
387 {
388 strcat(buf, "%");
389 strcat(buf, name);
390 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100391 port = ntohs(addr->in6.sin6_port);
392 }
393#else
394 strcpy(buf, inet_ntoa(addr->in.sin_addr));
395 port = ntohs(addr->in.sin_port);
396#endif
397
398 return port;
399}
400
Simon Kelley0a852542005-03-23 20:28:59 +0000401void prettyprint_time(char *buf, unsigned int t)
402{
403 if (t == 0xffffffff)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000404 sprintf(buf, _("infinite"));
Simon Kelley0a852542005-03-23 20:28:59 +0000405 else
406 {
407 unsigned int x, p = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100408 if ((x = t/86400))
409 p += sprintf(&buf[p], "%dd", x);
410 if ((x = (t/3600)%24))
Simon Kelley0a852542005-03-23 20:28:59 +0000411 p += sprintf(&buf[p], "%dh", x);
412 if ((x = (t/60)%60))
413 p += sprintf(&buf[p], "%dm", x);
414 if ((x = t%60))
415 p += sprintf(&buf[p], "%ds", x);
416 }
417}
418
419
Simon Kelley28866e92011-02-14 20:19:14 +0000420/* in may equal out, when maxlen may be -1 (No max len).
421 Return -1 for extraneous no-hex chars found. */
Simon Kelleycdeda282006-03-16 20:16:06 +0000422int parse_hex(char *in, unsigned char *out, int maxlen,
423 unsigned int *wildcard_mask, int *mac_type)
Simon Kelley0a852542005-03-23 20:28:59 +0000424{
425 int mask = 0, i = 0;
426 char *r;
Simon Kelleycdeda282006-03-16 20:16:06 +0000427
428 if (mac_type)
429 *mac_type = 0;
430
Simon Kelley0a852542005-03-23 20:28:59 +0000431 while (maxlen == -1 || i < maxlen)
432 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100433 for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000434 if (*r != '*' && !isxdigit((unsigned char)*r))
Simon Kelley28866e92011-02-14 20:19:14 +0000435 return -1;
436
Simon Kelley0a852542005-03-23 20:28:59 +0000437 if (*r == 0)
438 maxlen = i;
Simon Kelleycdeda282006-03-16 20:16:06 +0000439
Simon Kelley0a852542005-03-23 20:28:59 +0000440 if (r != in )
441 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000442 if (*r == '-' && i == 0 && mac_type)
443 {
444 *r = 0;
445 *mac_type = strtol(in, NULL, 16);
446 mac_type = NULL;
447 }
Simon Kelley0a852542005-03-23 20:28:59 +0000448 else
Simon Kelleycdeda282006-03-16 20:16:06 +0000449 {
450 *r = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000451 if (strcmp(in, "*") == 0)
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100452 {
453 mask = (mask << 1) | 1;
454 i++;
455 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000456 else
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100457 {
458 int j, bytes = (1 + (r - in))/2;
459 for (j = 0; j < bytes; j++)
460 {
Vladislav Grishenko50db3492013-11-26 11:09:31 +0000461 char sav = sav;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100462 if (j < bytes - 1)
463 {
464 sav = in[(j+1)*2];
465 in[(j+1)*2] = 0;
466 }
467 out[i] = strtol(&in[j*2], NULL, 16);
468 mask = mask << 1;
469 i++;
470 if (j < bytes - 1)
471 in[(j+1)*2] = sav;
472 }
473 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000474 }
Simon Kelley0a852542005-03-23 20:28:59 +0000475 }
476 in = r+1;
477 }
478
479 if (wildcard_mask)
480 *wildcard_mask = mask;
481
482 return i;
483}
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100484
Simon Kelley0fc2f312014-01-08 10:26:58 +0000485#ifdef HAVE_DNSSEC
486static int charval(char c)
487{
488 if (c >= 'A' && c <= 'Z')
489 return c - 'A';
490
491 if (c >= 'a' && c <= 'z')
492 return c - 'a' + 26;
493
494 if (c >= '0' && c <= '9')
495 return c - '0' + 52;
496
497 if (c == '+')
498 return 62;
499
500 if (c == '/')
501 return 63;
502
503 if (c == '=')
504 return -1;
505
506 return -2;
507}
508
509int parse_base64(char *in, char *out)
510{
511 char *p = out;
512 int i, val[4];
513
514 while (*in)
515 {
516 for (i = 0; i < 4; i++)
517 {
518 while (*in == ' ')
519 in++;
520 if (*in == 0)
521 return -1;
522 if ((val[i] = charval(*in++)) == -2)
523 return -1;
524 }
525
526 while (*in == ' ')
527 in++;
528
529 if (val[1] == -1)
530 return -1; /* too much padding */
531
532 *p++ = (val[0] << 2) | (val[1] >> 4);
533
534 if (val[2] != -1)
535 *p++ = (val[1] << 4) | ( val[2] >> 2);
536
537 if (val[3] != -1)
538 *p++ = (val[2] << 6) | val[3];
539 }
540
541 return p - out;
542}
543#endif
544
Simon Kelley7622fc02009-06-04 20:32:05 +0100545/* return 0 for no match, or (no matched octets) + 1 */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100546int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
547{
Simon Kelley7622fc02009-06-04 20:32:05 +0100548 int i, count;
549 for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
550 if (!(mask & 1))
551 {
552 if (a[i] == b[i])
553 count++;
554 else
555 return 0;
556 }
557 return count;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100558}
559
560/* _note_ may copy buffer */
561int expand_buf(struct iovec *iov, size_t size)
562{
563 void *new;
564
Simon Kelley824af852008-02-12 20:43:05 +0000565 if (size <= (size_t)iov->iov_len)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100566 return 1;
567
Simon Kelley5aabfc72007-08-29 11:24:47 +0100568 if (!(new = whine_malloc(size)))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100569 {
570 errno = ENOMEM;
571 return 0;
572 }
573
574 if (iov->iov_base)
575 {
576 memcpy(new, iov->iov_base, iov->iov_len);
577 free(iov->iov_base);
578 }
579
580 iov->iov_base = new;
581 iov->iov_len = size;
582
583 return 1;
584}
Simon Kelley7cebd202006-05-06 14:13:33 +0100585
Simon Kelley5aabfc72007-08-29 11:24:47 +0100586char *print_mac(char *buff, unsigned char *mac, int len)
Simon Kelley7cebd202006-05-06 14:13:33 +0100587{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100588 char *p = buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100589 int i;
590
591 if (len == 0)
592 sprintf(p, "<null>");
593 else
594 for (i = 0; i < len; i++)
595 p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
596
Simon Kelley5aabfc72007-08-29 11:24:47 +0100597 return buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100598}
Simon Kelley16972692006-10-16 20:04:18 +0100599
600void bump_maxfd(int fd, int *max)
601{
602 if (fd > *max)
603 *max = fd;
604}
605
Simon Kelley5aabfc72007-08-29 11:24:47 +0100606int retry_send(void)
607{
608 struct timespec waiter;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000609 if (errno == EAGAIN || errno == EWOULDBLOCK)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100610 {
611 waiter.tv_sec = 0;
612 waiter.tv_nsec = 10000;
613 nanosleep(&waiter, NULL);
614 return 1;
615 }
616
617 if (errno == EINTR)
618 return 1;
619
620 return 0;
621}
622
Simon Kelley16972692006-10-16 20:04:18 +0100623int read_write(int fd, unsigned char *packet, int size, int rw)
624{
625 ssize_t n, done;
626
627 for (done = 0; done < size; done += n)
628 {
629 retry:
630 if (rw)
631 n = read(fd, &packet[done], (size_t)(size - done));
632 else
633 n = write(fd, &packet[done], (size_t)(size - done));
634
635 if (n == 0)
636 return 0;
637 else if (n == -1)
638 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100639 if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
Simon Kelley16972692006-10-16 20:04:18 +0100640 goto retry;
641 else
642 return 0;
643 }
644 }
645 return 1;
646}
Simon Kelley1a6bca82008-07-11 11:11:42 +0100647
Simon Kelley49333cb2013-03-15 20:30:51 +0000648/* Basically match a string value against a wildcard pattern. */
649int wildcard_match(const char* wildcard, const char* match)
650{
651 while (*wildcard && *match)
652 {
653 if (*wildcard == '*')
654 return 1;
655
656 if (*wildcard != *match)
657 return 0;
658
659 ++wildcard;
660 ++match;
661 }
662
663 return *wildcard == *match;
664}