From 69a815aa8f4b91570b562a54b43c3d44ac533e06 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sat, 8 Jul 2017 21:20:16 +0100 Subject: [PATCH] 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. --- src/util.c | 63 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/util.c b/src/util.c index bb6dba3..76ee7f4 100644 --- a/src/util.c +++ b/src/util.c @@ -111,6 +111,7 @@ u64 rand64(void) 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) { /* remove trailing . @@ -118,6 +119,7 @@ static int check_name(char *in) size_t dotgap = 0, l = strlen(in); char c; int nowhite = 0; + int hasuscore = 0; if (l == 0 || l > MAXDNAME) return 0; @@ -141,13 +143,17 @@ static int check_name(char *in) return 0; #endif else if (c != ' ') - nowhite = 1; + { + nowhite = 1; + if (c == '_') + hasuscore = 1; + } } if (!nowhite) return 0; - return 1; + return hasuscore ? 2 : 1; } /* Hostnames have a more limited valid charset than domain names @@ -186,43 +192,48 @@ int legal_hostname(char *name) char *canonicalise(char *in, int *nomem) { char *ret = NULL; -#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) int rc; -#endif - + if (nomem) *nomem = 0; - if (!check_name(in)) + if (!(rc = check_name(in))) return NULL; #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) -#ifdef HAVE_LIBIDN2 - rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL); - if (rc == IDN2_DISALLOWED) - rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL); -#else - rc = idna_to_ascii_lz(in, &ret, 0); -#endif - if (rc != IDNA_SUCCESS) + /* libidn2 strips underscores, so don't do IDN processing + if the name has an underscore (check_name() returned 2) */ + if (rc != 2) { - if (ret) - free(ret); - - if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR)) - { - my_syslog(LOG_ERR, _("failed to allocate memory")); - *nomem = 1; - } - - return NULL; - } +#ifdef HAVE_LIBIDN2 + rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL); + if (rc == IDN2_DISALLOWED) + rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL); #else + rc = idna_to_ascii_lz(in, &ret, 0); +#endif + 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")); + *nomem = 1; + } + + return NULL; + } + + return ret; + } +#endif + if ((ret = whine_malloc(strlen(in)+1))) strcpy(ret, in); else if (nomem) *nomem = 1; -#endif return ret; }