"Fossies" - the Fresh Open Source Software Archive

Member "dnsmasq-2.85/src/util.c" (7 Apr 2021, 16801 Bytes) of package /linux/misc/dns/dnsmasq-2.85.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.84_vs_2.85.

    1 /* dnsmasq is Copyright (c) 2000-2021 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 2 if names is OK but contains one or more underscores */
  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;
  126   int hasuscore = 0;
  127   
  128   if (l == 0 || l > MAXDNAME) return 0;
  129   
  130   if (in[l-1] == '.')
  131     {
  132       in[l-1] = 0;
  133       nowhite = 1;
  134     }
  135 
  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;
  145 #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
  146       else if (!isascii((unsigned char)c))
  147     return 0;
  148 #endif
  149       else if (c != ' ')
  150     {
  151       nowhite = 1;
  152       if (c == '_')
  153         hasuscore = 1;
  154     }
  155     }
  156 
  157   if (!nowhite)
  158     return 0;
  159 
  160   return hasuscore ? 2 : 1;
  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;
  170   int first;
  171 
  172   if (!check_name(name))
  173     return 0;
  174 
  175   for (first = 1; (c = *name); name++, first = 0)
  176     /* check for legal char a-z A-Z 0-9 - _ . */
  177     {
  178       if ((c >= 'A' && c <= 'Z') ||
  179       (c >= 'a' && c <= 'z') ||
  180       (c >= '0' && c <= '9'))
  181     continue;
  182 
  183       if (!first && (c == '-' || c == '_'))
  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;
  200   
  201   if (nomem)
  202     *nomem = 0;
  203   
  204   if (!(rc = check_name(in)))
  205     return NULL;
  206   
  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)
  222     {
  223       if (ret)
  224         free(ret);
  225       
  226       if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
  227         {
  228           my_syslog(LOG_ERR, _("failed to allocate memory"));
  229           *nomem = 1;
  230         }
  231       
  232       return NULL;
  233     }
  234       
  235       return ret;
  236     }
  237 #endif
  238   
  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 
  247 unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
  248 {
  249   int j;
  250   
  251   while (sval && *sval)
  252     {
  253       unsigned char *cp = p++;
  254 
  255       if (limit && p > (unsigned char*)limit)
  256         return NULL;
  257 
  258       for (j = 0; *sval && (*sval != '.'); sval++, j++)
  259     {
  260           if (limit && p + 1 > (unsigned char*)limit)
  261             return NULL;
  262 
  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     }
  270       
  271       *cp  = j;
  272       if (*sval)
  273     sval++;
  274     }
  275   
  276   return p;
  277 }
  278 
  279 /* for use during startup */
  280 void *safe_malloc(size_t size)
  281 {
  282   void *ret = calloc(1, size);
  283   
  284   if (!ret)
  285     die(_("could not get memory"), NULL, EC_NOMEM);
  286       
  287   return ret;
  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 }
  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 {
  311   void *ret = calloc(1, size);
  312 
  313   if (!ret)
  314     my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
  315   
  316   return ret;
  317 }
  318 
  319 int sockaddr_isequal(const union mysockaddr *s1, const 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;
  327       
  328       if (s1->sa.sa_family == AF_INET6 &&
  329       s1->in6.sin6_port == s2->in6.sin6_port &&
  330       s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
  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 }
  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   
  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 
  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 
  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 
  456 /* return least significant 64 bits if IPv6 address */
  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))
  515     p += sprintf(&buf[p], "%ud", x);
  516        if ((x = (t/3600)%24))
  517     p += sprintf(&buf[p], "%uh", x);
  518       if ((x = (t/60)%60))
  519     p += sprintf(&buf[p], "%um", x);
  520       if ((x = t%60))
  521     p += sprintf(&buf[p], "%us", x);
  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 {
  531   int done = 0, mask = 0, i = 0;
  532   char *r;
  533     
  534   if (mac_type)
  535     *mac_type = 0;
  536   
  537   while (!done && (maxlen == -1 || i < maxlen))
  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)
  544     done = 1;
  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             { 
  567               char sav = sav;
  568               if (j < bytes - 1)
  569             {
  570               sav = in[(j+1)*2];
  571               in[(j+1)*2] = 0;
  572             }
  573               /* checks above allow mix of hexdigit and *, which
  574              is illegal. */
  575               if (strchr(&in[j*2], '*'))
  576             return -1;
  577               out[i] = strtol(&in[j*2], NULL, 16);
  578               mask = mask << 1;
  579               if (++i == maxlen)
  580             break; 
  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 
  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)
  655 {
  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. */
  670 
  671   if (errno == EAGAIN || errno == EWOULDBLOCK)
  672      {
  673        waiter.tv_sec = 0;
  674        waiter.tv_nsec = 10000;
  675        nanosleep(&waiter, NULL);
  676        if (retries++ < 1000)
  677      return 1;
  678      }
  679   
  680   retries = 0;
  681   
  682   if (errno == EINTR)
  683     return 1;
  684   
  685   return 0;
  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     {
  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;
  707     }
  708      
  709   return 1;
  710 }
  711 
  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 
  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;
  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);
  788 }
  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