blob: 972c60b7b17daf112e0ff20513f1332557dbfeca [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 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 Kelley0506a5e2020-03-19 21:56:45 +000033#ifdef HAVE_LINUX_NETWORK
34#include <sys/utsname.h>
35#endif
36
Simon Kelley1a6bca82008-07-11 11:11:42 +010037/* SURF random number generator */
38
Simon Kelley572b41e2011-02-18 18:11:18 +000039static u32 seed[32];
40static u32 in[12];
41static u32 out[8];
Simon Kelley6586e832013-11-07 14:20:13 +000042static int outleft = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010043
44void rand_init()
45{
46 int fd = open(RANDFILE, O_RDONLY);
47
48 if (fd == -1 ||
49 !read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
50 !read_write(fd, (unsigned char *)&in, sizeof(in), 1))
51 die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
52
53 close(fd);
54}
55
56#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
57#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
58
59static void surf(void)
60{
Simon Kelley572b41e2011-02-18 18:11:18 +000061 u32 t[12]; u32 x; u32 sum = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010062 int r; int i; int loop;
63
64 for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
65 for (i = 0;i < 8;++i) out[i] = seed[24 + i];
66 x = t[11];
67 for (loop = 0;loop < 2;++loop) {
68 for (r = 0;r < 16;++r) {
69 sum += 0x9e3779b9;
70 MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
71 MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
72 MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
73 }
74 for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
75 }
76}
77
78unsigned short rand16(void)
79{
Simon Kelley6586e832013-11-07 14:20:13 +000080 if (!outleft)
81 {
82 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
83 surf();
84 outleft = 8;
85 }
86
87 return (unsigned short) out[--outleft];
88}
89
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +010090u32 rand32(void)
91{
92 if (!outleft)
93 {
94 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
95 surf();
96 outleft = 8;
97 }
98
99 return out[--outleft];
100}
101
Simon Kelley6586e832013-11-07 14:20:13 +0000102u64 rand64(void)
103{
Simon Kelley1a6bca82008-07-11 11:11:42 +0100104 static int outleft = 0;
105
Simon Kelley6586e832013-11-07 14:20:13 +0000106 if (outleft < 2)
107 {
108 if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
109 surf();
110 outleft = 8;
111 }
112
113 outleft -= 2;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100114
Simon Kelley6586e832013-11-07 14:20:13 +0000115 return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100116}
117
Simon Kelley69a815a2017-07-08 21:20:16 +0100118/* returns 2 if names is OK but contains one or more underscores */
Simon Kelley1f15b812009-10-13 17:49:32 +0100119static int check_name(char *in)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120{
Simon Kelley1f15b812009-10-13 17:49:32 +0100121 /* remove trailing .
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000122 also fail empty string and label > 63 chars */
Simon Kelley1f15b812009-10-13 17:49:32 +0100123 size_t dotgap = 0, l = strlen(in);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000124 char c;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100125 int nowhite = 0;
Simon Kelley69a815a2017-07-08 21:20:16 +0100126 int hasuscore = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100127
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000128 if (l == 0 || l > MAXDNAME) return 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100129
130 if (in[l-1] == '.')
Simon Kelleya2226412004-05-13 20:27:08 +0100131 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100132 in[l-1] = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000133 nowhite = 1;
Simon Kelleya2226412004-05-13 20:27:08 +0100134 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000135
Simon Kelley1f15b812009-10-13 17:49:32 +0100136 for (; (c = *in); in++)
Simon Kelley3d8df262005-08-29 12:19:27 +0100137 {
138 if (c == '.')
139 dotgap = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +0100140 else if (++dotgap > MAXLABEL)
Simon Kelley3d8df262005-08-29 12:19:27 +0100141 return 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000142 else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100143 /* iscntrl only gives expected results for ascii */
144 return 0;
Simon Kelley43cdf1c2017-05-21 22:12:44 +0100145#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
Simon Kelley572b41e2011-02-18 18:11:18 +0000146 else if (!isascii((unsigned char)c))
Simon Kelley1f15b812009-10-13 17:49:32 +0100147 return 0;
148#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100149 else if (c != ' ')
Simon Kelley69a815a2017-07-08 21:20:16 +0100150 {
151 nowhite = 1;
152 if (c == '_')
153 hasuscore = 1;
154 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100155 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100156
157 if (!nowhite)
158 return 0;
159
Simon Kelley69a815a2017-07-08 21:20:16 +0100160 return hasuscore ? 2 : 1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100161}
162
163/* Hostnames have a more limited valid charset than domain names
164 so check for legal char a-z A-Z 0-9 - _
165 Note that this may receive a FQDN, so only check the first label
166 for the tighter criteria. */
167int legal_hostname(char *name)
168{
169 char c;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100170 int first;
Simon Kelley1f15b812009-10-13 17:49:32 +0100171
172 if (!check_name(name))
173 return 0;
174
Simon Kelley7abb69b2013-04-29 10:52:16 +0100175 for (first = 1; (c = *name); name++, first = 0)
Simon Kelley1f15b812009-10-13 17:49:32 +0100176 /* check for legal char a-z A-Z 0-9 - _ . */
177 {
178 if ((c >= 'A' && c <= 'Z') ||
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100179 (c >= 'a' && c <= 'z') ||
180 (c >= '0' && c <= '9'))
Simon Kelley1f15b812009-10-13 17:49:32 +0100181 continue;
Simon Kelley7abb69b2013-04-29 10:52:16 +0100182
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100183 if (!first && (c == '-' || c == '_'))
Simon Kelley7abb69b2013-04-29 10:52:16 +0100184 continue;
Kyle Mesteryd859ca22013-07-24 13:11:58 +0100185
Simon Kelley1f15b812009-10-13 17:49:32 +0100186 /* end of hostname part */
187 if (c == '.')
188 return 1;
189
190 return 0;
191 }
192
193 return 1;
194}
195
196char *canonicalise(char *in, int *nomem)
197{
198 char *ret = NULL;
Simon Kelley1f15b812009-10-13 17:49:32 +0100199 int rc;
Simon Kelley69a815a2017-07-08 21:20:16 +0100200
Simon Kelley1f15b812009-10-13 17:49:32 +0100201 if (nomem)
202 *nomem = 0;
203
Simon Kelley69a815a2017-07-08 21:20:16 +0100204 if (!(rc = check_name(in)))
Simon Kelley1f15b812009-10-13 17:49:32 +0100205 return NULL;
206
Simon Kelley09ce3072017-09-25 16:53:55 +0100207#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
208 /* older libidn2 strips underscores, so don't do IDN processing
Simon Kelley69a815a2017-07-08 21:20:16 +0100209 if the name has an underscore (check_name() returned 2) */
210 if (rc != 2)
Simon Kelley09ce3072017-09-25 16:53:55 +0100211#endif
212#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
Simon Kelley1f15b812009-10-13 17:49:32 +0100213 {
Simon Kelley09ce3072017-09-25 16:53:55 +0100214# ifdef HAVE_LIBIDN2
Simon Kelley69a815a2017-07-08 21:20:16 +0100215 rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
216 if (rc == IDN2_DISALLOWED)
217 rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
Simon Kelley09ce3072017-09-25 16:53:55 +0100218# else
Simon Kelley69a815a2017-07-08 21:20:16 +0100219 rc = idna_to_ascii_lz(in, &ret, 0);
Simon Kelley09ce3072017-09-25 16:53:55 +0100220# endif
Simon Kelley69a815a2017-07-08 21:20:16 +0100221 if (rc != IDNA_SUCCESS)
222 {
223 if (ret)
224 free(ret);
225
226 if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
227 {
228 my_syslog(LOG_ERR, _("failed to allocate memory"));
229 *nomem = 1;
230 }
231
232 return NULL;
233 }
234
235 return ret;
236 }
237#endif
238
Simon Kelley1f15b812009-10-13 17:49:32 +0100239 if ((ret = whine_malloc(strlen(in)+1)))
240 strcpy(ret, in);
241 else if (nomem)
242 *nomem = 1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100243
244 return ret;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000245}
246
Simon Kelley0549c732017-09-25 18:17:11 +0100247unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
Simon Kelley3d8df262005-08-29 12:19:27 +0100248{
249 int j;
250
251 while (sval && *sval)
252 {
253 unsigned char *cp = p++;
Simon Kelleyc3667172017-10-13 23:26:29 +0100254
255 if (limit && p > (unsigned char*)limit)
256 return NULL;
257
Simon Kelley3d8df262005-08-29 12:19:27 +0100258 for (j = 0; *sval && (*sval != '.'); sval++, j++)
Simon Kelleycbe379a2015-04-21 22:57:06 +0100259 {
Simon Kelley0549c732017-09-25 18:17:11 +0100260 if (limit && p + 1 > (unsigned char*)limit)
Simon Kelleyc3667172017-10-13 23:26:29 +0100261 return NULL;
262
Simon Kelleycbe379a2015-04-21 22:57:06 +0100263#ifdef HAVE_DNSSEC
264 if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100265 *p++ = (*(++sval))-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100266 else
267#endif
268 *p++ = *sval;
269 }
Simon Kelleyc3667172017-10-13 23:26:29 +0100270
Simon Kelley3d8df262005-08-29 12:19:27 +0100271 *cp = j;
272 if (*sval)
273 sval++;
274 }
Simon Kelleyc3667172017-10-13 23:26:29 +0100275
Simon Kelley3d8df262005-08-29 12:19:27 +0100276 return p;
277}
278
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000279/* for use during startup */
Simon Kelley0a852542005-03-23 20:28:59 +0000280void *safe_malloc(size_t size)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000281{
Simon Kelleyd6dce532016-07-11 21:34:31 +0100282 void *ret = calloc(1, size);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283
284 if (!ret)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100285 die(_("could not get memory"), NULL, EC_NOMEM);
Simon Kelleyd6dce532016-07-11 21:34:31 +0100286
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000287 return ret;
Petr Menšík47b45b22018-08-15 18:17:00 +0200288}
289
290/* Ensure limited size string is always terminated.
291 * Can be replaced by (void)strlcpy() on some platforms */
292void safe_strncpy(char *dest, const char *src, size_t size)
293{
Simon Kelleyd6820992018-09-04 23:00:11 +0100294 if (size != 0)
Petr Menšík47b45b22018-08-15 18:17:00 +0200295 {
296 dest[size-1] = '\0';
297 strncpy(dest, src, size-1);
298 }
299}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000300
Simon Kelley1a6bca82008-07-11 11:11:42 +0100301void safe_pipe(int *fd, int read_noblock)
302{
303 if (pipe(fd) == -1 ||
304 !fix_fd(fd[1]) ||
305 (read_noblock && !fix_fd(fd[0])))
306 die(_("cannot create pipe: %s"), NULL, EC_MISC);
307}
308
Simon Kelley5aabfc72007-08-29 11:24:47 +0100309void *whine_malloc(size_t size)
310{
Simon Kelleyd6dce532016-07-11 21:34:31 +0100311 void *ret = calloc(1, size);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100312
313 if (!ret)
314 my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
Simon Kelleyd55f81f2016-07-06 21:33:56 +0100315
Simon Kelley5aabfc72007-08-29 11:24:47 +0100316 return ret;
317}
318
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000319int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
320{
321 if (s1->sa.sa_family == s2->sa.sa_family)
322 {
323 if (s1->sa.sa_family == AF_INET &&
324 s1->in.sin_port == s2->in.sin_port &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100325 s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326 return 1;
Simon Kelleyee875042018-10-23 22:10:17 +0100327
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000328 if (s1->sa.sa_family == AF_INET6 &&
329 s1->in6.sin6_port == s2->in6.sin6_port &&
Simon Kelley39341552015-01-18 22:11:10 +0000330 s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100331 IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000333 }
334 return 0;
335}
336
337int sa_len(union mysockaddr *addr)
338{
339#ifdef HAVE_SOCKADDR_SA_LEN
340 return addr->sa.sa_len;
341#else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342 if (addr->sa.sa_family == AF_INET6)
343 return sizeof(addr->in6);
344 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000345 return sizeof(addr->in);
346#endif
347}
348
349/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
Simon Kelleyc99df932012-10-12 13:39:04 +0100350int hostname_isequal(const char *a, const char *b)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000351{
352 unsigned int c1, c2;
353
354 do {
Simon Kelley3d8df262005-08-29 12:19:27 +0100355 c1 = (unsigned char) *a++;
356 c2 = (unsigned char) *b++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000357
358 if (c1 >= 'A' && c1 <= 'Z')
359 c1 += 'a' - 'A';
360 if (c2 >= 'A' && c2 <= 'Z')
361 c2 += 'a' - 'A';
362
363 if (c1 != c2)
364 return 0;
365 } while (c1);
366
367 return 1;
368}
Simon Kelleyb637d782016-12-13 16:44:11 +0000369
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100370/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
371int hostname_issubdomain(char *a, char *b)
372{
373 char *ap, *bp;
374 unsigned int c1, c2;
375
376 /* move to the end */
377 for (ap = a; *ap; ap++);
378 for (bp = b; *bp; bp++);
379
380 /* a shorter than b or a empty. */
381 if ((bp - b) < (ap - a) || ap == a)
382 return 0;
383
384 do
385 {
386 c1 = (unsigned char) *(--ap);
387 c2 = (unsigned char) *(--bp);
388
389 if (c1 >= 'A' && c1 <= 'Z')
390 c1 += 'a' - 'A';
391 if (c2 >= 'A' && c2 <= 'Z')
392 c2 += 'a' - 'A';
393
394 if (c1 != c2)
395 return 0;
396 } while (ap != a);
397
398 if (bp == b)
399 return 2;
400
401 if (*(--bp) == '.')
402 return 1;
403
404 return 0;
405}
406
407
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100408time_t dnsmasq_time(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000409{
410#ifdef HAVE_BROKEN_RTC
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100411 struct tms dummy;
412 static long tps = 0;
413
414 if (tps == 0)
415 tps = sysconf(_SC_CLK_TCK);
416
417 return (time_t)(times(&dummy)/tps);
Simon Kelley44a2a312004-03-10 20:04:35 +0000418#else
Simon Kelley44a2a312004-03-10 20:04:35 +0000419 return time(NULL);
420#endif
421}
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100422
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800423int netmask_length(struct in_addr mask)
424{
425 int zero_count = 0;
426
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100427 while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
428 {
429 mask.s_addr >>= 1;
430 zero_count++;
431 }
432
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800433 return 32 - zero_count;
434}
435
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100436int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
437{
438 return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
439}
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100440
Simon Kelleyc72daea2012-01-05 21:33:27 +0000441int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
442{
443 int pfbytes = prefixlen >> 3;
444 int pfbits = prefixlen & 7;
445
446 if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
447 return 0;
448
449 if (pfbits == 0 ||
Simon Kelleyc64b7f62012-05-18 10:19:59 +0100450 (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000451 return 1;
452
453 return 0;
454}
455
Josh Soref730c6742017-02-06 16:14:04 +0000456/* return least significant 64 bits if IPv6 address */
Simon Kelley52b92f42012-01-22 16:05:15 +0000457u64 addr6part(struct in6_addr *addr)
458{
459 int i;
460 u64 ret = 0;
461
462 for (i = 8; i < 16; i++)
463 ret = (ret << 8) + addr->s6_addr[i];
464
465 return ret;
466}
467
468void setaddr6part(struct in6_addr *addr, u64 host)
469{
470 int i;
471
472 for (i = 15; i >= 8; i--)
473 {
474 addr->s6_addr[i] = host;
475 host = host >> 8;
476 }
477}
478
Simon Kelleyc72daea2012-01-05 21:33:27 +0000479
Simon Kelley3d8df262005-08-29 12:19:27 +0100480/* returns port number from address */
481int prettyprint_addr(union mysockaddr *addr, char *buf)
482{
483 int port = 0;
484
Simon Kelley3d8df262005-08-29 12:19:27 +0100485 if (addr->sa.sa_family == AF_INET)
486 {
487 inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
488 port = ntohs(addr->in.sin_port);
489 }
490 else if (addr->sa.sa_family == AF_INET6)
491 {
Simon Kelley7de060b2011-08-26 17:24:52 +0100492 char name[IF_NAMESIZE];
Simon Kelley3d8df262005-08-29 12:19:27 +0100493 inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
Simon Kelley7de060b2011-08-26 17:24:52 +0100494 if (addr->in6.sin6_scope_id != 0 &&
495 if_indextoname(addr->in6.sin6_scope_id, name) &&
496 strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
497 {
498 strcat(buf, "%");
499 strcat(buf, name);
500 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100501 port = ntohs(addr->in6.sin6_port);
502 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100503
504 return port;
505}
506
Simon Kelley0a852542005-03-23 20:28:59 +0000507void prettyprint_time(char *buf, unsigned int t)
508{
509 if (t == 0xffffffff)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000510 sprintf(buf, _("infinite"));
Simon Kelley0a852542005-03-23 20:28:59 +0000511 else
512 {
513 unsigned int x, p = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100514 if ((x = t/86400))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100515 p += sprintf(&buf[p], "%ud", x);
Simon Kelley3d8df262005-08-29 12:19:27 +0100516 if ((x = (t/3600)%24))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100517 p += sprintf(&buf[p], "%uh", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000518 if ((x = (t/60)%60))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100519 p += sprintf(&buf[p], "%um", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000520 if ((x = t%60))
Rosen Penevcbd29e52017-06-27 22:29:51 +0100521 p += sprintf(&buf[p], "%us", x);
Simon Kelley0a852542005-03-23 20:28:59 +0000522 }
523}
524
525
Simon Kelley28866e92011-02-14 20:19:14 +0000526/* in may equal out, when maxlen may be -1 (No max len).
527 Return -1 for extraneous no-hex chars found. */
Simon Kelleycdeda282006-03-16 20:16:06 +0000528int parse_hex(char *in, unsigned char *out, int maxlen,
529 unsigned int *wildcard_mask, int *mac_type)
Simon Kelley0a852542005-03-23 20:28:59 +0000530{
Simon Kelley7d04e172019-12-12 16:44:22 +0000531 int done = 0, mask = 0, i = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000532 char *r;
Simon Kelleycdeda282006-03-16 20:16:06 +0000533
534 if (mac_type)
535 *mac_type = 0;
536
Simon Kelley7d04e172019-12-12 16:44:22 +0000537 while (!done && (maxlen == -1 || i < maxlen))
Simon Kelley0a852542005-03-23 20:28:59 +0000538 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100539 for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000540 if (*r != '*' && !isxdigit((unsigned char)*r))
Simon Kelley28866e92011-02-14 20:19:14 +0000541 return -1;
542
Simon Kelley0a852542005-03-23 20:28:59 +0000543 if (*r == 0)
Simon Kelley7d04e172019-12-12 16:44:22 +0000544 done = 1;
Simon Kelleycdeda282006-03-16 20:16:06 +0000545
Simon Kelley0a852542005-03-23 20:28:59 +0000546 if (r != in )
547 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000548 if (*r == '-' && i == 0 && mac_type)
549 {
550 *r = 0;
551 *mac_type = strtol(in, NULL, 16);
552 mac_type = NULL;
553 }
Simon Kelley0a852542005-03-23 20:28:59 +0000554 else
Simon Kelleycdeda282006-03-16 20:16:06 +0000555 {
556 *r = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000557 if (strcmp(in, "*") == 0)
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100558 {
559 mask = (mask << 1) | 1;
560 i++;
561 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000562 else
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100563 {
564 int j, bytes = (1 + (r - in))/2;
565 for (j = 0; j < bytes; j++)
566 {
Vladislav Grishenko50db3492013-11-26 11:09:31 +0000567 char sav = sav;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100568 if (j < bytes - 1)
569 {
570 sav = in[(j+1)*2];
571 in[(j+1)*2] = 0;
572 }
Simon Kelleyae3154a2017-01-01 22:59:46 +0000573 /* checks above allow mix of hexdigit and *, which
574 is illegal. */
575 if (strchr(&in[j*2], '*'))
576 return -1;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100577 out[i] = strtol(&in[j*2], NULL, 16);
578 mask = mask << 1;
Simon Kelley22827872017-05-08 21:39:04 +0100579 if (++i == maxlen)
Simon Kelley56144132017-05-03 22:54:09 +0100580 break;
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100581 if (j < bytes - 1)
582 in[(j+1)*2] = sav;
583 }
584 }
Simon Kelleycdeda282006-03-16 20:16:06 +0000585 }
Simon Kelley0a852542005-03-23 20:28:59 +0000586 }
587 in = r+1;
588 }
589
590 if (wildcard_mask)
591 *wildcard_mask = mask;
592
593 return i;
594}
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100595
Simon Kelley7622fc02009-06-04 20:32:05 +0100596/* return 0 for no match, or (no matched octets) + 1 */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100597int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
598{
Simon Kelley7622fc02009-06-04 20:32:05 +0100599 int i, count;
600 for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
601 if (!(mask & 1))
602 {
603 if (a[i] == b[i])
604 count++;
605 else
606 return 0;
607 }
608 return count;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100609}
610
611/* _note_ may copy buffer */
612int expand_buf(struct iovec *iov, size_t size)
613{
614 void *new;
615
Simon Kelley824af852008-02-12 20:43:05 +0000616 if (size <= (size_t)iov->iov_len)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100617 return 1;
618
Simon Kelley5aabfc72007-08-29 11:24:47 +0100619 if (!(new = whine_malloc(size)))
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100620 {
621 errno = ENOMEM;
622 return 0;
623 }
624
625 if (iov->iov_base)
626 {
627 memcpy(new, iov->iov_base, iov->iov_len);
628 free(iov->iov_base);
629 }
630
631 iov->iov_base = new;
632 iov->iov_len = size;
633
634 return 1;
635}
Simon Kelley7cebd202006-05-06 14:13:33 +0100636
Simon Kelley5aabfc72007-08-29 11:24:47 +0100637char *print_mac(char *buff, unsigned char *mac, int len)
Simon Kelley7cebd202006-05-06 14:13:33 +0100638{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100639 char *p = buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100640 int i;
641
642 if (len == 0)
643 sprintf(p, "<null>");
644 else
645 for (i = 0; i < len; i++)
646 p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
647
Simon Kelley5aabfc72007-08-29 11:24:47 +0100648 return buff;
Simon Kelley7cebd202006-05-06 14:13:33 +0100649}
Simon Kelley16972692006-10-16 20:04:18 +0100650
Simon Kelleyff841eb2015-03-11 21:36:30 +0000651/* rc is return from sendto and friends.
652 Return 1 if we should retry.
653 Set errno to zero if we succeeded. */
654int retry_send(ssize_t rc)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100655{
Simon Kelleyff841eb2015-03-11 21:36:30 +0000656 static int retries = 0;
657 struct timespec waiter;
658
659 if (rc != -1)
660 {
661 retries = 0;
662 errno = 0;
663 return 0;
664 }
665
Simon Kelley57826492014-09-18 22:08:58 +0100666 /* Linux kernels can return EAGAIN in perpetuity when calling
667 sendmsg() and the relevant interface has gone. Here we loop
668 retrying in EAGAIN for 1 second max, to avoid this hanging
669 dnsmasq. */
670
Simon Kelleyff841eb2015-03-11 21:36:30 +0000671 if (errno == EAGAIN || errno == EWOULDBLOCK)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100672 {
673 waiter.tv_sec = 0;
674 waiter.tv_nsec = 10000;
675 nanosleep(&waiter, NULL);
Simon Kelley57826492014-09-18 22:08:58 +0100676 if (retries++ < 1000)
677 return 1;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100678 }
Simon Kelleyff841eb2015-03-11 21:36:30 +0000679
680 retries = 0;
681
682 if (errno == EINTR)
683 return 1;
684
685 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100686}
687
Simon Kelley16972692006-10-16 20:04:18 +0100688int read_write(int fd, unsigned char *packet, int size, int rw)
689{
690 ssize_t n, done;
691
692 for (done = 0; done < size; done += n)
693 {
Simon Kelleyff841eb2015-03-11 21:36:30 +0000694 do {
695 if (rw)
696 n = read(fd, &packet[done], (size_t)(size - done));
697 else
698 n = write(fd, &packet[done], (size_t)(size - done));
699
700 if (n == 0)
701 return 0;
702
703 } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
Simon Kelley16972692006-10-16 20:04:18 +0100704
Simon Kelleyff841eb2015-03-11 21:36:30 +0000705 if (errno != 0)
706 return 0;
Simon Kelley16972692006-10-16 20:04:18 +0100707 }
Simon Kelleyff841eb2015-03-11 21:36:30 +0000708
Simon Kelley16972692006-10-16 20:04:18 +0100709 return 1;
710}
Simon Kelley1a6bca82008-07-11 11:11:42 +0100711
Simon Kelley0541a1a2020-03-02 17:10:25 +0000712/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
713void close_fds(long max_fd, int spare1, int spare2, int spare3)
714{
Simon Kelley48755eb2020-03-02 17:42:51 +0000715 /* On Linux, use the /proc/ filesystem to find which files
716 are actually open, rather than iterate over the whole space,
717 for efficiency reasons. If this fails we drop back to the dumb code. */
718#ifdef HAVE_LINUX_NETWORK
719 DIR *d;
720
721 if ((d = opendir("/proc/self/fd")))
722 {
723 struct dirent *de;
724
725 while ((de = readdir(d)))
726 {
727 long fd;
728 char *e = NULL;
729
730 errno = 0;
731 fd = strtol(de->d_name, &e, 10);
732
733 if (errno != 0 || !e || *e || fd == dirfd(d) ||
734 fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
735 fd == spare1 || fd == spare2 || fd == spare3)
736 continue;
737
Simon Kelley02df0002020-03-02 22:30:28 +0000738 close(fd);
Simon Kelley48755eb2020-03-02 17:42:51 +0000739 }
740
741 closedir(d);
742 return;
743 }
744#endif
745
746 /* fallback, dumb code. */
Simon Kelley0541a1a2020-03-02 17:10:25 +0000747 for (max_fd--; max_fd >= 0; max_fd--)
748 if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
749 max_fd != spare1 && max_fd != spare2 && max_fd != spare3)
750 close(max_fd);
751}
752
Simon Kelley49333cb2013-03-15 20:30:51 +0000753/* Basically match a string value against a wildcard pattern. */
754int wildcard_match(const char* wildcard, const char* match)
755{
756 while (*wildcard && *match)
757 {
758 if (*wildcard == '*')
759 return 1;
760
761 if (*wildcard != *match)
762 return 0;
763
764 ++wildcard;
765 ++match;
766 }
767
768 return *wildcard == *match;
769}
Neil Jerram70772c92014-06-11 21:22:40 +0100770
771/* The same but comparing a maximum of NUM characters, like strncmp. */
772int wildcard_matchn(const char* wildcard, const char* match, int num)
773{
774 while (*wildcard && *match && num)
775 {
776 if (*wildcard == '*')
777 return 1;
778
779 if (*wildcard != *match)
780 return 0;
781
782 ++wildcard;
783 ++match;
784 --num;
785 }
786
787 return (!num) || (*wildcard == *match);
788}
Simon Kelley0506a5e2020-03-19 21:56:45 +0000789
790#ifdef HAVE_LINUX_NETWORK
791int kernel_version(void)
792{
793 struct utsname utsname;
794 int version;
795 char *split;
796
797 if (uname(&utsname) < 0)
798 die(_("failed to find kernel version: %s"), NULL, EC_MISC);
799
800 split = strtok(utsname.release, ".");
801 version = (split ? atoi(split) : 0);
802 split = strtok(NULL, ".");
803 version = version * 256 + (split ? atoi(split) : 0);
804 split = strtok(NULL, ".");
805 return version * 256 + (split ? atoi(split) : 0);
806}
807#endif