check_name() determines if IDN processing is needed.

Optimization that only runs IDN processing if it would alter the domain
name (non-ascii or uppercase characters).

This patch has conributions from Petr Menšík.
This commit is contained in:
Gustaf Ullberg
2021-09-10 00:13:39 +01:00
committed by Simon Kelley
parent 6f4de018af
commit 93cf516bf1

View File

@@ -115,7 +115,8 @@ 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 .
@@ -123,7 +124,9 @@ 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;
@@ -142,22 +145,43 @@ static int check_name(char *in)
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))
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
return 0; return 0;
#else
idn_encode = 1;
#endif #endif
else if (c != ' ') else if (c != ' ')
{ {
nowhite = 1; nowhite = 1;
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
if (c == '_') if (c == '_')
hasuscore = 1; 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
@@ -204,12 +228,8 @@ 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);
@@ -234,6 +254,8 @@ 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)))