Annotation of embedaddon/dnsmasq/src/util.c, revision 1.1.1.4

1.1.1.4 ! misho       1: /* dnsmasq is Copyright (c) 2000-2021 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.4 ! misho     118: /* returns 2 if names is OK but contains one or more underscores */
1.1       misho     119: static int check_name(char *in)
                    120: {
                    121:   /* remove trailing . 
                    122:      also fail empty string and label > 63 chars */
                    123:   size_t dotgap = 0, l = strlen(in);
                    124:   char c;
                    125:   int nowhite = 0;
1.1.1.4 ! misho     126:   int hasuscore = 0;
1.1       misho     127:   
                    128:   if (l == 0 || l > MAXDNAME) return 0;
                    129:   
                    130:   if (in[l-1] == '.')
                    131:     {
                    132:       in[l-1] = 0;
1.1.1.2   misho     133:       nowhite = 1;
1.1       misho     134:     }
1.1.1.2   misho     135: 
1.1       misho     136:   for (; (c = *in); in++)
                    137:     {
                    138:       if (c == '.')
                    139:        dotgap = 0;
                    140:       else if (++dotgap > MAXLABEL)
                    141:        return 0;
                    142:       else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) 
                    143:        /* iscntrl only gives expected results for ascii */
                    144:        return 0;
1.1.1.4 ! misho     145: #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
1.1       misho     146:       else if (!isascii((unsigned char)c))
                    147:        return 0;
                    148: #endif
                    149:       else if (c != ' ')
1.1.1.4 ! misho     150:        {
        !           151:          nowhite = 1;
        !           152:          if (c == '_')
        !           153:            hasuscore = 1;
        !           154:        }
1.1       misho     155:     }
                    156: 
                    157:   if (!nowhite)
                    158:     return 0;
                    159: 
1.1.1.4 ! misho     160:   return hasuscore ? 2 : 1;
1.1       misho     161: }
                    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. */
                    167: int legal_hostname(char *name)
                    168: {
                    169:   char c;
1.1.1.2   misho     170:   int first;
1.1       misho     171: 
                    172:   if (!check_name(name))
                    173:     return 0;
                    174: 
1.1.1.2   misho     175:   for (first = 1; (c = *name); name++, first = 0)
1.1       misho     176:     /* check for legal char a-z A-Z 0-9 - _ . */
                    177:     {
                    178:       if ((c >= 'A' && c <= 'Z') ||
                    179:          (c >= 'a' && c <= 'z') ||
1.1.1.2   misho     180:          (c >= '0' && c <= '9'))
                    181:        continue;
                    182: 
                    183:       if (!first && (c == '-' || c == '_'))
1.1       misho     184:        continue;
                    185:       
                    186:       /* end of hostname part */
                    187:       if (c == '.')
                    188:        return 1;
                    189:       
                    190:       return 0;
                    191:     }
                    192:   
                    193:   return 1;
                    194: }
                    195:   
                    196: char *canonicalise(char *in, int *nomem)
                    197: {
                    198:   char *ret = NULL;
                    199:   int rc;
1.1.1.4 ! misho     200:   
1.1       misho     201:   if (nomem)
                    202:     *nomem = 0;
                    203:   
1.1.1.4 ! misho     204:   if (!(rc = check_name(in)))
1.1       misho     205:     return NULL;
                    206:   
1.1.1.4 ! misho     207: #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
        !           208:   /* older libidn2 strips underscores, so don't do IDN processing
        !           209:      if the name has an underscore (check_name() returned 2) */
        !           210:   if (rc != 2)
        !           211: #endif
        !           212: #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
        !           213:     {
        !           214: #  ifdef HAVE_LIBIDN2
        !           215:       rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
        !           216:       if (rc == IDN2_DISALLOWED)
        !           217:        rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
        !           218: #  else
        !           219:       rc = idna_to_ascii_lz(in, &ret, 0);
        !           220: #  endif
        !           221:       if (rc != IDNA_SUCCESS)
1.1       misho     222:        {
1.1.1.4 ! misho     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;
1.1       misho     233:        }
1.1.1.4 ! misho     234:       
        !           235:       return ret;
1.1       misho     236:     }
1.1.1.4 ! misho     237: #endif
        !           238:   
1.1       misho     239:   if ((ret = whine_malloc(strlen(in)+1)))
                    240:     strcpy(ret, in);
                    241:   else if (nomem)
                    242:     *nomem = 1;    
                    243: 
                    244:   return ret;
                    245: }
                    246: 
