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>