Blame


1 7957cbd9 2021-01-27 op /*
2 7957cbd9 2021-01-27 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 7957cbd9 2021-01-27 op *
4 7957cbd9 2021-01-27 op * Permission to use, copy, modify, and distribute this software for any
5 7957cbd9 2021-01-27 op * purpose with or without fee is hereby granted, provided that the above
6 7957cbd9 2021-01-27 op * copyright notice and this permission notice appear in all copies.
7 7957cbd9 2021-01-27 op *
8 7957cbd9 2021-01-27 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 7957cbd9 2021-01-27 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 7957cbd9 2021-01-27 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 7957cbd9 2021-01-27 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 7957cbd9 2021-01-27 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 7957cbd9 2021-01-27 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 7957cbd9 2021-01-27 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 7957cbd9 2021-01-27 op */
16 7957cbd9 2021-01-27 op
17 7957cbd9 2021-01-27 op #include <stddef.h>
18 7957cbd9 2021-01-27 op #include <stdint.h>
19 7957cbd9 2021-01-27 op #include <string.h>
20 7957cbd9 2021-01-27 op
21 7957cbd9 2021-01-27 op #include "gmid.h"
22 7957cbd9 2021-01-27 op
23 7957cbd9 2021-01-27 op #define BASE 36
24 7957cbd9 2021-01-27 op #define TMIN 1
25 7957cbd9 2021-01-27 op #define TMAX 26
26 7957cbd9 2021-01-27 op #define SKEW 38
27 7957cbd9 2021-01-27 op #define DAMP 700
28 7957cbd9 2021-01-27 op #define IBIAS 72
29 7957cbd9 2021-01-27 op #define IN 128
30 7957cbd9 2021-01-27 op
31 3abf91b0 2021-02-07 op /* to make the linker happy */
32 3abf91b0 2021-02-07 op struct conf conf;
33 3abf91b0 2021-02-07 op
34 7957cbd9 2021-01-27 op static int
35 7957cbd9 2021-01-27 op adapt(int delta, int numpoints, int firsttime)
36 7957cbd9 2021-01-27 op {
37 7957cbd9 2021-01-27 op int k;
38 7957cbd9 2021-01-27 op
39 7957cbd9 2021-01-27 op if (firsttime)
40 7957cbd9 2021-01-27 op delta = delta / DAMP;
41 7957cbd9 2021-01-27 op else
42 7957cbd9 2021-01-27 op delta = delta / 2;
43 7957cbd9 2021-01-27 op
44 7957cbd9 2021-01-27 op delta += (delta / numpoints);
45 7957cbd9 2021-01-27 op
46 7957cbd9 2021-01-27 op k = 0;
47 7957cbd9 2021-01-27 op while (delta > ((BASE - TMIN) * TMAX) / 2) {
48 7957cbd9 2021-01-27 op delta = delta / (BASE - TMIN);
49 7957cbd9 2021-01-27 op k += BASE;
50 7957cbd9 2021-01-27 op }
51 7957cbd9 2021-01-27 op return k + (((BASE - TMIN + 1) * delta) / (delta + SKEW));
52 7957cbd9 2021-01-27 op }
53 7957cbd9 2021-01-27 op
54 7957cbd9 2021-01-27 op static const char *
55 35cf19e3 2021-01-28 op copy_label(const char *s, char *out, size_t len)
56 7957cbd9 2021-01-27 op {
57 7957cbd9 2021-01-27 op char *end, *t;
58 0cd66754 2021-01-27 op size_t l;
59 7957cbd9 2021-01-27 op
60 7957cbd9 2021-01-27 op end = strchr(s, '\0');
61 0cd66754 2021-01-27 op l = end - s;
62 0cd66754 2021-01-27 op if (l > len)
63 7957cbd9 2021-01-27 op return NULL;
64 7957cbd9 2021-01-27 op
65 7957cbd9 2021-01-27 op for (t = end; t >= s; --t)
66 7957cbd9 2021-01-27 op if (*t == '-')
67 7957cbd9 2021-01-27 op break;
68 7957cbd9 2021-01-27 op
69 7957cbd9 2021-01-27 op if (t < s)
70 7957cbd9 2021-01-27 op t = end;
71 7957cbd9 2021-01-27 op
72 7957cbd9 2021-01-27 op for (; s < t; ++s, ++out) {
73 7957cbd9 2021-01-27 op if (*s > 'z')
74 7957cbd9 2021-01-27 op return NULL;
75 7957cbd9 2021-01-27 op *out = *s;
76 7957cbd9 2021-01-27 op }
77 7957cbd9 2021-01-27 op
78 7957cbd9 2021-01-27 op return s;
79 7957cbd9 2021-01-27 op }
80 7957cbd9 2021-01-27 op
81 7957cbd9 2021-01-27 op static unsigned int
82 7957cbd9 2021-01-27 op digit_value(char c)
83 7957cbd9 2021-01-27 op {
84 7957cbd9 2021-01-27 op if ('A' <= c && c <= 'Z')
85 7957cbd9 2021-01-27 op return c - 'A';
86 7957cbd9 2021-01-27 op
87 7957cbd9 2021-01-27 op if ('a' <= c && c <= 'z')
88 7957cbd9 2021-01-27 op return c - 'a';
89 7957cbd9 2021-01-27 op
90 7957cbd9 2021-01-27 op if ('0' <= c && c <= '9')
91 7957cbd9 2021-01-27 op return 26 + c - '0';
92 7957cbd9 2021-01-27 op
93 7957cbd9 2021-01-27 op return c;
94 7957cbd9 2021-01-27 op }
95 7957cbd9 2021-01-27 op
96 7957cbd9 2021-01-27 op static int
97 4a3ab609 2021-01-29 op insert(char *out, size_t len, int codepoint, size_t i, const char **err)
98 7957cbd9 2021-01-27 op {
99 7957cbd9 2021-01-27 op int l;
100 7957cbd9 2021-01-27 op char *t;
101 7957cbd9 2021-01-27 op
102 a2fd8013 2021-01-29 op if (codepoint <= 0x7F) {
103 a2fd8013 2021-01-29 op *err = "puny: invalid decoded character (ASCII range)";
104 7957cbd9 2021-01-27 op return 0;
105 a2fd8013 2021-01-29 op } else if (codepoint <= 0x7FF) {
106 7957cbd9 2021-01-27 op l = 2;
107 a2fd8013 2021-01-29 op } else if (codepoint <= 0xFFFF) {
108 7957cbd9 2021-01-27 op l = 3;
109 a2fd8013 2021-01-29 op } else if (codepoint <= 0x10FFFF) {
110 7957cbd9 2021-01-27 op l = 4;
111 a2fd8013 2021-01-29 op } else {
112 a2fd8013 2021-01-29 op *err = "puny: invalid decoded character";
113 7957cbd9 2021-01-27 op return 0;
114 a2fd8013 2021-01-29 op }
115 7957cbd9 2021-01-27 op
116 a2fd8013 2021-01-29 op if ((t = utf8_nth(out, i)) == NULL) {
117 a2fd8013 2021-01-29 op *err = "puny: invalid insert position";
118 7957cbd9 2021-01-27 op return 0;
119 a2fd8013 2021-01-29 op }
120 a2fd8013 2021-01-29 op
121 a2fd8013 2021-01-29 op if (t + l >= out + len) {
122 a2fd8013 2021-01-29 op *err = "puny: insert would overflow";
123 7957cbd9 2021-01-27 op return 0;
124 a2fd8013 2021-01-29 op }
125 7957cbd9 2021-01-27 op
126 7957cbd9 2021-01-27 op memmove(t + l, t, strlen(t));
127 7957cbd9 2021-01-27 op
128 7957cbd9 2021-01-27 op switch (l) {
129 7957cbd9 2021-01-27 op case 2:
130 7957cbd9 2021-01-27 op t[1] = ( codepoint & 0x3F) + 0x80;
131 35cf19e3 2021-01-28 op t[0] = ((codepoint >> 6) & 0x1F) + 0xC0;
132 7957cbd9 2021-01-27 op break;
133 7957cbd9 2021-01-27 op case 3:
134 7957cbd9 2021-01-27 op t[2] = ( codepoint & 0x3F) + 0x80;
135 35cf19e3 2021-01-28 op t[1] = ((codepoint >> 6) & 0x3F) + 0x80;
136 7957cbd9 2021-01-27 op t[0] = ((codepoint >> 12) & 0x0F) + 0xE0;
137 7957cbd9 2021-01-27 op break;
138 7957cbd9 2021-01-27 op case 4:
139 7957cbd9 2021-01-27 op t[3] = ( codepoint & 0x3F) + 0x80;
140 35cf19e3 2021-01-28 op t[2] = ((codepoint >> 6) & 0x3F) + 0x80;
141 7957cbd9 2021-01-27 op t[1] = ((codepoint >> 12) & 0x3F) + 0x80;
142 7957cbd9 2021-01-27 op t[0] = ((codepoint >> 18) & 0x07) + 0xF0;
143 7957cbd9 2021-01-27 op break;
144 7957cbd9 2021-01-27 op }
145 7957cbd9 2021-01-27 op return 1;
146 7957cbd9 2021-01-27 op }
147 7957cbd9 2021-01-27 op
148 7957cbd9 2021-01-27 op static int
149 a2fd8013 2021-01-29 op decode(const char *str, char *out, size_t len, const char **err)
150 7957cbd9 2021-01-27 op {
151 7957cbd9 2021-01-27 op size_t i;
152 7957cbd9 2021-01-27 op uint32_t n;
153 7957cbd9 2021-01-27 op unsigned int oldi, bias, w, k, digit, t;
154 7957cbd9 2021-01-27 op unsigned int numpoints;
155 7957cbd9 2021-01-27 op const char *s;
156 7957cbd9 2021-01-27 op
157 44ee1bac 2021-01-27 op if (!starts_with(str, "xn--")) {
158 7957cbd9 2021-01-27 op strncpy(out, str, len);
159 7957cbd9 2021-01-27 op return 1;
160 7957cbd9 2021-01-27 op }
161 7957cbd9 2021-01-27 op
162 7957cbd9 2021-01-27 op /* skip the xn-- */
163 7957cbd9 2021-01-27 op str += 4;
164 7957cbd9 2021-01-27 op
165 7957cbd9 2021-01-27 op if (strchr(str, '-') != NULL) {
166 a2fd8013 2021-01-29 op if ((s = copy_label(str, out, len)) == NULL) {
167 a2fd8013 2021-01-29 op *err = "puny: invalid label";
168 7957cbd9 2021-01-27 op return 0;
169 a2fd8013 2021-01-29 op }
170 7957cbd9 2021-01-27 op if (*s == '-')
171 7957cbd9 2021-01-27 op s++;
172 7957cbd9 2021-01-27 op } else
173 7957cbd9 2021-01-27 op s = str;
174 7957cbd9 2021-01-27 op
175 7957cbd9 2021-01-27 op numpoints = strlen(out);
176 7957cbd9 2021-01-27 op
177 7957cbd9 2021-01-27 op n = IN;
178 7957cbd9 2021-01-27 op i = 0;
179 7957cbd9 2021-01-27 op bias = IBIAS;
180 7957cbd9 2021-01-27 op
181 7957cbd9 2021-01-27 op while (*s != '\0') {
182 7957cbd9 2021-01-27 op oldi = i;
183 7957cbd9 2021-01-27 op w = 1;
184 7957cbd9 2021-01-27 op
185 7957cbd9 2021-01-27 op for (k = BASE; ; k += BASE) {
186 a2fd8013 2021-01-29 op if (*s == '\0') {
187 a2fd8013 2021-01-29 op *err = "puny: label truncated?";
188 7957cbd9 2021-01-27 op return 0;
189 a2fd8013 2021-01-29 op }
190 7957cbd9 2021-01-27 op /* fail eventually? */
191 7957cbd9 2021-01-27 op digit = digit_value(*s);
192 7957cbd9 2021-01-27 op s++;
193 7957cbd9 2021-01-27 op
194 7957cbd9 2021-01-27 op /* fail on overflow */
195 7957cbd9 2021-01-27 op i += digit * w;
196 7957cbd9 2021-01-27 op
197 7957cbd9 2021-01-27 op if (k <= bias)
198 7957cbd9 2021-01-27 op t = TMIN;
199 7957cbd9 2021-01-27 op else if (k >= bias + TMAX)
200 7957cbd9 2021-01-27 op t = TMAX;
201 7957cbd9 2021-01-27 op else
202 7957cbd9 2021-01-27 op t = k - bias;
203 7957cbd9 2021-01-27 op
204 7957cbd9 2021-01-27 op if (digit < t)
205 7957cbd9 2021-01-27 op break;
206 7957cbd9 2021-01-27 op w *= (BASE - t);
207 7957cbd9 2021-01-27 op }
208 7957cbd9 2021-01-27 op
209 7957cbd9 2021-01-27 op bias = adapt(i - oldi, numpoints+1, oldi == 0);
210 7957cbd9 2021-01-27 op n += i / (numpoints+1); /* fail on overflow */
211 7957cbd9 2021-01-27 op i = i % (numpoints+1);
212 7957cbd9 2021-01-27 op
213 4a3ab609 2021-01-29 op if (!insert(out, len, n, i, err))
214 7957cbd9 2021-01-27 op return 0;
215 7957cbd9 2021-01-27 op numpoints++;
216 7957cbd9 2021-01-27 op ++i;
217 7957cbd9 2021-01-27 op }
218 7957cbd9 2021-01-27 op
219 7957cbd9 2021-01-27 op return 1;
220 7957cbd9 2021-01-27 op }
221 7957cbd9 2021-01-27 op
222 0cd66754 2021-01-27 op static const char *
223 35cf19e3 2021-01-28 op end_of_label(const char *hostname)
224 7957cbd9 2021-01-27 op {
225 7957cbd9 2021-01-27 op for (; *hostname != '\0' && *hostname != '.'; ++hostname)
226 7957cbd9 2021-01-27 op ; /* nop */
227 7957cbd9 2021-01-27 op return hostname;
228 7957cbd9 2021-01-27 op }
229 7957cbd9 2021-01-27 op
230 7957cbd9 2021-01-27 op int
231 a2fd8013 2021-01-29 op puny_decode(const char *hostname, char *out, size_t len, const char **err)
232 7957cbd9 2021-01-27 op {
233 35cf19e3 2021-01-28 op char label[LABEL_LEN];
234 7957cbd9 2021-01-27 op const char *s, *end;
235 7957cbd9 2021-01-27 op size_t l;
236 7957cbd9 2021-01-27 op
237 7957cbd9 2021-01-27 op memset(out, 0, len);
238 44ee1bac 2021-01-27 op if (hostname == NULL)
239 44ee1bac 2021-01-27 op return 1;
240 7957cbd9 2021-01-27 op
241 7957cbd9 2021-01-27 op s = hostname;
242 7957cbd9 2021-01-27 op for (;;) {
243 415ac7a2 2021-01-28 op end = end_of_label(s);
244 0cd66754 2021-01-27 op l = end - s;
245 a2fd8013 2021-01-29 op if (l >= sizeof(label)) {
246 a2fd8013 2021-01-29 op *err = "label too long";
247 7957cbd9 2021-01-27 op return 0;
248 a2fd8013 2021-01-29 op }
249 7957cbd9 2021-01-27 op
250 35cf19e3 2021-01-28 op memcpy(label, s, l);
251 35cf19e3 2021-01-28 op label[l] = '\0';
252 7957cbd9 2021-01-27 op
253 a2fd8013 2021-01-29 op if (!decode(label, out, len, err))
254 7957cbd9 2021-01-27 op return 0;
255 7957cbd9 2021-01-27 op
256 7957cbd9 2021-01-27 op if (*end == '\0')
257 7957cbd9 2021-01-27 op return 1;
258 7957cbd9 2021-01-27 op
259 a2fd8013 2021-01-29 op if (strlcat(out, ".", len) >= len) {
260 a2fd8013 2021-01-29 op *err = "domain name too long";
261 7957cbd9 2021-01-27 op return 0;
262 a2fd8013 2021-01-29 op }
263 7957cbd9 2021-01-27 op
264 7957cbd9 2021-01-27 op l = strlen(out);
265 a2fd8013 2021-01-29 op if (l >= len) {
266 a2fd8013 2021-01-29 op *err = "domain name too long";
267 7957cbd9 2021-01-27 op return 0;
268 a2fd8013 2021-01-29 op }
269 7957cbd9 2021-01-27 op out += l;
270 7957cbd9 2021-01-27 op len -= l;
271 7957cbd9 2021-01-27 op
272 7957cbd9 2021-01-27 op s = end+1;
273 7957cbd9 2021-01-27 op }
274 7957cbd9 2021-01-27 op }