1.1.1.4 ! misho     247: unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
1.1       misho     248: {
                    249:   int j;
                    250:   
                    251:   while (sval && *sval)
                    252:     {
                    253:       unsigned char *cp = p++;
1.1.1.4 ! misho     254: 
        !           255:       if (limit && p > (unsigned char*)limit)
        !           256:         return NULL;
        !           257: 
1.1       misho     258:       for (j = 0; *sval && (*sval != '.'); sval++, j++)
1.1.1.3   misho     259:        {
1.1.1.4 ! misho     260:           if (limit && p + 1 > (unsigned char*)limit)
        !           261:             return NULL;
        !           262: 
1.1.1.3   misho     263: #ifdef HAVE_DNSSEC
                    264:          if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
                    265:            *p++ = (*(++sval))-1;
                    266:          else
                    267: #endif         
                    268:            *p++ = *sval;
                    269:        }
1.1.1.4 ! misho     270:       
1.1       misho     271:       *cp  = j;
                    272:       if (*sval)
                    273:        sval++;
                    274:     }
1.1.1.4 ! misho     275:   
1.1       misho     276:   return p;
                    277: }
                    278: 
                    279: /* for use during startup */
                    280: void *safe_malloc(size_t size)
                    281: {
1.1.1.4 ! misho     282:   void *ret = calloc(1, size);
1.1       misho     283:   
                    284:   if (!ret)
                    285:     die(_("could not get memory"), NULL, EC_NOMEM);
1.1.1.4 ! misho     286:       
1.1       misho     287:   return ret;
1.1.1.4 ! misho     288: }
        !           289: 
        !           290: /* Ensure limited size string is always terminated.
        !           291:  * Can be replaced by (void)strlcpy() on some platforms */
        !           292: void safe_strncpy(char *dest, const char *src, size_t size)
        !           293: {
        !           294:   if (size != 0)
        !           295:     {
        !           296:       dest[size-1] = '\0';
        !           297:       strncpy(dest, src, size-1);
        !           298:     }
        !           299: }
1.1       misho     300: 
                    301: void 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: 
                    309: void *whine_malloc(size_t size)
                    310: {
1.1.1.4 ! misho     311:   void *ret = calloc(1, size);
1.1       misho     312: 
                    313:   if (!ret)
                    314:     my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
1.1.1.4 ! misho     315:   
1.1       misho     316:   return ret;
                    317: }
                    318: 
                    319: int 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 &&
                    325:          s1->in.sin_addr.s_addr == s2->in.sin_addr.s_addr)
                    326:        return 1;
