File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / util.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (10 months, 2 weeks ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
    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: 
   27: #if defined(HAVE_LIBIDN2)
   28: #include <idn2.h>
   29: #elif defined(HAVE_IDN)
   30: #include <idna.h>
   31: #endif
   32: 
   33: #ifdef HAVE_LINUX_NETWORK
   34: #include <sys/utsname.h>
   35: #endif
   36: 
   37: /* SURF random number generator */
   38: 
   39: static u32 seed[32];
   40: static u32 in[12];
   41: static u32 out[8];
   42: static int outleft = 0;
   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: {
   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: 
   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: 
  102: u64 rand64(void)
  103: {
  104:   static int outleft = 0;
  105: 
  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;
  114: 
  115:   return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
  116: }
  117: 
  118: /* returns 1 if name is OK and ascii printable
  119:  * returns 2 if name should be processed by IDN */
  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;
  127:   int idn_encode = 0;
  128:   int hasuscore = 0;
  129:   int hasucase = 0;
  130:   
  131:   if (l == 0 || l > MAXDNAME) return 0;
  132:   
  133:   if (in[l-1] == '.')
  134:     {
  135:       in[l-1] = 0;
  136:       nowhite = 1;
  137:     }
  138: 
  139:   for (; (c = *in); in++)
  140:     {
  141:       if (c == '.')
  142:         dotgap = 0;
  143:       else if (++dotgap > MAXLABEL)
  144:         return 0;
  145:       else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) 
  146:         /* iscntrl only gives expected results for ascii */
  147:         return 0;
  148:       else if (!isascii((unsigned char)c))
  149: #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
  150:         return 0;
  151: #else
  152:         idn_encode = 1;
  153: #endif
  154:       else if (c != ' ')
  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:         }
  171:     }
  172: 
  173:   if (!nowhite)
  174:     return 0;
  175: 
  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;
  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;
  194:   int first;
  195: 
  196:   if (!check_name(name))
  197:     return 0;
  198: 
  199:   for (first = 1; (c = *name); name++, first = 0)
  200:     /* check for legal char a-z A-Z 0-9 - _ . */
  201:     {
  202:       if ((c >= 'A' && c <= 'Z') ||
  203: 	  (c >= 'a' && c <= 'z') ||
  204: 	  (c >= '0' && c <= '9'))
  205: 	continue;
  206: 
  207:       if (!first && (c == '-' || c == '_'))
  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;
  224:   
  225:   if (nomem)
  226:     *nomem = 0;
  227:   
  228:   if (!(rc = check_name(in)))
  229:     return NULL;
  230:   
  231: #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
  232:   if (rc == 2)
  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)
  240: 	{
  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;
  251: 	}
  252:       
  253:       return ret;
  254:     }
  255: #else
  256:   (void)rc;
  257: #endif
  258:   
  259:   if ((ret = whine_malloc(strlen(in)+1)))
  260:     strcpy(ret, in);
  261:   else if (nomem)
  262:     *nomem = 1;
  263: 
  264:   return ret;
  265: }
  266: 
  267: unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
  268: {
  269:   int j;
  270:   
  271:   while (sval && *sval)
  272:     {
  273:       unsigned char *cp = p++;
  274: 
  275:       if (limit && p > (unsigned char*)limit)
  276:         return NULL;
  277: 
  278:       for (j = 0; *sval && (*sval != '.'); sval++, j++)
  279: 	{
  280:           if (limit && p + 1 > (unsigned char*)limit)
  281:             return NULL;
  282: 
  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: 	}
  290:       
  291:       *cp  = j;
  292:       if (*sval)
  293: 	sval++;
  294:     }
  295:   
  296:   return p;
  297: }
  298: 
  299: /* for use during startup */
  300: void *safe_malloc(size_t size)
  301: {
  302:   void *ret = calloc(1, size);
  303:   
  304:   if (!ret)
  305:     die(_("could not get memory"), NULL, EC_NOMEM);
  306:       
  307:   return ret;
  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: }
  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: {
  331:   void *ret = calloc(1, size);
  332: 
  333:   if (!ret)
  334:     my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
  335:   
  336:   return ret;
  337: }
  338: 
  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)
  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;
  357:       
  358:       if (s1->sa.sa_family == AF_INET6 &&
  359: 	  s1->in6.sin6_port == s2->in6.sin6_port &&
  360: 	  s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
  361: 	  IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
  362: 	return 1;
  363:     }
  364:   return 0;
  365: }
  366: 
  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: 
  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 */
  393: int hostname_order(const char *a, const char *b)
  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:     
  406:     if (c1 < c2)
  407:       return -1;
  408:     else if (c1 > c2)
  409:       return 1;
  410:     
  411:   } while (c1);
  412:   
  413:   return 0;
  414: }
  415: 
  416: int hostname_isequal(const char *a, const char *b)
  417: {
  418:   return hostname_order(a, b) == 0;
  419: }
  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:   
  459: time_t dnsmasq_time(void)
  460: {
  461: #ifdef HAVE_BROKEN_RTC
  462:   struct timespec ts;
  463: 
  464:   if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
  465:     die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
  466: 
  467:   return ts.tv_sec;
  468: #else
  469:   return time(NULL);
  470: #endif
  471: }
  472: 
  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: 
  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: 
  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);
  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: 
  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: 
  525: /* return least significant 64 bits if IPv6 address */
  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))
  584: 	p += sprintf(&buf[p], "%ud", x);
  585:        if ((x = (t/3600)%24))
  586: 	p += sprintf(&buf[p], "%uh", x);
  587:       if ((x = (t/60)%60))
  588: 	p += sprintf(&buf[p], "%um", x);
  589:       if ((x = t%60))
  590: 	sprintf(&buf[p], "%us", x);
  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: {
  600:   int done = 0, mask = 0, i = 0;
  601:   char *r;
  602:     
  603:   if (mac_type)
  604:     *mac_type = 0;
  605:   
  606:   while (!done && (maxlen == -1 || i < maxlen))
  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)
  613: 	done = 1;
  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: 		    { 
  636: 		      char sav;
  637: 		      if (j < bytes - 1)
  638: 			{
  639: 			  sav = in[(j+1)*2];
  640: 			  in[(j+1)*2] = 0;
  641: 			}
  642: 		      /* checks above allow mix of hexdigit and *, which
  643: 			 is illegal. */
  644: 		      if (strchr(&in[j*2], '*'))
  645: 			return -1;
  646: 		      out[i] = strtol(&in[j*2], NULL, 16);
  647: 		      mask = mask << 1;
  648: 		      if (++i == maxlen)
  649: 			break; 
  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: 
  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)
  724: {
  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. */
  739: 
  740:   if (errno == EAGAIN || errno == EWOULDBLOCK)
  741:      {
  742:        waiter.tv_sec = 0;
  743:        waiter.tv_nsec = 10000;
  744:        nanosleep(&waiter, NULL);
  745:        if (retries++ < 1000)
  746: 	 return 1;
  747:      }
  748:   
  749:   retries = 0;
  750:   
  751:   if (errno == EINTR)
  752:     return 1;
  753:   
  754:   return 0;
  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:     {
  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;
  776:     }
  777:      
  778:   return 1;
  779: }
  780: 
  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: 
  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;
  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);
  857: }
  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>