Annotation of embedaddon/dnsmasq/src/util.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 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, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: 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.
12:
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/>.
15: */
16:
17: /* The SURF random number generator was taken from djbdns-1.05, by
18: Daniel J Bernstein, which is public domain. */
19:
20:
21: #include "dnsmasq.h"
22:
23: #ifdef HAVE_BROKEN_RTC
24: #include <sys/times.h>
25: #endif
26:
1.1.1.4 misho 27: #if defined(HAVE_LIBIDN2)
28: #include <idn2.h>
29: #elif defined(HAVE_IDN)
1.1 misho 30: #include <idna.h>
31: #endif
32:
1.1.1.4 misho 33: #ifdef HAVE_LINUX_NETWORK
34: #include <sys/utsname.h>
35: #endif
36:
1.1 misho 37: /* SURF random number generator */
38:
39: static u32 seed[32];
40: static u32 in[12];
41: static u32 out[8];
1.1.1.2 misho 42: static int outleft = 0;
1.1 misho 43:
44: void 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:
59: static void surf(void)
60: {
61: u32 t[12]; u32 x; u32 sum = 0;
62: 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:
78: unsigned short rand16(void)
79: {
1.1.1.2 misho 80: 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:
1.1.1.3 misho 90: u32 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:
1.1.1.2 misho 102: u64 rand64(void)
103: {
1.1 misho 104: static int outleft = 0;
105:
1.1.1.2 misho 106: 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;
1.1 misho 114:
1.1.1.2 misho 115: return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
1.1 misho 116: }
117:
1.1.1.5 ! misho 118: /* returns 1 if name is OK and ascii printable
! 119: * returns 2 if name should be processed by IDN */
1.1 misho 120: static int check_name(char *in)
121: {
122: /* remove trailing .
123: also fail empty string and label > 63 chars */
124: size_t dotgap = 0, l = strlen(in);
125: char c;
126: int nowhite = 0;
1.1.1.5 ! misho 127: int idn_encode = 0;
1.1.1.4 misho 128: int hasuscore = 0;
1.1.1.5 ! misho 129: int hasucase = 0;
1.1 misho 130:
131: if (l == 0 || l > MAXDNAME) return 0;
132:
133: if (in[l-1] == '.')
134: {
135: in[l-1] = 0;
1.1.1.2 misho 136: nowhite = 1;
1.1 misho 137: }
1.1.1.2 misho 138:
1.1 misho 139: for (; (c = *in); in++)
140: {
141: if (c == '.')
1.1.1.5 ! misho 142: dotgap = 0;
1.1 misho 143: else if (++dotgap > MAXLABEL)
1.1.1.5 ! misho 144: return 0;
1.1 misho 145: else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
1.1.1.5 ! misho 146: /* iscntrl only gives expected results for ascii */
! 147: return 0;
1.1 misho 148: else if (!isascii((unsigned char)c))
1.1.1.5 ! misho 149: #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
! 150: return 0;
! 151: #else
! 152: idn_encode = 1;
1.1 misho 153: #endif
154: else if (c != ' ')
1.1.1.5 ! misho 155: {
! 156: nowhite = 1;
! 157: #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
! 158: if (c == '_')
! 159: hasuscore = 1;
! 160: #else
! 161: (void)hasuscore;
! 162: #endif
! 163:
! 164: #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
! 165: if (c >= 'A' && c <= 'Z')
! 166: hasucase = 1;
! 167: #else
! 168: (void)hasucase;
! 169: #endif
! 170: }
1.1 misho 171: }
172:
173: if (!nowhite)
174: return 0;
175:
1.1.1.5 ! misho 176: #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
! 177: /* Older libidn2 strips underscores, so don't do IDN processing
! 178: if the name has an underscore unless it also has non-ascii characters. */
! 179: idn_encode = idn_encode || (hasucase && !hasuscore);
! 180: #else
! 181: idn_encode = idn_encode || hasucase;
! 182: #endif
! 183:
! 184: return (idn_encode) ? 2 : 1;
1.1 misho 185: }
186:
187: /* Hostnames have a more limited valid charset than domain names
188: so check for legal char a-z A-Z 0-9 - _
189: Note that this may receive a FQDN, so only check the first label
190: for the tighter criteria. */
191: int legal_hostname(char *name)
192: {
193: char c;
1.1.1.2 misho 194: int first;
1.1 misho 195:
196: if (!check_name(name))
197: return 0;
198:
1.1.1.2 misho 199: for (first = 1; (c = *name); name++, first = 0)
1.1 misho 200: /* check for legal char a-z A-Z 0-9 - _ . */
201: {
202: if ((c >= 'A' && c <= 'Z') ||
203: (c >= 'a' && c <= 'z') ||
1.1.1.2 misho 204: (c >= '0' && c <= '9'))
205: continue;
206:
207: if (!first && (c == '-' || c == '_'))
1.1 misho 208: continue;
209:
210: /* end of hostname part */
211: if (c == '.')
212: return 1;
213:
214: return 0;
215: }
216:
217: return 1;
218: }
219:
220: char *canonicalise(char *in, int *nomem)
221: {
222: char *ret = NULL;
223: int rc;
1.1.1.4 misho 224:
1.1 misho 225: if (nomem)
226: *nomem = 0;
227:
1.1.1.4 misho 228: if (!(rc = check_name(in)))
1.1 misho 229: return NULL;
230:
1.1.1.4 misho 231: #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
1.1.1.5 ! misho 232: if (rc == 2)
1.1.1.4 misho 233: {
234: # ifdef HAVE_LIBIDN2
235: rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
236: # else
237: rc = idna_to_ascii_lz(in, &ret, 0);
238: # endif
239: if (rc != IDNA_SUCCESS)
1.1 misho 240: {
1.1.1.4 misho 241: if (ret)
242: free(ret);
243:
244: if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
245: {
246: my_syslog(LOG_ERR, _("failed to allocate memory"));
247: *nomem = 1;
248: }
249:
250: return NULL;
1.1 misho 251: }
1.1.1.4 misho 252:
253: return ret;
1.1 misho 254: }
1.1.1.5 ! misho 255: #else
! 256: (void)rc;
1.1.1.4 misho 257: #endif
258:
1.1 misho 259: if ((ret = whine_malloc(strlen(in)+1)))
260: strcpy(ret, in);
261: else if (nomem)
1.1.1.5 ! misho 262: *nomem = 1;
1.1 misho 263:
264: return ret;
265: }
266:
1.1.1.4 misho 267: unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
1.1 misho 268: {
269: int j;
270:
271: while (sval && *sval)
272: {
273: unsigned char *cp = p++;
1.1.1.4 misho 274:
275: if (limit && p > (unsigned char*)limit)
276: return NULL;
277:
1.1 misho 278: for (j = 0; *sval && (*sval != '.'); sval++, j++)
1.1.1.3 misho 279: {
1.1.1.4 misho 280: if (limit && p + 1 > (unsigned char*)limit)
281: return NULL;
282:
1.1.1.3 misho 283: #ifdef HAVE_DNSSEC
284: if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
285: *p++ = (*(++sval))-1;
286: else
287: #endif
288: *p++ = *sval;
289: }
1.1.1.4 misho 290:
1.1 misho 291: *cp = j;
292: if (*sval)
293: sval++;
294: }
1.1.1.4 misho 295:
1.1 misho 296: return p;
297: }
298:
299: /* for use during startup */
300: void *safe_malloc(size_t size)
301: {
1.1.1.4 misho 302: void *ret = calloc(1, size);
1.1 misho 303:
304: if (!ret)
305: die(_("could not get memory"), NULL, EC_NOMEM);
1.1.1.4 misho 306:
1.1 misho 307: return ret;
1.1.1.4 misho 308: }
309:
310: /* Ensure limited size string is always terminated.
311: * Can be replaced by (void)strlcpy() on some platforms */
312: void safe_strncpy(char *dest, const char *src, size_t size)
313: {
314: if (size != 0)
315: {
316: dest[size-1] = '\0';
317: strncpy(dest, src, size-1);
318: }
319: }
1.1 misho 320:
321: void safe_pipe(int *fd, int read_noblock)
322: {
323: if (pipe(fd) == -1 ||
324: !fix_fd(fd[1]) ||
325: (read_noblock && !fix_fd(fd[0])))
326: die(_("cannot create pipe: %s"), NULL, EC_MISC);
327: }
328:
329: void *whine_malloc(size_t size)
330: {
1.1.1.4 misho 331: void *ret = calloc(1, size);
1.1 misho 332:
333: if (!ret)
334: my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
1.1.1.4 misho 335:
1.1 misho 336: return ret;
337: }
338:
1.1.1.5 ! misho 339: void *whine_realloc(void *ptr, size_t size)
! 340: {
! 341: void *ret = realloc(ptr, size);
! 342:
! 343: if (!ret)
! 344: my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
! 345:
! 346: return ret;
! 347: }
! 348:
! 349: int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
1.1 misho 350: {
351: if (s1->sa.sa_family == s2->sa.sa_family)
352: {
353: if (s1->sa.sa_family == AF_INET &&
354: s1->in.sin_port == s2->in.sin_port &&
355: s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
356: return 1;
1.1.1.4 misho 357:
1.1 misho 358: if (s1->sa.sa_family == AF_INET6 &&
359: s1->in6.sin6_port == s2->in6.sin6_port &&
1.1.1.3 misho 360: s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
1.1 misho 361: IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
362: return 1;
363: }
364: return 0;
365: }
366:
1.1.1.5 ! misho 367: int sockaddr_isnull(const union mysockaddr *s)
! 368: {
! 369: if (s->sa.sa_family == AF_INET &&
! 370: s->in.sin_addr.s_addr == 0)
! 371: return 1;
! 372:
! 373: if (s->sa.sa_family == AF_INET6 &&
! 374: IN6_IS_ADDR_UNSPECIFIED(&s->in6.sin6_addr))
! 375: return 1;
! 376:
! 377: return 0;
! 378: }
! 379:
1.1 misho 380: int sa_len(union mysockaddr *addr)
381: {
382: #ifdef HAVE_SOCKADDR_SA_LEN
383: return addr->sa.sa_len;
384: #else
385: if (addr->sa.sa_family == AF_INET6)
386: return sizeof(addr->in6);
387: else
388: return sizeof(addr->in);
389: #endif
390: }
391:
392: /* don't use strcasecmp and friends here - they may be messed up by LOCALE */
1.1.1.5 ! misho 393: int hostname_order(const char *a, const char *b)
1.1 misho 394: {
395: unsigned int c1, c2;
396:
397: do {
398: c1 = (unsigned char) *a++;
399: c2 = (unsigned char) *b++;
400:
401: if (c1 >= 'A' && c1 <= 'Z')
402: c1 += 'a' - 'A';
403: if (c2 >= 'A' && c2 <= 'Z')
404: c2 += 'a' - 'A';
405:
1.1.1.5 ! misho 406: if (c1 < c2)
! 407: return -1;
! 408: else if (c1 > c2)
! 409: return 1;
! 410:
1.1 misho 411: } while (c1);
412:
1.1.1.5 ! misho 413: return 0;
! 414: }
! 415:
! 416: int hostname_isequal(const char *a, const char *b)
! 417: {
! 418: return hostname_order(a, b) == 0;
1.1 misho 419: }
1.1.1.4 misho 420:
421: /* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
422: int hostname_issubdomain(char *a, char *b)
423: {
424: char *ap, *bp;
425: unsigned int c1, c2;
426:
427: /* move to the end */
428: for (ap = a; *ap; ap++);
429: for (bp = b; *bp; bp++);
430:
431: /* a shorter than b or a empty. */
432: if ((bp - b) < (ap - a) || ap == a)
433: return 0;
434:
435: do
436: {
437: c1 = (unsigned char) *(--ap);
438: c2 = (unsigned char) *(--bp);
439:
440: if (c1 >= 'A' && c1 <= 'Z')
441: c1 += 'a' - 'A';
442: if (c2 >= 'A' && c2 <= 'Z')
443: c2 += 'a' - 'A';
444:
445: if (c1 != c2)
446: return 0;
447: } while (ap != a);
448:
449: if (bp == b)
450: return 2;
451:
452: if (*(--bp) == '.')
453: return 1;
454:
455: return 0;
456: }
457:
458:
1.1 misho 459: time_t dnsmasq_time(void)
460: {
461: #ifdef HAVE_BROKEN_RTC
1.1.1.5 ! misho 462: struct timespec ts;
1.1 misho 463:
1.1.1.5 ! misho 464: if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
! 465: die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
1.1 misho 466:
1.1.1.5 ! misho 467: return ts.tv_sec;
1.1 misho 468: #else
469: return time(NULL);
470: #endif
471: }
472:
1.1.1.5 ! misho 473: u32 dnsmasq_milliseconds(void)
! 474: {
! 475: struct timeval tv;
! 476:
! 477: gettimeofday(&tv, NULL);
! 478:
! 479: return (tv.tv_sec) * 1000 + (tv.tv_usec / 1000);
! 480: }
! 481:
1.1.1.3 misho 482: int netmask_length(struct in_addr mask)
483: {
484: int zero_count = 0;
485:
486: while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
487: {
488: mask.s_addr >>= 1;
489: zero_count++;
490: }
491:
492: return 32 - zero_count;
493: }
494:
1.1 misho 495: int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
496: {
497: return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
1.1.1.5 ! misho 498: }
! 499:
! 500: int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix)
! 501: {
! 502: struct in_addr mask;
! 503:
! 504: mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
! 505:
! 506: return is_same_net(a, b, mask);
! 507: }
! 508:
1.1 misho 509:
510: int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
511: {
512: int pfbytes = prefixlen >> 3;
513: int pfbits = prefixlen & 7;
514:
515: if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
516: return 0;
517:
518: if (pfbits == 0 ||
519: (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
520: return 1;
521:
522: return 0;
523: }
524:
1.1.1.4 misho 525: /* return least significant 64 bits if IPv6 address */
1.1 misho 526: u64 addr6part(struct in6_addr *addr)
527: {
528: int i;
529: u64 ret = 0;
530:
531: for (i = 8; i < 16; i++)
532: ret = (ret << 8) + addr->s6_addr[i];
533:
534: return ret;
535: }
536:
537: void setaddr6part(struct in6_addr *addr, u64 host)
538: {
539: int i;
540:
541: for (i = 15; i >= 8; i--)
542: {
543: addr->s6_addr[i] = host;
544: host = host >> 8;
545: }
546: }
547:
548:
549: /* returns port number from address */
550: int prettyprint_addr(union mysockaddr *addr, char *buf)
551: {
552: int port = 0;
553:
554: if (addr->sa.sa_family == AF_INET)
555: {
556: inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
557: port = ntohs(addr->in.sin_port);
558: }
559: else if (addr->sa.sa_family == AF_INET6)
560: {
561: char name[IF_NAMESIZE];
562: inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
563: if (addr->in6.sin6_scope_id != 0 &&
564: if_indextoname(addr->in6.sin6_scope_id, name) &&
565: strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
566: {
567: strcat(buf, "%");
568: strcat(buf, name);
569: }
570: port = ntohs(addr->in6.sin6_port);
571: }
572:
573: return port;
574: }
575:
576: void prettyprint_time(char *buf, unsigned int t)
577: {
578: if (t == 0xffffffff)
579: sprintf(buf, _("infinite"));
580: else
581: {
582: unsigned int x, p = 0;
583: if ((x = t/86400))
1.1.1.4 misho 584: p += sprintf(&buf[p], "%ud", x);
1.1 misho 585: if ((x = (t/3600)%24))
1.1.1.4 misho 586: p += sprintf(&buf[p], "%uh", x);
1.1 misho 587: if ((x = (t/60)%60))
1.1.1.4 misho 588: p += sprintf(&buf[p], "%um", x);
1.1 misho 589: if ((x = t%60))
1.1.1.5 ! misho 590: sprintf(&buf[p], "%us", x);
1.1 misho 591: }
592: }
593:
594:
595: /* in may equal out, when maxlen may be -1 (No max len).
596: Return -1 for extraneous no-hex chars found. */
597: int parse_hex(char *in, unsigned char *out, int maxlen,
598: unsigned int *wildcard_mask, int *mac_type)
599: {
1.1.1.4 misho 600: int done = 0, mask = 0, i = 0;
1.1 misho 601: char *r;
602:
603: if (mac_type)
604: *mac_type = 0;
605:
1.1.1.4 misho 606: while (!done && (maxlen == -1 || i < maxlen))
1.1 misho 607: {
608: for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
609: if (*r != '*' && !isxdigit((unsigned char)*r))
610: return -1;
611:
612: if (*r == 0)
1.1.1.4 misho 613: done = 1;
1.1 misho 614:
615: if (r != in )
616: {
617: if (*r == '-' && i == 0 && mac_type)
618: {
619: *r = 0;
620: *mac_type = strtol(in, NULL, 16);
621: mac_type = NULL;
622: }
623: else
624: {
625: *r = 0;
626: if (strcmp(in, "*") == 0)
627: {
628: mask = (mask << 1) | 1;
629: i++;
630: }
631: else
632: {
633: int j, bytes = (1 + (r - in))/2;
634: for (j = 0; j < bytes; j++)
635: {
1.1.1.5 ! misho 636: char sav;
1.1 misho 637: if (j < bytes - 1)
638: {
639: sav = in[(j+1)*2];
640: in[(j+1)*2] = 0;
641: }
1.1.1.4 misho 642: /* checks above allow mix of hexdigit and *, which
643: is illegal. */
644: if (strchr(&in[j*2], '*'))
645: return -1;
1.1 misho 646: out[i] = strtol(&in[j*2], NULL, 16);
647: mask = mask << 1;
1.1.1.4 misho 648: if (++i == maxlen)
649: break;
1.1 misho 650: if (j < bytes - 1)
651: in[(j+1)*2] = sav;
652: }
653: }
654: }
655: }
656: in = r+1;
657: }
658:
659: if (wildcard_mask)
660: *wildcard_mask = mask;
661:
662: return i;
663: }
664:
665: /* return 0 for no match, or (no matched octets) + 1 */
666: int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
667: {
668: int i, count;
669: for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
670: if (!(mask & 1))
671: {
672: if (a[i] == b[i])
673: count++;
674: else
675: return 0;
676: }
677: return count;
678: }
679:
680: /* _note_ may copy buffer */
681: int expand_buf(struct iovec *iov, size_t size)
682: {
683: void *new;
684:
685: if (size <= (size_t)iov->iov_len)
686: return 1;
687:
688: if (!(new = whine_malloc(size)))
689: {
690: errno = ENOMEM;
691: return 0;
692: }
693:
694: if (iov->iov_base)
695: {
696: memcpy(new, iov->iov_base, iov->iov_len);
697: free(iov->iov_base);
698: }
699:
700: iov->iov_base = new;
701: iov->iov_len = size;
702:
703: return 1;
704: }
705:
706: char *print_mac(char *buff, unsigned char *mac, int len)
707: {
708: char *p = buff;
709: int i;
710:
711: if (len == 0)
712: sprintf(p, "<null>");
713: else
714: for (i = 0; i < len; i++)
715: p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
716:
717: return buff;
718: }
719:
1.1.1.3 misho 720: /* rc is return from sendto and friends.
721: Return 1 if we should retry.
722: Set errno to zero if we succeeded. */
723: int retry_send(ssize_t rc)
1.1 misho 724: {
1.1.1.3 misho 725: static int retries = 0;
726: struct timespec waiter;
727:
728: if (rc != -1)
729: {
730: retries = 0;
731: errno = 0;
732: return 0;
733: }
734:
735: /* Linux kernels can return EAGAIN in perpetuity when calling
736: sendmsg() and the relevant interface has gone. Here we loop
737: retrying in EAGAIN for 1 second max, to avoid this hanging
738: dnsmasq. */
1.1 misho 739:
1.1.1.3 misho 740: if (errno == EAGAIN || errno == EWOULDBLOCK)
1.1 misho 741: {
742: waiter.tv_sec = 0;
743: waiter.tv_nsec = 10000;
744: nanosleep(&waiter, NULL);
1.1.1.3 misho 745: if (retries++ < 1000)
746: return 1;
1.1 misho 747: }
1.1.1.3 misho 748:
749: retries = 0;
750:
751: if (errno == EINTR)
752: return 1;
753:
754: return 0;
1.1 misho 755: }
756:
757: int read_write(int fd, unsigned char *packet, int size, int rw)
758: {
759: ssize_t n, done;
760:
761: for (done = 0; done < size; done += n)
762: {
1.1.1.3 misho 763: do {
764: if (rw)
765: n = read(fd, &packet[done], (size_t)(size - done));
766: else
767: n = write(fd, &packet[done], (size_t)(size - done));
768:
769: if (n == 0)
770: return 0;
771:
772: } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
773:
774: if (errno != 0)
775: return 0;
1.1 misho 776: }
1.1.1.3 misho 777:
1.1 misho 778: return 1;
779: }
780:
1.1.1.4 misho 781: /* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
782: void close_fds(long max_fd, int spare1, int spare2, int spare3)
783: {
784: /* On Linux, use the /proc/ filesystem to find which files
785: are actually open, rather than iterate over the whole space,
786: for efficiency reasons. If this fails we drop back to the dumb code. */
787: #ifdef HAVE_LINUX_NETWORK
788: DIR *d;
789:
790: if ((d = opendir("/proc/self/fd")))
791: {
792: struct dirent *de;
793:
794: while ((de = readdir(d)))
795: {
796: long fd;
797: char *e = NULL;
798:
799: errno = 0;
800: fd = strtol(de->d_name, &e, 10);
801:
802: if (errno != 0 || !e || *e || fd == dirfd(d) ||
803: fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
804: fd == spare1 || fd == spare2 || fd == spare3)
805: continue;
806:
807: close(fd);
808: }
809:
810: closedir(d);
811: return;
812: }
813: #endif
814:
815: /* fallback, dumb code. */
816: for (max_fd--; max_fd >= 0; max_fd--)
817: if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
818: max_fd != spare1 && max_fd != spare2 && max_fd != spare3)
819: close(max_fd);
820: }
821:
1.1 misho 822: /* Basically match a string value against a wildcard pattern. */
823: int wildcard_match(const char* wildcard, const char* match)
824: {
825: while (*wildcard && *match)
826: {
827: if (*wildcard == '*')
828: return 1;
829:
830: if (*wildcard != *match)
831: return 0;
832:
833: ++wildcard;
834: ++match;
835: }
836:
837: return *wildcard == *match;
1.1.1.3 misho 838: }
839:
840: /* The same but comparing a maximum of NUM characters, like strncmp. */
841: int wildcard_matchn(const char* wildcard, const char* match, int num)
842: {
843: while (*wildcard && *match && num)
844: {
845: if (*wildcard == '*')
846: return 1;
847:
848: if (*wildcard != *match)
849: return 0;
850:
851: ++wildcard;
852: ++match;
853: --num;
854: }
855:
856: return (!num) || (*wildcard == *match);
1.1 misho 857: }
1.1.1.4 misho 858:
859: #ifdef HAVE_LINUX_NETWORK
860: int kernel_version(void)
861: {
862: struct utsname utsname;
863: int version;
864: char *split;
865:
866: if (uname(&utsname) < 0)
867: die(_("failed to find kernel version: %s"), NULL, EC_MISC);
868:
869: split = strtok(utsname.release, ".");
870: version = (split ? atoi(split) : 0);
871: split = strtok(NULL, ".");
872: version = version * 256 + (split ? atoi(split) : 0);
873: split = strtok(NULL, ".");
874: return version * 256 + (split ? atoi(split) : 0);
875: }
876: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>