1 /* IDNA functions, forwarding to implementations in libidn2.
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <allocate_once.h>
21 #include <inet/net-internal.h>
24 #include <pointer_guard.h>
26 /* Use the soname and version to locate libidn2, to ensure a
28 #define LIBIDN2_SONAME "libidn2.so.0"
29 #define LIBIDN2_VERSION "IDN2_0.0.0"
31 /* Return codes from libidn2. */
38 /* Functions from libidn2. */
42 int (*lookup_ul
) (const char *src
, char **result
, int flags
);
43 int (*to_unicode_lzlz
) (const char *name
, char **result
, int flags
);
47 functions_allocate (void *closure
)
49 struct functions
*result
= malloc (sizeof (*result
));
53 void *handle
= __libc_dlopen (LIBIDN2_SONAME
);
55 /* Do not cache open failures. The library may appear
63 = __libc_dlvsym (handle
, "idn2_lookup_ul", LIBIDN2_VERSION
);
64 void *ptr_to_unicode_lzlz
65 = __libc_dlvsym (handle
, "idn2_to_unicode_lzlz", LIBIDN2_VERSION
);
66 if (ptr_lookup_ul
== NULL
|| ptr_to_unicode_lzlz
== NULL
)
68 __libc_dlclose (handle
);
73 result
->handle
= handle
;
74 result
->lookup_ul
= ptr_lookup_ul
;
75 result
->to_unicode_lzlz
= ptr_to_unicode_lzlz
;
76 PTR_MANGLE (result
->lookup_ul
);
77 PTR_MANGLE (result
->to_unicode_lzlz
);
83 functions_deallocate (void *closure
, void *ptr
)
85 struct functions
*functions
= ptr
;
86 __libc_dlclose (functions
->handle
);
90 /* Ensure that *functions is initialized and return the value of the
91 pointer. If the library cannot be loaded, return NULL. */
92 static inline struct functions
*
95 static void *functions
;
96 return allocate_once (&functions
, functions_allocate
, functions_deallocate
,
100 /* strdup with an EAI_* error code. */
102 gai_strdup (const char *name
, char **result
)
104 char *ptr
= __strdup (name
);
112 __idna_to_dns_encoding (const char *name
, char **result
)
114 switch (__idna_name_classify (name
))
116 case idna_name_ascii
:
117 /* Nothing to convert. */
118 return gai_strdup (name
, result
);
119 case idna_name_nonascii
:
120 /* Encoding needed. Handled below. */
122 case idna_name_nonascii_backslash
:
123 case idna_name_encoding_error
:
124 return EAI_IDN_ENCODE
;
125 case idna_name_memory_error
:
127 case idna_name_error
:
131 struct functions
*functions
= get_functions ();
132 if (functions
== NULL
)
133 /* We report this as an encoding error (assuming that libidn2 is
134 not installed), although the root cause may be a temporary
135 error condition due to resource shortage. */
136 return EAI_IDN_ENCODE
;
138 __typeof__ (functions
->lookup_ul
) fptr
= functions
->lookup_ul
;
140 int ret
= fptr (name
, &ptr
, 0);
143 /* Assume that idn2_free is equivalent to free. */
147 else if (ret
== IDN2_MALLOC
)
150 return EAI_IDN_ENCODE
;
152 libc_hidden_def (__idna_to_dns_encoding
)
155 __idna_from_dns_encoding (const char *name
, char **result
)
157 struct functions
*functions
= get_functions ();
158 if (functions
== NULL
)
159 /* Simply use the encoded name, assuming that it is not punycode
160 (but even a punycode name would be syntactically valid). */
161 return gai_strdup (name
, result
);
163 __typeof__ (functions
->to_unicode_lzlz
) fptr
= functions
->to_unicode_lzlz
;
165 int ret
= fptr (name
, &ptr
, 0);
168 /* Assume that idn2_free is equivalent to free. */
172 else if (ret
== IDN2_MALLOC
)
175 return EAI_IDN_ENCODE
;
177 libc_hidden_def (__idna_from_dns_encoding
)