version 1.1.1.4, 2021/03/17 00:56:46
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 115 u64 rand64(void)
|
Line 115 u64 rand64(void)
|
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32); |
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32); |
} |
} |
|
|
/* returns 2 if names is OK but contains one or more underscores */ | /* returns 1 if name is OK and ascii printable |
| * returns 2 if name should be processed by IDN */ |
static int check_name(char *in) |
static int check_name(char *in) |
{ |
{ |
/* remove trailing . |
/* remove trailing . |
Line 123 static int check_name(char *in)
|
Line 124 static int check_name(char *in)
|
size_t dotgap = 0, l = strlen(in); |
size_t dotgap = 0, l = strlen(in); |
char c; |
char c; |
int nowhite = 0; |
int nowhite = 0; |
|
int idn_encode = 0; |
int hasuscore = 0; |
int hasuscore = 0; |
|
int hasucase = 0; |
|
|
if (l == 0 || l > MAXDNAME) return 0; |
if (l == 0 || l > MAXDNAME) return 0; |
|
|
Line 136 static int check_name(char *in)
|
Line 139 static int check_name(char *in)
|
for (; (c = *in); in++) |
for (; (c = *in); in++) |
{ |
{ |
if (c == '.') |
if (c == '.') |
dotgap = 0; | dotgap = 0; |
else if (++dotgap > MAXLABEL) |
else if (++dotgap > MAXLABEL) |
return 0; | return 0; |
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) |
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c)) |
/* iscntrl only gives expected results for ascii */ | /* iscntrl only gives expected results for ascii */ |
return 0; | return 0; |
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2) | |
else if (!isascii((unsigned char)c)) |
else if (!isascii((unsigned char)c)) |
return 0; | #if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2) |
| return 0; |
| #else |
| idn_encode = 1; |
#endif |
#endif |
else if (c != ' ') |
else if (c != ' ') |
{ | { |
nowhite = 1; | nowhite = 1; |
if (c == '_') | #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003) |
hasuscore = 1; | if (c == '_') |
} | hasuscore = 1; |
| #else |
| (void)hasuscore; |
| #endif |
| |
| #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) |
| if (c >= 'A' && c <= 'Z') |
| hasucase = 1; |
| #else |
| (void)hasucase; |
| #endif |
| } |
} |
} |
|
|
if (!nowhite) |
if (!nowhite) |
return 0; |
return 0; |
|
|
return hasuscore ? 2 : 1; | #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003) |
| /* Older libidn2 strips underscores, so don't do IDN processing |
| if the name has an underscore unless it also has non-ascii characters. */ |
| idn_encode = idn_encode || (hasucase && !hasuscore); |
| #else |
| idn_encode = idn_encode || hasucase; |
| #endif |
| |
| return (idn_encode) ? 2 : 1; |
} |
} |
|
|
/* Hostnames have a more limited valid charset than domain names |
/* Hostnames have a more limited valid charset than domain names |
Line 204 char *canonicalise(char *in, int *nomem)
|
Line 228 char *canonicalise(char *in, int *nomem)
|
if (!(rc = check_name(in))) |
if (!(rc = check_name(in))) |
return NULL; |
return NULL; |
|
|
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003) |
|
/* older libidn2 strips underscores, so don't do IDN processing |
|
if the name has an underscore (check_name() returned 2) */ |
|
if (rc != 2) |
|
#endif |
|
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) |
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) |
|
if (rc == 2) |
{ |
{ |
# ifdef HAVE_LIBIDN2 |
# ifdef HAVE_LIBIDN2 |
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL); |
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL); |
if (rc == IDN2_DISALLOWED) |
|
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL); |
|
# else |
# else |
rc = idna_to_ascii_lz(in, &ret, 0); |
rc = idna_to_ascii_lz(in, &ret, 0); |
# endif |
# endif |
Line 234 char *canonicalise(char *in, int *nomem)
|
Line 252 char *canonicalise(char *in, int *nomem)
|
|
|
return ret; |
return ret; |
} |
} |
|
#else |
|
(void)rc; |
#endif |
#endif |
|
|
if ((ret = whine_malloc(strlen(in)+1))) |
if ((ret = whine_malloc(strlen(in)+1))) |
strcpy(ret, in); |
strcpy(ret, in); |
else if (nomem) |
else if (nomem) |
*nomem = 1; | *nomem = 1; |
|
|
return ret; |
return ret; |
} |
} |
Line 316 void *whine_malloc(size_t size)
|
Line 336 void *whine_malloc(size_t size)
|
return ret; |
return ret; |
} |
} |
|
|
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2) | void *whine_realloc(void *ptr, size_t size) |
{ |
{ |
|
void *ret = realloc(ptr, size); |
|
|
|
if (!ret) |
|
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size); |
|
|
|
return ret; |
|
} |
|
|
|
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2) |
|
{ |
if (s1->sa.sa_family == s2->sa.sa_family) |
if (s1->sa.sa_family == s2->sa.sa_family) |
{ |
{ |
if (s1->sa.sa_family == AF_INET && |
if (s1->sa.sa_family == AF_INET && |
Line 334 int sockaddr_isequal(union mysockaddr *s1, union mysoc
|
Line 364 int sockaddr_isequal(union mysockaddr *s1, union mysoc
|
return 0; |
return 0; |
} |
} |
|
|
|
int sockaddr_isnull(const union mysockaddr *s) |
|
{ |
|
if (s->sa.sa_family == AF_INET && |
|
s->in.sin_addr.s_addr == 0) |
|
return 1; |
|
|
|
if (s->sa.sa_family == AF_INET6 && |
|
IN6_IS_ADDR_UNSPECIFIED(&s->in6.sin6_addr)) |
|
return 1; |
|
|
|
return 0; |
|
} |
|
|
int sa_len(union mysockaddr *addr) |
int sa_len(union mysockaddr *addr) |
{ |
{ |
#ifdef HAVE_SOCKADDR_SA_LEN |
#ifdef HAVE_SOCKADDR_SA_LEN |
Line 347 int sa_len(union mysockaddr *addr)
|
Line 390 int sa_len(union mysockaddr *addr)
|
} |
} |
|
|
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */ |
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */ |
int hostname_isequal(const char *a, const char *b) | int hostname_order(const char *a, const char *b) |
{ |
{ |
unsigned int c1, c2; |
unsigned int c1, c2; |
|
|
Line 360 int hostname_isequal(const char *a, const char *b)
|
Line 403 int hostname_isequal(const char *a, const char *b)
|
if (c2 >= 'A' && c2 <= 'Z') |
if (c2 >= 'A' && c2 <= 'Z') |
c2 += 'a' - 'A'; |
c2 += 'a' - 'A'; |
|
|
if (c1 != c2) | if (c1 < c2) |
return 0; | return -1; |
| else if (c1 > c2) |
| return 1; |
| |
} while (c1); |
} while (c1); |
|
|
return 1; | return 0; |
} |
} |
|
|
|
int hostname_isequal(const char *a, const char *b) |
|
{ |
|
return hostname_order(a, b) == 0; |
|
} |
|
|
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */ |
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */ |
int hostname_issubdomain(char *a, char *b) |
int hostname_issubdomain(char *a, char *b) |
{ |
{ |
Line 408 int hostname_issubdomain(char *a, char *b)
|
Line 459 int hostname_issubdomain(char *a, char *b)
|
time_t dnsmasq_time(void) |
time_t dnsmasq_time(void) |
{ |
{ |
#ifdef HAVE_BROKEN_RTC |
#ifdef HAVE_BROKEN_RTC |
struct tms dummy; | struct timespec ts; |
static long tps = 0; | |
|
|
if (tps == 0) | if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) |
tps = sysconf(_SC_CLK_TCK); | die(_("cannot read monotonic clock: %s"), NULL, EC_MISC); |
|
|
return (time_t)(times(&dummy)/tps); | return ts.tv_sec; |
#else |
#else |
return time(NULL); |
return time(NULL); |
#endif |
#endif |
} |
} |
|
|
|
u32 dnsmasq_milliseconds(void) |
|
{ |
|
struct timeval tv; |
|
|
|
gettimeofday(&tv, NULL); |
|
|
|
return (tv.tv_sec) * 1000 + (tv.tv_usec / 1000); |
|
} |
|
|
int netmask_length(struct in_addr mask) |
int netmask_length(struct in_addr mask) |
{ |
{ |
int zero_count = 0; |
int zero_count = 0; |
Line 436 int netmask_length(struct in_addr mask)
|
Line 495 int netmask_length(struct in_addr mask)
|
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) |
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) |
{ |
{ |
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); |
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); |
} | } |
|
|
|
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix) |
|
{ |
|
struct in_addr mask; |
|
|
|
mask.s_addr = htonl(~((1 << (32 - prefix)) - 1)); |
|
|
|
return is_same_net(a, b, mask); |
|
} |
|
|
|
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen) |
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen) |
{ |
{ |
int pfbytes = prefixlen >> 3; |
int pfbytes = prefixlen >> 3; |
Line 518 void prettyprint_time(char *buf, unsigned int t)
|
Line 587 void prettyprint_time(char *buf, unsigned int t)
|
if ((x = (t/60)%60)) |
if ((x = (t/60)%60)) |
p += sprintf(&buf[p], "%um", x); |
p += sprintf(&buf[p], "%um", x); |
if ((x = t%60)) |
if ((x = t%60)) |
p += sprintf(&buf[p], "%us", x); | sprintf(&buf[p], "%us", x); |
} |
} |
} |
} |
|
|
Line 564 int parse_hex(char *in, unsigned char *out, int maxlen
|
Line 633 int parse_hex(char *in, unsigned char *out, int maxlen
|
int j, bytes = (1 + (r - in))/2; |
int j, bytes = (1 + (r - in))/2; |
for (j = 0; j < bytes; j++) |
for (j = 0; j < bytes; j++) |
{ |
{ |
char sav = sav; | char sav; |
if (j < bytes - 1) |
if (j < bytes - 1) |
{ |
{ |
sav = in[(j+1)*2]; |
sav = in[(j+1)*2]; |