domain-set: support punycode.

This commit is contained in:
Nick Peng
2023-12-06 22:56:48 +08:00
parent 11d92a67a1
commit 9554b3debe
7 changed files with 461 additions and 6 deletions

View File

@@ -15,8 +15,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
BIN=smartdns
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/timer_wheel.o
OBJS_MAIN=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o lib/conf.o lib/nftset.o
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/timer_wheel.o lib/idna.o lib/conf.o lib/nftset.o
OBJS_MAIN=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o
OBJS=$(OBJS_MAIN) $(OBJS_LIB)
# cflags

View File

@@ -17,6 +17,7 @@
*/
#include "dns_conf.h"
#include "idna.h"
#include "list.h"
#include "rbtree.h"
#include "tlog.h"
@@ -308,8 +309,14 @@ static int _get_domain(char *value, char *domain, int max_domain_size, char **pt
goto errout;
}
memcpy(domain, begin, len);
domain[len] = '\0';
size_t domain_len = max_domain_size;
domain_len = utf8_to_punycode(begin, len, domain, domain_len);
if (domain_len <= 0) {
tlog(TLOG_ERROR, "domain name %s invalid", value);
goto errout;
}
domain[domain_len] = '\0';
if (ptr_after_domain) {
*ptr_after_domain = end + 1;

32
src/include/idna.h Normal file
View File

@@ -0,0 +1,32 @@
/*************************************************************************
*
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
*
* smartdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* smartdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SMARTDNS_IDNA_H
#define _SMARTDNS_IDNA_H
#ifdef __cplusplus
extern "C" {
#endif
int utf8_to_punycode(const char *src, int src_len, char *dst, int dst_len);
#ifdef __cplusplus
}
#endif
#endif // !_SMARTDNS_IDNA_H

339
src/lib/idna.c Normal file
View File

@@ -0,0 +1,339 @@
/*************************************************************************
*
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
*
* smartdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* smartdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include "idna.h"
#include <limits.h>
static unsigned _utf8_decode_slow(const char **p, const char *pe, unsigned a)
{
unsigned b;
unsigned c;
unsigned d;
unsigned min;
if (a > 0xF7) {
return -1;
}
switch (pe - *p) {
default:
if (a > 0xEF) {
min = 0x10000;
a = a & 7;
b = (unsigned char)*(*p)++;
c = (unsigned char)*(*p)++;
d = (unsigned char)*(*p)++;
break;
}
case 2:
if (a > 0xDF) {
min = 0x800;
b = 0x80 | (a & 15);
c = (unsigned char)*(*p)++;
d = (unsigned char)*(*p)++;
a = 0;
break;
}
case 1:
if (a > 0xBF) {
min = 0x80;
b = 0x80;
c = 0x80 | (a & 31);
d = (unsigned char)*(*p)++;
a = 0;
break;
}
case 0:
return -1;
}
if (0x80 != (0xC0 & (b ^ c ^ d))) {
return -1;
}
b &= 63;
c &= 63;
d &= 63;
a = (a << 18) | (b << 12) | (c << 6) | d;
if (a < min) {
return -1;
}
if (a > 0x10FFFF) {
return -1;
}
if (a >= 0xD800 && a <= 0xDFFF) {
return -1;
}
return a;
}
static unsigned _utf8_decode(const char **p, const char *pe)
{
unsigned a;
a = (unsigned char)*(*p)++;
if (a < 128) {
return a;
}
return _utf8_decode_slow(p, pe, a);
}
static int _utf8_to_punycode_label(const char *s, const char *se, char **d, char *de)
{
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
const char *ss;
unsigned c;
unsigned h;
unsigned k;
unsigned n;
unsigned m;
unsigned q;
unsigned t;
unsigned x;
unsigned y;
unsigned bias;
unsigned delta;
unsigned todo;
int first;
h = 0;
ss = s;
todo = 0;
while (s < se) {
c = _utf8_decode(&s, se);
if (c == UINT_MAX) {
return -1;
}
if (c < 128) {
h++;
} else {
todo++;
}
}
if (todo > 0) {
if (*d < de) {
*(*d)++ = 'x';
}
if (*d < de) {
*(*d)++ = 'n';
}
if (*d < de) {
*(*d)++ = '-';
}
if (*d < de) {
*(*d)++ = '-';
}
}
x = 0;
s = ss;
while (s < se) {
c = _utf8_decode(&s, se);
if (c > 127) {
continue;
}
if (*d < de) {
*(*d)++ = c;
}
if (++x == h) {
break;
}
}
if (todo == 0) {
return h;
}
if (h > 0) {
if (*d < de) {
*(*d)++ = '-';
}
}
n = 128;
bias = 72;
delta = 0;
first = 1;
while (todo > 0) {
m = -1;
s = ss;
while (s < se) {
c = _utf8_decode(&s, se);
if (c >= n) {
if (c < m) {
m = c;
}
}
}
x = m - n;
y = h + 1;
if (x > ~delta / y) {
return -1;
}
delta += x * y;
n = m;
s = ss;
while (s < se) {
c = _utf8_decode(&s, se);
if (c < n) {
if (++delta == 0) {
return -1;
}
}
if (c != n) {
continue;
}
for (k = 36, q = delta;; k += 36) {
t = 1;
if (k > bias) {
t = k - bias;
}
if (t > 26) {
t = 26;
}
if (q < t) {
break;
}
x = q - t;
y = 36 - t;
q = x / y;
t = t + x % y;
if (*d < de) {
*(*d)++ = alphabet[t];
}
}
if (*d < de) {
*(*d)++ = alphabet[q];
}
delta /= 2;
if (first) {
delta /= 350;
first = 0;
}
h++;
delta += delta / h;
for (bias = 0; delta > 35 * 26 / 2; bias += 36) {
delta /= 35;
}
bias += 36 * delta / (delta + 38);
delta = 0;
todo--;
}
delta++;
n++;
}
return 0;
}
int utf8_to_punycode(const char *src, int src_len, char *dst, int dst_len)
{
const char *si;
const char *se;
const char *st;
unsigned c;
char *ds;
char *de;
int rc;
ds = dst;
si = src;
se = src + src_len;
de = dst + dst_len;
while (si < se) {
st = si;
c = _utf8_decode(&si, se);
if (c == UINT_MAX) {
return -1;
}
if (c != '.') {
if (c != 0x3002) {
if (c != 0xFF0E) {
if (c != 0xFF61) {
continue;
}
}
}
}
rc = _utf8_to_punycode_label(src, st, &dst, de);
if (rc < 0) {
return rc;
}
if (dst < de) {
*dst++ = '.';
}
src = si;
}
if (src < se) {
rc = _utf8_to_punycode_label(src, se, &dst, de);
if (rc < 0) {
return rc;
}
}
if (dst < de) {
*dst++ = '\0';
}
return dst - ds;
}

View File

@@ -1187,7 +1187,7 @@ static int _tlog_write_screen(struct tlog_log *log, struct tlog_loginfo *info, c
}
if (color != NULL) {
fprintf(stdout, "%s%s\e[0m", color, buff);
fprintf(stdout, "%s%.*s\033[0m\n", color, bufflen - 2, buff);
} else {
fprintf(stdout, "%s", buff);
}