summaryrefslogtreecommitdiffstats
path: root/src/shared/dns-domain.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2017-05-10 03:56:34 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2017-05-11 20:25:01 +0200
commit87057e244b4d2e723dc98b2b3cef1901c155f005 (patch)
treec7505157bfa7609a15700082336e4f04311243cd /src/shared/dns-domain.c
parent50-udev-default.rules.in: set correct group for mediaX/cecX (#5921) (diff)
downloadsystemd-87057e244b4d2e723dc98b2b3cef1901c155f005.tar.xz
systemd-87057e244b4d2e723dc98b2b3cef1901c155f005.zip
resolved: support libidn2 in addition to libidn
libidn2 2.0.0 supports IDNA2008, in contrast to libidn which supports IDNA2003. https://bugzilla.redhat.com/show_bug.cgi?id=1449145 From that bug report: Internationalized domain names exist for quite some time (IDNA2003), although the protocols describing them have evolved in an incompatible way (IDNA2008). These incompatibilities will prevent applications written for IDNA2003 to access certain problematic domain names defined with IDNA2008, e.g., faß.de is translated to domain xn--fa-hia.de with IDNA2008, while in IDNA2003 it is translated to fass.de domain. That not only causes incompatibility problems, but may be used as an attack vector to redirect users to different web sites. v2: - keep libidn support - require libidn2 >= 2.0.0 v3: - keep dns_name_apply_idna caller dumb, and keep the #ifdefs inside of the function. - use both ±IDN and ±IDN2 in the version string
Diffstat (limited to 'src/shared/dns-domain.c')
-rw-r--r--src/shared/dns-domain.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 33debadb15..40aec3a1ea 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -17,9 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_LIBIDN
-#include <idna.h>
-#include <stringprep.h>
+#if defined(HAVE_LIBIDN2)
+# include <idn2.h>
+#elif defined(HAVE_LIBIDN)
+# include <idna.h>
+# include <stringprep.h>
#endif
#include <endian.h>
@@ -299,8 +301,8 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
return r;
}
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
#ifdef HAVE_LIBIDN
+int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
_cleanup_free_ uint32_t *input = NULL;
size_t input_size, l;
const char *p;
@@ -348,13 +350,9 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
decoded[l] = 0;
return (int) l;
-#else
- return 0;
-#endif
}
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
size_t input_size, output_size;
_cleanup_free_ uint32_t *input = NULL;
_cleanup_free_ char *result = NULL;
@@ -399,10 +397,8 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
decoded[w] = 0;
return w;
-#else
- return 0;
-#endif
}
+#endif
int dns_name_concat(const char *a, const char *b, char **_ret) {
_cleanup_free_ char *ret = NULL;
@@ -1274,6 +1270,23 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
}
int dns_name_apply_idna(const char *name, char **ret) {
+ /* Return negative on error, 0 if not implemented, positive on success. */
+
+#if defined(HAVE_LIBIDN2)
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret,
+ IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+ if (r == IDN2_OK)
+ return 1; /* *ret has been written */
+ else if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
+ return -ENOSPC;
+ else
+ return -EINVAL;
+#elif defined(HAVE_LIBIDN)
_cleanup_free_ char *buf = NULL;
size_t n = 0, allocated = 0;
bool first = true;
@@ -1323,6 +1336,9 @@ int dns_name_apply_idna(const char *name, char **ret) {
buf = NULL;
return (int) n;
+#else
+ return 0;
+#endif
}
int dns_name_is_valid_or_address(const char *name) {