blob: 079fe44dfdaafed7954d922342b0a3ef4e3ef56c [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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 Kelley43cdf1c2017-05-21 22:12:44 +010027#if defined(HAVE_LIBIDN2)
Petr Menšíkd203af42017-05-10 21:41:57 +010028#include <idn2.h>
Simon Kelley43cdf1c2017-05-21 22:12:44 +010029#elif defined(HAVE_IDN)
Simon Kelley1f15b812009-10-13 17:49:32 +010030#include <idna.h>
31#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +010032
Simon Kelley1a6bca82008-07-11 11:11:42 +010033/* SURF random number generator */
34
Simon Kelley572b41e2011-02-18 18:11:18 +000035static u32 seed[32];
36static u32 in[12];
37static u32 out[8];
Simon Kelley6586e832013-11-07 14:20:13 +000038static int outleft = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010039
40void rand_init()
41{
42 int fd = open(RANDFILE, O_RDONLY);
43
44 if (fd == -1 ||
45 !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
46 !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
47 die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
48
49 close(fd);
50}
51
52#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
53#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
54
55static void surf(void)
56{
Simon Kelley572b41e2011-02-18 18:11:18 +000057 u32 t[12]; u32 x; u32 sum = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010058 int r; int i; int loop;
59
60 for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
61 for (i = 0;i < 8;++i) out[i] = seed[24 + i];
62 x = t[11];
63 for (loop = 0;loop < 2;++loop) {
64 for (r = 0;r < 16;++r) {
65 sum += 0x9e3779b9;
66 MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
67 MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
68 MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
69 }
70 for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
71 }
72}
73
74unsigned short rand16(void)
75{
Simon Kelley6586e832013-11-07 14:20:13 +000076 if (!outleft)
77 {
78 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
79 surf();
80 outleft = 8;
81 }
82
83 return (unsigned short) out[--outleft];
84}
85
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +010086u32 rand32(void)
87{
88 if (!outleft)
89 {
90 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
91 surf();
92 outleft = 8;
93 }
94
95 return out[--outleft];
96}
97
Simon Kelley6586e832013-11-07 14:20:13 +000098u64 rand64(void)
99{
Simon Kelley1a6bca82008-07-11 11:11:42 +0100100 static int outleft = 0;
101
Simon Kelley6586e832013-11-07 14:20:13 +0000102 if (outleft < 2)
103 {
104 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
105 surf();
106 outleft = 8;
107 }
108
109 outleft -= 2;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100110
Simon Kelley6586e832013-11-07 14:20:13 +0000111 return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100112}
113
Simon Kelley69a815a2017-07-08 21:20:16 +0100114/* returns 2 if names is OK but contains one or more underscores */
Simon Kelley1f15b812009-10-13 17:49:32 +0100115static int check_name(char *in)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000116{
Simon Kelley1f15b812009-10-13 17:49:32 +0100117 /* remove trailing .
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000118 also fail empty string and label > 63 chars */
Simon Kelley1f15b812009-10-13 17:49:32 +0100119 size_t dotgap = 0, l = strlen(in);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120 char c;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100121 int nowhite = 0;
Simon Kelley69a815a2017-07-08 21:20:16 +0100122 int hasuscore = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100123
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000124 if (l == 0 || l > MAXDNAME) return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100125
126 if (in[l-1] == '.')
Simon Kelleya2226412004-05-13 20:27:08 +0100127 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100128 in[l-1] = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000129 nowhite = 1;
Simon Kelleya2226412004-05-13 20:27:08 +0100130 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000131
Simon Kelley1f15b812009-10-13 17:49:32 +0100132 for (; (c = *in); in++)
Simon Kelley3d8df262005-08-29 12:19:27 +0100133 {
134 if (c == '.')
135 dotgap = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100136 else if (++dotgap > MAXLABEL)
Simon Kelley3d8df262005-08-29 12:19:27 +0100137 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000138 else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100139 /* iscntrl only gives expected results for ascii */
140 return 0;
Simon Kelley43cdf1c2017-05-21 22:12:44 +0100141#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
Simon Kelley572b41e2011-02-18 18:11:18 +0000142 else if (!isascii((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100143 return 0;
144#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100145 else if (c != ' ')
Simon Kelley69a815a2017-07-08 21:20:16 +0100146 {
147 nowhite = 1;
148 if (c == '_')
149 hasuscore = 1;
150 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100151 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100152
153 if (!nowhite)
154 return 0;
155
Simon Kelley69a815a2017-07-08 21:20:16 +0100156 return hasuscore ? 2 : 1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100157}
158
159/* Hostnames have a more limited valid charset than domain names
160 so check for legal char a-z A-Z 0-9 - _
161 Note that this may receive a FQDN, so only check the first label
162 for the tighter criteria. */
163int legal_hostname(char *name)
164{
165 char c;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100166 int first;
Simon Kelley1f15b812009-10-13 17:49:32 +0100167
168 if (!check_name(name))
169 return 0;
170
Simon Kelley7abb69b2013-04-29 10:52:16 +0100171 for (first = 1; (c = *name); name++, first = 0)
Simon Kelley1f15b812009-10-13 17:49:32 +0100172 /* check for legal char a-z A-Z 0-9 - _ . */
173 {
174 if ((c >= 'A' && c <= 'Z') ||
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100175 (c >= 'a' && c <= 'z') ||
176 (c >= '0' && c <= '9'))
Simon Kelley1f15b812009-10-13 17:49:32 +0100177 continue;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100178
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100179 if (!first && (c == '-' || c == '_'))
Simon Kelley7abb69b2013-04-29 10:52:16 +0100180 continue;
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100181
Simon Kelley1f15b812009-10-13 17:49:32 +0100182 /* end of hostname part */
183 if (c == '.')
184 return 1;
185
186 return 0;
187 }
188
189 return 1;
190}
191
192char *canonicalise(char *in, int *nomem)
193{
194 char *ret = NULL;
Simon Kelley1f15b812009-10-13 17:49:32 +0100195 int rc;
Simon Kelley69a815a2017-07-08 21:20:16 +0100196
Simon Kelley1f15b812009-10-13 17:49:32 +0100197 if (nomem)
198 *nomem = 0;
199
Simon Kelley69a815a2017-07-08 21:20:16 +0100200 if (!(rc = check_name(in)))
Simon Kelley1f15b812009-10-13 17:49:32 +0100201 return NULL;
202
Simon Kelley09ce3072017-09-25 16:53:55 +0100203#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
204 /* older libidn2 strips underscores, so don't do IDN processing
Simon Kelley69a815a2017-07-08 21:20:16 +0100205 if the name has an underscore (check_name() returned 2) */
206 if (rc != 2)
Simon Kelley09ce3072017-09-25 16:53:55 +0100207#endif
208#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
Simon Kelley1f15b812009-10-13 17:49:32 +0100209 {
Simon Kelley09ce3072017-09-25 16:53:55 +0100210# ifdef HAVE_LIBIDN2
Simon Kelley69a815a2017-07-08 21:20:16 +0100211 rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
212 if (rc == IDN2_DISALLOWED)
213 rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
Simon Kelley09ce3072017-09-25 16:53:55 +0100214# else
Simon Kelley69a815a2017-07-08 21:20:16 +0100215 rc = idna_to_ascii_lz(in, &ret, 0);
Simon Kelley09ce3072017-09-25 16:53:55 +0100216# endif
Simon Kelley69a815a2017-07-08 21:20:16 +0100217 if (rc != IDNA_SUCCESS)
218 {
219 if (ret)
220 free(ret);
221
222 if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
223 {
224 my_syslog(LOG_ERR, _("failed to allocate memory"));
225 *nomem = 1;
226 }
227
228 return NULL;
229 }
230
231 return ret;
232 }
233#endif
234
Simon Kelley1f15b812009-10-13 17:49:32 +0100235 if ((ret = whine_malloc(strlen(in)+1)))
236 strcpy(ret, in);
237 else if (nomem)
238 *nomem = 1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100239
240 return ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000241}
242
Simon Kelley0549c732017-09-25 18:17:11 +0100243unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
Simon Kelley3d8df262005-08-29 12:19:27 +0100244{
245 int j;
246
247 while (sval && *sval)
248 {
249 unsigned char *cp = p++;
Simon Kelleyc3667172017-10-13 23:26:29 +0100250
251 if (limit && p > (unsigned char*)limit)
252 return NULL;
253
Simon Kelley3d8df262005-08-29 12:19:27 +0100254 for (j = 0; *sval && (*sval != '.'); sval++, j++)
Simon Kelleycbe379a2015-04-21 22:57:06 +0100255 {
Simon Kelley0549c732017-09-25 18:17:11 +0100256 if (limit && p + 1 > (unsigned char*)limit)
Simon Kelleyc3667172017-10-13 23:26:29 +0100257 return NULL;
258
Simon Kelleycbe379a2015-04-21 22:57:06 +0100259#ifdef HAVE_DNSSEC
260 if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100261 *p++ = (*(++sval))-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100262 else
263#endif
264 *p++ = *sval;
265 }
Simon Kelleyc3667172017-10-13 23:26:29 +0100266
Simon Kelley3d8df262005-08-29 12:19:27 +0100267 *cp = j;
268 if (*sval)
269 sval++;
270 }
Simon Kelleyc3667172017-10-13 23:26:29 +0100271
Simon Kelley3d8df262005-08-29 12:19:27 +0100272 return p;
273}
274
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000275/* for use during startup */
Simon Kelley0a852542005-03-23 20:28:59 +0000276void *safe_malloc(size_t size)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000277{
Simon Kelleyd6dce532016-07-11 21:34:31 +0100278 void *ret = calloc(1, size);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000279
280 if (!ret)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100281 die(_("could not get memory"), NULL, EC_NOMEM);
Simon Kelleyd6dce532016-07-11 21:34:31 +0100282
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 return ret;
Petr Menšík47b45b22018-08-15 18:17:00 +0200284}
285
286/* Ensure limited size string is always terminated.
287 * Can be replaced by (void)strlcpy() on some platforms */
288void safe_strncpy(char *dest, const char *src, size_t size)
289{
Simon Kelleyd6820992018-09-04 23:00:11 +0100290 if (size != 0)
Petr Menšík47b45b22018-08-15 18:17:00 +0200291 {
292 dest[size-1] = '\0';
293 strncpy(dest, src, size-1);
294 }
295}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000296
Simon Kelley1a6bca82008-07-11 11:11:42 +0100297void safe_pipe(int *fd, int read_noblock)
298{
299 if (pipe(fd) == -1 ||
300 !fix_fd(fd[1]) ||
301 (read_noblock && !fix_fd(fd[0])))
302 die(_("cannot create pipe: %s"), NULL, EC_MISC);
303}
304
Simon Kelley5aabfc72007-08-29 11:24:47 +0100305void *whine_malloc(size_t size)
306{
Simon Kelleyd6dce532016-07-11 21:34:31 +0100307 void *ret = calloc(1, size);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308
309 if (!ret)
310 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
Simon Kelleyd55f81f2016-07-06 21:33:56 +0100311
Simon Kelley5aabfc72007-08-29 11:24:47 +0100312 return ret;
313}
314
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
316{
317 if (s1->sa.sa_family == s2->sa.sa_family)
318 {
319 if (s1->sa.sa_family == AF_INET &&
320 s1->in.sin_port == s2->in.sin_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100321 s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000322 return 1;
Simon Kelleyee875042018-10-23 22:10:17 +0100323
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000324 if (s1->sa.sa_family == AF_INET6 &&
325 s1->in6.sin6_port == s2->in6.sin6_port &&
Simon Kelley39341552015-01-18 22:11:10 +0000326 s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100327 IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000328 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000329 }
330 return 0;
331}
332
333int sa_len(union mysockaddr *addr)
334{
335#ifdef HAVE_SOCKADDR_SA_LEN
336 return addr->sa.sa_len;
337#else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338 if (addr->sa.sa_family == AF_INET6)
339 return sizeof(addr->in6);
340 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000341 return sizeof(addr->in);
342#endif
343}
344
345/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
Simon Kelleyc99df932012-10-12 13:39:04 +0100346int hostname_isequal(const char *a, const char *b)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000347{
348 unsigned int c1, c2;
349
350 do {
Simon Kelley3d8df262005-08-29 12:19:27 +0100351 c1 = (unsigned char) *a++;
352 c2 = (unsigned char) *b++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353
354 if (c1 >= 'A' && c1 <= 'Z')
355 c1 += 'a' - 'A';
356 if (c2 >= 'A' && c2 <= 'Z')
357 c2 += 'a' - 'A';
358
359 if (c1 != c2)
360 return 0;
361 } while (c1);
362
363 return 1;
364}
Simon Kelleyb637d782016-12-13 16:44:11 +0000365
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100366/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
367int hostname_issubdomain(char *a, char *b)
368{
369 char *ap, *bp;
370 unsigned int c1, c2;
371
372 /* move to the end */
373 for (ap = a; *ap; ap++);
374 for (bp = b; *bp; bp++);
375
376 /* a shorter than b or a empty. */
377 if ((bp - b) < (ap - a) || ap == a)
378 return 0;
379
380 do
381 {
382 c1 = (unsigned char) *(--ap);
383 c2 = (unsigned char) *(--bp);
384
385 if (c1 >= 'A' && c1 <= 'Z')
386 c1 += 'a' - 'A';
387 if (c2 >= 'A' && c2 <= 'Z')
388 c2 += 'a' - 'A';
389
390 if (c1 != c2)
391 return 0;
392 } while (ap != a);
393
394 if (bp == b)
395 return 2;
396
397 if (*(--bp) == '.')
398 return 1;
399
400 return 0;
401}
402
403
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100404time_t dnsmasq_time(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000405{
406#ifdef HAVE_BROKEN_RTC
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100407 struct tms dummy;
408 static long tps = 0;
409
410 if (tps == 0)
411 tps = sysconf(_SC_CLK_TCK);
412
413 return (time_t)(times(&dummy)/tps);
Simon Kelley44a2a312004-03-10 20:04:35 +0000414#else
Simon Kelley44a2a312004-03-10 20:04:35 +0000415 return time(NULL);
416#endif
417}
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100418
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800419int netmask_length(struct in_addr mask)
420{
421 int zero_count = 0;
422
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100423 while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
424 {
425 mask.s_addr >>= 1;
426 zero_count++;
427 }
428
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800429 return 32 - zero_count;
430}
431
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100432int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
433{
434 return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
435}
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100436
Simon Kelleyc72daea2012-01-05 21:33:27 +0000437int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
438{
439 int pfbytes = prefixlen >> 3;
440 int pfbits = prefixlen & 7;
441
442 if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
443 return 0;
444
445 if (pfbits == 0 ||
Simon Kelleyc64b7f62012-05-18 10:19:59 +0100446 (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000447 return 1;
448
449 return 0;
450}
451
Josh Soref730c6742017-02-06 16:14:04 +0000452/* return least significant 64 bits if IPv6 address */
Simon Kelley52b92f42012-01-22 16:05:15 +0000453u64 addr6part(struct in6_addr *addr)
454{
455 int i;
456 u64 ret = 0;
457
458 for (i = 8; i < 16; i++)
459 ret = (ret << 8) + addr->s6_addr[i];
460
461 return ret;
462}
463
464void setaddr6part(struct in6_addr *addr, u64 host)
465{
466 int i;
467
468 for (i = 15; i >= 8; i--)
469 {
470 addr->s6_addr[i] = host;
471 host = host >> 8;
472 }
473}
474
Simon Kelleyc72daea2012-01-05 21:33:27 +0000475
Simon Kelley3d8df262005-08-29 12:19:27 +0100476/* returns port number from address */
477int prettyprint_addr(union mysockaddr *addr, char *buf)
478{
479 int port = 0;
480
Simon Kelley3d8df262005-08-29 12:19:27 +0100481 if (addr->sa.sa_family == AF_INET)
482 {
483 inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
484 port = ntohs(addr->in.sin_port);
485 }
486 else if (addr->sa.sa_family == AF_INET6)
487 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100488 char name[IF_NAMESIZE];
Simon Kelley3d8df262005-08-29 12:19:27 +0100489 inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
Simon Kelley7de060b2011-08-26 17:24:52 +0100490 if (addr->in6.sin6_scope_id != 0 &&
491 if_indextoname(addr->in6.sin6_scope_id, name) &&
492 strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
493 {
494 strcat(buf, "%");
495 strcat(buf, name);
496 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100497 port = ntohs(addr->in6.sin6_port);
498 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100499
500 return port;
501}
502
Simon Kelley0a852542005-03-23 20:28:59 +0000503void prettyprint_time(char *buf, unsigned int t)
504{
505 if (t == 0xffffffff)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000506 sprintf(buf, _("infinite"));
Simon Kelley0a852542005-03-23 20:28:59 +0000507 else
508 {
509 unsigned int x, p = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100510 if ((x = t/86400))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100511 p += sprintf(&buf[p], "%ud", x);
Simon Kelley3d8df262005-08-29 12:19:27 +0100512 if ((x = (t/3600)%24))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100513 p += sprintf(&buf[p], "%uh", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000514 if ((x = (t/60)%60))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100515 p += sprintf(&buf[p], "%um", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000516 if ((x = t%60))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100517 p += sprintf(&buf[p], "%us", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000518 }
519}
520
521
Simon Kelley28866e92011-02-14 20:19:14 +0000522/* in may equal out, when maxlen may be -1 (No max len).
523 Return -1 for extraneous no-hex chars found. */
Simon Kelleycdeda282006-03-16 20:16:06 +0000524int parse_hex(char *in, unsigned char *out, int maxlen,
525 unsigned int *wildcard_mask, int *mac_type)
Simon Kelley0a852542005-03-23 20:28:59 +0000526{
527 int mask = 0, i = 0;
528 char *r;
Simon Kelleycdeda282006-03-16 20:16:06 +0000529
530 if (mac_type)
531 *mac_type = 0;
532
Simon Kelley0a852542005-03-23 20:28:59 +0000533 while (maxlen == -1 || i < maxlen)
534 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100535 for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000536 if (*r != '*' && !isxdigit((unsigned char)*r))
Simon Kelley28866e92011-02-14 20:19:14 +0000537 return -1;
538
Simon Kelley0a852542005-03-23 20:28:59 +0000539 if (*r == 0)
540 maxlen = i;
Simon Kelleycdeda282006-03-16 20:16:06 +0000541
Simon Kelley0a852542005-03-23 20:28:59 +0000542 if (r != in )
543 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000544 if (*r == '-' && i == 0 && mac_type)
545 {
546 *r = 0;
547 *mac_type = strtol(in, NULL, 16);
548 mac_type = NULL;
549 }
Simon Kelley0a852542005-03-23 20:28:59 +0000550 else
Simon Kelleycdeda282006-03-16 20:16:06 +0000551 {
552 *r = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000553 if (strcmp(in, "*") == 0)
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100554 {
555 mask = (mask << 1) | 1;
556 i++;
557 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000558 else
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100559 {
560 int j, bytes = (1 + (r - in))/2;
561 for (j = 0; j < bytes; j++)
562 {
Vladislav Grishenko50db3492013-11-26 11:09:31 +0000563 char sav = sav;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100564 if (j < bytes - 1)
565 {
566 sav = in[(j+1)*2];
567 in[(j+1)*2] = 0;
568 }
Simon Kelleyae3154a2017-01-01 22:59:46 +0000569 /* checks above allow mix of hexdigit and *, which
570 is illegal. */
571 if (strchr(&in[j*2], '*'))
572 return -1;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100573 out[i] = strtol(&in[j*2], NULL, 16);
574 mask = mask << 1;
Simon Kelley22827872017-05-08 21:39:04 +0100575 if (++i == maxlen)
Simon Kelley56144132017-05-03 22:54:09 +0100576 break;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100577 if (j < bytes - 1)
578 in[(j+1)*2] = sav;
579 }
580 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000581 }
Simon Kelley0a852542005-03-23 20:28:59 +0000582 }
583 in = r+1;
584 }
585
586 if (wildcard_mask)
587 *wildcard_mask = mask;
588
589 return i;
590}
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100591
Simon Kelley7622fc02009-06-04 20:32:05 +0100592/* return 0 for no match, or (no matched octets) + 1 */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100593int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
594{
Simon Kelley7622fc02009-06-04 20:32:05 +0100595 int i, count;
596 for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
597 if (!(mask & 1))
598 {
599 if (a[i] == b[i])
600 count++;
601 else
602 return 0;
603 }
604 return count;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100605}
606
607/* _note_ may copy buffer */
608int expand_buf(struct iovec *iov, size_t size)
609{
610 void *new;
611
Simon Kelley824af852008-02-12 20:43:05 +0000612 if (size <= (size_t)iov->iov_len)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100613 return 1;
614
Simon Kelley5aabfc72007-08-29 11:24:47 +0100615 if (!(new = whine_malloc(size)))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100616 {
617 errno = ENOMEM;
618 return 0;
619 }
620
621 if (iov->iov_base)
622 {
623 memcpy(new, iov->iov_base, iov->iov_len);
624 free(iov->iov_base);
625 }
626
627 iov->iov_base = new;
628 iov->iov_len = size;
629
630 return 1;
631}
Simon Kelley7cebd202006-05-06 14:13:33 +0100632
Simon Kelley5aabfc72007-08-29 11:24:47 +0100633char *print_mac(char *buff, unsigned char *mac, int len)
Simon Kelley7cebd202006-05-06 14:13:33 +0100634{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100635 char *p = buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100636 int i;
637
638 if (len == 0)
639 sprintf(p, "<null>");
640 else
641 for (i = 0; i < len; i++)
642 p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
643
Simon Kelley5aabfc72007-08-29 11:24:47 +0100644 return buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100645}
Simon Kelley16972692006-10-16 20:04:18 +0100646
Simon Kelleyff841eb2015-03-11 21:36:30 +0000647/* rc is return from sendto and friends.
648 Return 1 if we should retry.
649 Set errno to zero if we succeeded. */
650int retry_send(ssize_t rc)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100651{
Simon Kelleyff841eb2015-03-11 21:36:30 +0000652 static int retries = 0;
653 struct timespec waiter;
654
655 if (rc != -1)
656 {
657 retries = 0;
658 errno = 0;
659 return 0;
660 }
661
Simon Kelley57826492014-09-18 22:08:58 +0100662 /* Linux kernels can return EAGAIN in perpetuity when calling
663 sendmsg() and the relevant interface has gone. Here we loop
664 retrying in EAGAIN for 1 second max, to avoid this hanging
665 dnsmasq. */
666
Simon Kelleyff841eb2015-03-11 21:36:30 +0000667 if (errno == EAGAIN || errno == EWOULDBLOCK)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100668 {
669 waiter.tv_sec = 0;
670 waiter.tv_nsec = 10000;
671 nanosleep(&waiter, NULL);
Simon Kelley57826492014-09-18 22:08:58 +0100672 if (retries++ < 1000)
673 return 1;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100674 }
Simon Kelleyff841eb2015-03-11 21:36:30 +0000675
676 retries = 0;
677
678 if (errno == EINTR)
679 return 1;
680
681 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100682}
683
Simon Kelley16972692006-10-16 20:04:18 +0100684int read_write(int fd, unsigned char *packet, int size, int rw)
685{
686 ssize_t n, done;
687
688 for (done = 0; done < size; done += n)
689 {
Simon Kelleyff841eb2015-03-11 21:36:30 +0000690 do {
691 if (rw)
692 n = read(fd, &packet[done], (size_t)(size - done));
693 else
694 n = write(fd, &packet[done], (size_t)(size - done));
695
696 if (n == 0)
697 return 0;
698
699 } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
Simon Kelley16972692006-10-16 20:04:18 +0100700
Simon Kelleyff841eb2015-03-11 21:36:30 +0000701 if (errno != 0)
702 return 0;
Simon Kelley16972692006-10-16 20:04:18 +0100703 }
Simon Kelleyff841eb2015-03-11 21:36:30 +0000704
Simon Kelley16972692006-10-16 20:04:18 +0100705 return 1;
706}
Simon Kelley1a6bca82008-07-11 11:11:42 +0100707
Simon Kelley49333cb2013-03-15 20:30:51 +0000708/* Basically match a string value against a wildcard pattern. */
709int wildcard_match(const char* wildcard, const char* match)
710{
711 while (*wildcard && *match)
712 {
713 if (*wildcard == '*')
714 return 1;
715
716 if (*wildcard != *match)
717 return 0;
718
719 ++wildcard;
720 ++match;
721 }
722
723 return *wildcard == *match;
724}
Neil Jerram70772c92014-06-11 21:22:40 +0100725
726/* The same but comparing a maximum of NUM characters, like strncmp. */
727int wildcard_matchn(const char* wildcard, const char* match, int num)
728{
729 while (*wildcard && *match && num)
730 {
731 if (*wildcard == '*')
732 return 1;
733
734 if (*wildcard != *match)
735 return 0;
736
737 ++wildcard;
738 ++match;
739 --num;
740 }
741
742 return (!num) || (*wildcard == *match);
743}