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