Fix loss of undercores in domain names when using libidn2.

libidn2 strips underscores from international domain names
when encoding them. Indeed, it strips underscores even if
no encoding is necessary, which breaks SRV records.

Don't submit domain names to IDN encoding if they contain
one or more underscores to fix this.
This commit is contained in:
Simon Kelley
2017-07-08 21:20:16 +01:00
parent 1d224949cc
commit 69a815aa8f

View File

@@ -111,6 +111,7 @@ 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 */
static int check_name(char *in) static int check_name(char *in)
{ {
/* remove trailing . /* remove trailing .
@@ -118,6 +119,7 @@ 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 hasuscore = 0;
if (l == 0 || l > MAXDNAME) return 0; if (l == 0 || l > MAXDNAME) return 0;
@@ -141,13 +143,17 @@ static int check_name(char *in)
return 0; return 0;
#endif #endif
else if (c != ' ') else if (c != ' ')
{
nowhite = 1; nowhite = 1;
if (c == '_')
hasuscore = 1;
}
} }
if (!nowhite) if (!nowhite)
return 0; return 0;
return 1; return hasuscore ? 2 : 1;
} }
/* Hostnames have a more limited valid charset than domain names /* Hostnames have a more limited valid charset than domain names
@@ -186,17 +192,19 @@ int legal_hostname(char *name)
char *canonicalise(char *in, int *nomem) char *canonicalise(char *in, int *nomem)
{ {
char *ret = NULL; char *ret = NULL;
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
int rc; int rc;
#endif
if (nomem) if (nomem)
*nomem = 0; *nomem = 0;
if (!check_name(in)) if (!(rc = check_name(in)))
return NULL; return NULL;
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
/* libidn2 strips underscores, so don't do IDN processing
if the name has an underscore (check_name() returned 2) */
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) if (rc == IDN2_DISALLOWED)
@@ -217,12 +225,15 @@ char *canonicalise(char *in, int *nomem)
return NULL; return NULL;
} }
#else
return ret;
}
#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;
#endif
return ret; return ret;
} }