1.1.1.4 ! misho     327:       
1.1       misho     328:       if (s1->sa.sa_family == AF_INET6 &&
                    329:          s1->in6.sin6_port == s2->in6.sin6_port &&
1.1.1.3   misho     330:          s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
1.1       misho     331:          IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
                    332:        return 1;
                    333:     }
                    334:   return 0;
                    335: }
                    336: 
                    337: int sa_len(union mysockaddr *addr)
                    338: {
                    339: #ifdef HAVE_SOCKADDR_SA_LEN
                    340:   return addr->sa.sa_len;
                    341: #else
                    342:   if (addr->sa.sa_family == AF_INET6)
                    343:     return sizeof(addr->in6);
                    344:   else
                    345:     return sizeof(addr->in); 
                    346: #endif
                    347: }
                    348: 
                    349: /* don't use strcasecmp and friends here - they may be messed up by LOCALE */
                    350: int hostname_isequal(const char *a, const char *b)
                    351: {
                    352:   unsigned int c1, c2;
                    353:   
                    354:   do {
                    355:     c1 = (unsigned char) *a++;
                    356:     c2 = (unsigned char) *b++;
                    357:     
                    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: }
1.1.1.4 ! misho     369: 
        !           370: /* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
        !           371: int 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:   
1.1       misho     408: time_t dnsmasq_time(void)
                    409: {
                    410: #ifdef HAVE_BROKEN_RTC
                    411:   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);
                    418: #else
                    419:   return time(NULL);
                    420: #endif
                    421: }
                    422: 
1.1.1.3   misho     423: int netmask_length(struct in_addr mask)
                    424: {
                    425:   int zero_count = 0;
                    426: 
                    427:   while (0x0 == (mask.s_addr & 0x1) && zero_count < 32) 
                    428:     {
                    429:       mask.s_addr >>= 1;
                    430:       zero_count++;
                    431:     }
                    432:   
                    433:   return 32 - zero_count;
                    434: }
                    435: 
1.1       misho     436: int 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: } 
                    440: 
                    441: int 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 ||
                    450:       (a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
                    451:     return 1;
                    452: 
                    453:   return 0;
                    454: }
                    455: 
1.1.1.4 ! misho     456: /* return least significant 64 bits if IPv6 address */
1.1       misho     457: u64 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: 
                    468: void 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: 
                    479: 
                    480: /* returns port number from address */
                    481: int prettyprint_addr(union mysockaddr *addr, char *buf)
                    482: {
                    483:   int port = 0;
                    484:   
                    485:   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:     {
                    492:       char name[IF_NAMESIZE];
                    493:       inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
                    494:       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:        }
                    501:       port = ntohs(addr->in6.sin6_port);
                    502:     }
                    503:   
                    504:   return port;
                    505: }
                    506: 
                    507: void prettyprint_time(char *buf, unsigned int t)
                    508: {
                    509:   if (t == 0xffffffff)
                    510:     sprintf(buf, _("infinite"));
                    511:   else
                    512:     {
                    513:       unsigned int x, p = 0;
                    514:        if ((x = t/86400))
1.1.1.4 ! misho     515:        p += sprintf(&buf[p], "%ud", x);
1.1       misho     516:        if ((x = (t/3600)%24))
1.1.1.4 ! misho     517:        p += sprintf(&buf[p], "%uh", x);
1.1       misho     518:       if ((x = (t/60)%60))
1.1.1.4 ! misho     519:        p += sprintf(&buf[p], "%um", x);
1.1       misho     520:       if ((x = t%60))
1.1.1.4 ! misho     521:        p += sprintf(&buf[p], "%us", x);
1.1       misho     522:     }
                    523: }
                    524: 
                    525: 
                    526: /* in may equal out, when maxlen may be -1 (No max len). 
                    527:    Return -1 for extraneous no-hex chars found. */
                    528: int parse_hex(char *in, unsigned char *out, int maxlen, 
                    529:              unsigned int *wildcard_mask, int *mac_type)
                    530: {
1.1.1.4 ! misho     531:   int done = 0, mask = 0, i = 0;
1.1       misho     532:   char *r;
                    533:     
                    534:   if (mac_type)
                    535:     *mac_type = 0;
                    536:   
1.1.1.4 ! misho     537:   while (!done && (maxlen == -1 || i < maxlen))
1.1       misho     538:     {
                    539:       for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
                    540:        if (*r != '*' && !isxdigit((unsigned char)*r))
                    541:          return -1;
                    542:       
                    543:       if (*r == 0)
1.1.1.4 ! misho     544:        done = 1;
1.1       misho     545:       
                    546:       if (r != in )
                    547:        {
                    548:          if (*r == '-' && i == 0 && mac_type)
                    549:           {
                    550:              *r = 0;
                    551:              *mac_type = strtol(in, NULL, 16);
                    552:              mac_type = NULL;
                    553:           }
                    554:          else
                    555:            {
                    556:              *r = 0;
                    557:              if (strcmp(in, "*") == 0)
                    558:                {
                    559:                  mask = (mask << 1) | 1;
                    560:                  i++;
                    561:                }
                    562:              else
                    563:                {
                    564:                  int j, bytes = (1 + (r - in))/2;
                    565:                  for (j = 0; j < bytes; j++)
                    566:                    { 
1.1.1.2   misho     567:                      char sav = sav;
1.1       misho     568:                      if (j < bytes - 1)
                    569:                        {
                    570:                          sav = in[(j+1)*2];
                    571:                          in[(j+1)*2] = 0;
                    572:                        }
1.1.1.4 ! misho     573:                      /* checks above allow mix of hexdigit and *, which
        !           574:                         is illegal. */
        !           575:                      if (strchr(&in[j*2], '*'))
        !           576:                        return -1;
1.1       misho     577:                      out[i] = strtol(&in[j*2], NULL, 16);
                    578:                      mask = mask << 1;
1.1.1.4 ! misho     579:                      if (++i == maxlen)
        !           580:                        break; 
1.1       misho     581:                      if (j < bytes - 1)
                    582:                        in[(j+1)*2] = sav;
                    583:                    }
                    584:                }
                    585:            }
                    586:        }
                    587:       in = r+1;
                    588:     }
                    589:   
                    590:   if (wildcard_mask)
                    591:     *wildcard_mask = mask;
                    592: 
                    593:   return i;
                    594: }
                    595: 
                    596: /* return 0 for no match, or (no matched octets) + 1 */
                    597: int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
                    598: {
                    599:   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;
                    609: }
                    610: 
                    611: /* _note_ may copy buffer */
                    612: int expand_buf(struct iovec *iov, size_t size)
                    613: {
                    614:   void *new;
                    615: 
                    616:   if (size <= (size_t)iov->iov_len)
                    617:     return 1;
                    618: 
                    619:   if (!(new = whine_malloc(size)))
                    620:     {
                    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: }
                    636: 
                    637: char *print_mac(char *buff, unsigned char *mac, int len)
                    638: {
                    639:   char *p = buff;
                    640:   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:   
                    648:   return buff;
                    649: }
                    650: 
1.1.1.3   misho     651: /* rc is return from sendto and friends.
                    652:    Return 1 if we should retry.
                    653:    Set errno to zero if we succeeded. */
                    654: int retry_send(ssize_t rc)
1.1       misho     655: {
1.1.1.3   misho     656:   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:   
                    666:   /* 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. */
1.1       misho     670: 
1.1.1.3   misho     671:   if (errno == EAGAIN || errno == EWOULDBLOCK)
1.1       misho     672:      {
                    673:        waiter.tv_sec = 0;
                    674:        waiter.tv_nsec = 10000;
                    675:        nanosleep(&waiter, NULL);
1.1.1.3   misho     676:        if (retries++ < 1000)
                    677:         return 1;
1.1       misho     678:      }
1.1.1.3   misho     679:   
                    680:   retries = 0;
                    681:   
                    682:   if (errno == EINTR)
                    683:     return 1;
                    684:   
                    685:   return 0;
1.1       misho     686: }
                    687: 
                    688: int 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:     {
1.1.1.3   misho     694:       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);
                    704: 
                    705:       if (errno != 0)
                    706:        return 0;
1.1       misho     707:     }
1.1.1.3   misho     708:      
1.1       misho     709:   return 1;
                    710: }
                    711: 
1.1.1.4 ! misho     712: /* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
        !           713: void close_fds(long max_fd, int spare1, int spare2, int spare3) 
        !           714: {
        !           715:   /* 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:          
        !           738:          close(fd);
        !           739:        }
        !           740:       
        !           741:       closedir(d);
        !           742:       return;
        !           743:   }
        !           744: #endif
        !           745: 
        !           746:   /* fallback, dumb code. */
        !           747:   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: 
1.1       misho     753: /* Basically match a string value against a wildcard pattern.  */
                    754: int 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;
1.1.1.3   misho     769: }
                    770: 
                    771: /* The same but comparing a maximum of NUM characters, like strncmp.  */
                    772: int 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);
1.1       misho     788: }
1.1.1.4 ! misho     789: 
        !           790: #ifdef HAVE_LINUX_NETWORK
        !           791: int 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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>