domain-set: support punycode.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
32
src/include/idna.h
Normal 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
339
src/lib/idna.c
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user