Commit 69a815aa authored by Simon Kelley's avatar Simon Kelley

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.
parent 1d224949
...@@ -111,6 +111,7 @@ u64 rand64(void) ...@@ -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) ...@@ -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) ...@@ -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,43 +192,48 @@ int legal_hostname(char *name) ...@@ -186,43 +192,48 @@ 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)
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL); 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
if (rc != IDNA_SUCCESS) if (rc != IDNA_SUCCESS)
{
if (ret)
free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
{ {
my_syslog(LOG_ERR, _("failed to allocate memory")); if (ret)
*nomem = 1; free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
{
my_syslog(LOG_ERR, _("failed to allocate memory"));
*nomem = 1;
}
return NULL;
} }
return NULL; return ret;
} }
#else #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;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment