shithub: riscv

Download patch

ref: e5e6a729ddb6956d520c87cb5905b3515323dccc
parent: d2b3e2f55a52df45c8e9c0b043763809f0001e69
parent: 33682a58857cc79b967ed37b39845f80a03f6958
author: cinap_lenrek <[email protected]>
date: Tue Sep 25 16:45:11 EDT 2018

merge

--- a/sys/include/libc.h
+++ b/sys/include/libc.h
@@ -527,6 +527,9 @@
 extern	NetConnInfo*	getnetconninfo(char*, int);
 extern	void		freenetconninfo(NetConnInfo*);
 
+extern	char*	idn2utf(char*, char*, int);
+extern	char*	utf2idn(char*, char*, int);
+
 /*
  * system calls
  *
--- a/sys/src/cmd/ip/dhcp6d.c
+++ b/sys/src/cmd/ip/dhcp6d.c
@@ -562,6 +562,7 @@
 static int
 odomainlist(uchar *w, int n, Otab *o, Req *q)
 {
+	char val[256];
 	Ndbtuple *t;
 	int l, r;
 	char *s;
@@ -570,7 +571,9 @@
 	for(t = q->t; t != nil; t = t->entry){
 		if(strcmp(t->attr, o->q[0]) != 0)
 			continue;
-		for(s = t->val; *s != 0; s++){
+		if(utf2idn(t->val, val, sizeof(val)) == nil)
+			continue;
+		for(s = val; *s != 0; s++){
 			for(l = 0; *s != 0 && *s != '.'; l++)
 				s++;
 			if(r+1+l > n)
@@ -578,6 +581,8 @@
 			w[r++] = l;
 			memmove(w+r, s-l, l);
 			r += l;
+			if(*s != '.')
+				break;
 		}
 		if(r >= n)
 			return -1;
--- a/sys/src/cmd/ip/dhcpd/dhcpd.c
+++ b/sys/src/cmd/ip/dhcpd/dhcpd.c
@@ -1584,7 +1584,7 @@
 void
 dnsnamesopt(Req *rp, int t, char *attr, Ndbtuple *nt)
 {
-	char *s;
+	char val[Maxstr], *s;
 	uchar *d;
 	int n, l;
 
@@ -1591,8 +1591,10 @@
 	for(; nt != nil; nt = nt->entry){
 		if(strcmp(nt->attr, attr) != 0)
 			continue;
+		if(utf2idn(nt->val, val, sizeof(val)) == nil)
+			continue;
 		d = &rp->p[2];
-		for(s = nt->val; *s != 0; s++){
+		for(s = val; *s != 0; s++){
 			for(l = 0; *s != 0 && *s != '.'; l++)
 				s++;
 			if(l > 077)
@@ -1602,6 +1604,8 @@
 				return;
 			d[-l-1] = l;
 			memmove(d-l, s-l, l);
+			if(*s != '.')
+				break;
 		}
 		*d++ = 0;
 		n = d - &rp->p[2];
@@ -1610,7 +1614,7 @@
 		rp->p[0] = t;
 		rp->p[1] = n;
 		rp->p = d;
-		op = seprint(op, oe, "%s(%s)", optname[t], nt->val);
+		op = seprint(op, oe, "%s(%s)", optname[t], val);
 	Skip:;
 	}
 }
--- a/sys/src/cmd/ip/dhcpd/ndb.c
+++ b/sys/src/cmd/ip/dhcpd/ndb.c
@@ -305,7 +305,8 @@
 
 	for(nt = t; nt != nil; nt = nt->entry)
 		if(strcmp(nt->attr, "dom") == 0){
-			strncpy(val, nt->val, len-1);
+			if(utf2idn(nt->val, val, len) == nil)
+				strncpy(val, nt->val, len-1);
 			val[len-1] = 0;
 			break;
 		}
--- a/sys/src/cmd/ip/ipconfig/main.c
+++ b/sys/src/cmd/ip/ipconfig/main.c
@@ -47,6 +47,9 @@
 static void	dounbind(void);
 static void	ndbconfig(void);
 
+static int	Ufmt(Fmt*);
+#pragma varargck type "U" char*
+
 void
 usage(void)
 {
@@ -61,12 +64,14 @@
 init(void)
 {
 	srand(truerand());
+
 	fmtinstall('H', encodefmt);
 	fmtinstall('E', eipfmt);
 	fmtinstall('I', eipfmt);
 	fmtinstall('M', eipfmt);
 	fmtinstall('V', eipfmt);
- 	nsec();			/* make sure time file is open before forking */
+	fmtinstall('U', Ufmt);
+	nsec();			/* make sure time file is open before forking */
 
 	conf.cfd = -1;
 	conf.rfd = -1;
@@ -193,7 +198,7 @@
 		if(p == nil || *p == 0)
 			p = sysname();
 		if(p != nil)
-			strncpy(conf.hostname, p, sizeof conf.hostname-1);
+			utf2idn(p, conf.hostname, sizeof(conf.hostname));
 	}
 
 	/* defaults */
@@ -636,11 +641,12 @@
 	char *x;
 
 	for(; *s != 0; s = x+1){
-		if((x = strchr(s, ' ')) == nil)
-			x = strchr(s, 0);
-		p = seprint(p, e, "%s=%.*s\n", attr, (int)(x - s), s);
-		if(*x == 0)
+		if((x = strchr(s, ' ')) != nil)
+			*x = 0;
+		p = seprint(p, e, "%s=%U\n", attr, s);
+		if(x == nil)
 			break;
+		*x = ' ';
 	}
 	return p;
 }
@@ -665,9 +671,9 @@
 		*np = 0;
 	}
 	if(*conf.hostname)
-		p = seprint(p, e, "\tsys=%s\n", conf.hostname);
+		p = seprint(p, e, "\tsys=%U\n", conf.hostname);
 	if(*conf.domainname)
-		p = seprint(p, e, "\tdom=%s.%s\n",
+		p = seprint(p, e, "\tdom=%U.%U\n",
 			conf.hostname, conf.domainname);
 	if(*conf.dnsdomain)
 		p = putnames(p, e, "\tdnsdomain", conf.dnsdomain);
@@ -967,6 +973,18 @@
 	return d - (de - nd);
 }
 
+static int
+Ufmt(Fmt *f)
+{
+	char d[256], *s;
+
+	s = va_arg(f->args, char*);
+	if(idn2utf(s, d, sizeof(d)) != nil)
+		s = d;
+	fmtprint(f, "%s", s);
+	return 0;
+}
+
 static Ndbtuple*
 uniquent(Ndbtuple *t)
 {
@@ -990,7 +1008,7 @@
 ndb2conf(Ndb *db, uchar *myip)
 {
 	int nattr;
-	char *attrs[10], val[64];
+	char *attrs[10], val[256];
 	uchar ip[IPaddrlen];
 	Ndbtuple *t, *nt;
 
@@ -1021,7 +1039,9 @@
 	t = ndbipinfo(db, "ip", val, attrs, nattr);
 	for(nt = t; nt != nil; nt = nt->entry) {
 		if(strcmp(nt->attr, "dnsdomain") == 0) {
-			addnames(conf.dnsdomain, nt->val, sizeof(conf.dnsdomain));
+			if(utf2idn(nt->val, val, sizeof(val)) == nil)
+				continue;
+			addnames(conf.dnsdomain, val, sizeof(conf.dnsdomain));
 			continue;
 		}
 		if(strcmp(nt->attr, "ipmask") == 0) {
--- a/sys/src/cmd/ndb/dns.h
+++ b/sys/src/cmd/ndb/dns.h
@@ -531,8 +531,4 @@
 /* convM2DNS.c */
 char*	convM2DNS(uchar*, int, DNSmsg*, int*);
 
-/* idn.c */
-char*	utf2idn(char *, char *, int);
-char*	idn2utf(char *, char *, int);
-
 #pragma varargck argpos dnslog 1
--- a/sys/src/cmd/ndb/idn.c
+++ /dev/null
@@ -1,262 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ip.h>
-#include "dns.h"
-
-enum {
-	base = 36,
-	tmin = 1,
-	tmax = 26,
-	skew = 38,
-	damp = 700,
-	initial_bias = 72,
-	initial_n = 0x80,
-};
-
-static uint maxint = ~0;
-
-static uint
-decode_digit(uint cp)
-{
-	if((cp - '0') < 10)
-		return cp - ('0' - 26);
-	if((cp - 'A') < 26)
-		return cp - 'A';
-	if((cp - 'a') < 26)
-		return cp - 'a';
-	return base;
-}
-
-static char
-encode_digit(uint d, int flag)
-{
-	if(d < 26)
-		return d + (flag ? 'A' : 'a');
-	return d + ('0' - 26);
-}
-
-static uint
-adapt(uint delta, uint numpoints, int firsttime)
-{
-	uint k;
-
-	delta = firsttime ? delta / damp : delta >> 1;
-	delta += delta / numpoints;
-	for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
-		delta /= base - tmin;
-	return k + (base - tmin + 1) * delta / (delta + skew);
-}
-
-static int
-punyencode(uint input_length, Rune input[], uint max_out, char output[])
-{
-	uint n, delta, h, b, out, bias, j, m, q, k, t;
-
-	n = initial_n;
-	delta = out = 0;
-	bias = initial_bias;
-
-	for (j = 0;  j < input_length;  ++j) {
-		if ((uint)input[j] < 0x80) {
-			if (max_out - out < 2)
-				return -1;
-			output[out++] = input[j];
-		}
-	}
-
-	h = b = out;
-
-	if (b > 0)
-		output[out++] = '-';
-
-	while (h < input_length) {
-		for (m = maxint, j = 0; j < input_length; ++j) {
-			if (input[j] >= n && input[j] < m)
-				m = input[j];
-		}
-
-		if (m - n > (maxint - delta) / (h + 1))
-			return -1;
-
-		delta += (m - n) * (h + 1);
-		n = m;
-
-		for (j = 0;  j < input_length;  ++j) {
-			if (input[j] < n) {
-				if (++delta == 0)
-					return -1;
-			}
-
-			if (input[j] == n) {
-				for (q = delta, k = base;; k += base) {
-					if (out >= max_out)
-						return -1;
-					if (k <= bias)
-						t = tmin;
-					else if (k >= bias + tmax)
-						t = tmax;
-					else
-						t = k - bias;
-					if (q < t)
-						break;
-					output[out++] = encode_digit(t + (q - t) % (base - t), 0);
-					q = (q - t) / (base - t);
-				}
-				output[out++] = encode_digit(q, isupperrune(input[j]));
-				bias = adapt(delta, h + 1, h == b);
-				delta = 0;
-				++h;
-			}
-		}
-
-		++delta, ++n;
-	}
-
-	return (int)out;
-}
-
-static int
-punydecode(uint input_length, char input[], uint max_out, Rune output[])
-{
-	uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
-
-	n = initial_n;
-	out = i = 0;
-	bias = initial_bias;
-
-	for (b = j = 0; j < input_length; ++j)
-		if (input[j] == '-')
-			b = j;
-
-	if (b > max_out)
-		return -1;
-
-	for (j = 0;  j < b;  ++j) {
-		if (input[j] & 0x80)
-			return -1;
-		output[out++] = input[j];
-	}
-
-	for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
-		for (oldi = i, w = 1, k = base;; k += base) {
-			if (in >= input_length)
-				return -1;
-			digit = decode_digit(input[in++]);
-			if (digit >= base)
-				return -1;
-			if (digit > (maxint - i) / w)
-				return -1;
-			i += digit * w;
-			if (k <= bias)
-				t = tmin;
-			else if (k >= bias + tmax)
-				t = tmax;
-			else
-				t = k - bias;
-			if (digit < t)
-				break;
-			if (w > maxint / (base - t))
-				return -1;
-			w *= (base - t);
-		}
-
-		bias = adapt(i - oldi, out + 1, oldi == 0);
-
-		if (i / (out + 1) > maxint - n)
-			return -1;
-		n += i / (out + 1);
-		i %= (out + 1);
-
-		if (out >= max_out)
-			return -1;
-
-		memmove(output + i + 1, output + i, (out - i) * sizeof *output);
-		if(((uint)input[in-1] - 'A') < 26)
-			output[i++] = toupperrune(n);
-		else
-			output[i++] = tolowerrune(n);
-	}
-
-	return (int)out;
-}
-
-/*
- * convert punycode encoded internationalized
- * domain name to unicode string
- */
-char*
-idn2utf(char *name, char *buf, int nbuf)
-{
-	char *dp, *de, *cp;
-	Rune rb[Domlen], r;
-	int nc, nr, n;
-
-	cp = name;
-	dp = buf;
-	de = dp+nbuf-1;
-	for(;;){
-		nc = nr = 0;
-		while(cp[nc] != 0){
-			n = chartorune(&r, cp+nc);
-			if(r == '.')
-				break;
-			rb[nr++] = r;
-			nc += n;
-		}
-		if(cistrncmp(cp, "xn--", 4) == 0)
-			if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
-				return nil;
-		dp = seprint(dp, de, "%.*S", nr, rb);
-		if(dp >= de)
-			return nil;
-		if(cp[nc] == 0)
-			break;
-		*dp++ = '.';
-		cp += nc+1;
-	}
-	*dp = 0;
-	return buf;
-}
-
-/*
- * convert unicode string to punycode
- * encoded internationalized domain name
- */
-char*
-utf2idn(char *name, char *buf, int nbuf)
-{
-	char *dp, *de, *cp;
-	Rune rb[Domlen], r;
-	int nc, nr, n;
-
-	dp = buf;
-	de = dp+nbuf-1;
-	cp = name;
-	for(;;){
-		nc = nr = 0;
-		while(cp[nc] != 0 && nr < nelem(rb)){
-			n = chartorune(&r, cp+nc);
-			if(r == '.')
-				break;
-			rb[nr++] = r;
-			nc += n;
-		}
-		if(nc == nr)
-			dp = seprint(dp, de, "%.*s", nc, cp);
-		else {
-			dp = seprint(dp, de, "xn--");
-			if((n = punyencode(nr, rb, de - dp, dp)) < 0)
-				return nil;
-			dp += n;
-		}
-		if(dp >= de)
-			return nil;
-		if(cp[nc] == 0)
-			break;
-		*dp++ = '.';
-		cp += nc+1;
-	}
-	*dp = 0;
-	return buf;
-}
-
--- a/sys/src/cmd/ndb/mkfile
+++ b/sys/src/cmd/ndb/mkfile
@@ -17,16 +17,16 @@
 	inform\
 
 DNSOBJ = dns.$O dnudpserver.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O dnnotify.$O\
-	 dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+	 dnarea.$O convM2DNS.$O convDNS2M.$O
 
 DNSTCPOBJ = dnstcp.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
-	 dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+	 dnarea.$O convM2DNS.$O convDNS2M.$O
 
 DNSDEBUGOBJ = dnsdebug.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
-	 dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+	 dnarea.$O convM2DNS.$O convDNS2M.$O
 
 DNSGETIPOBJ = dnsgetip.$O dn.$O dnresolve.$O dblookup.$O dnserver.$O\
-	 dnarea.$O convM2DNS.$O convDNS2M.$O idn.$O
+	 dnarea.$O convM2DNS.$O convDNS2M.$O
 
 HFILES = dns.h /$objtype/lib/libndb.a
 
--- a/sys/src/cmd/webfs/fns.h
+++ b/sys/src/cmd/webfs/fns.h
@@ -25,10 +25,6 @@
 int	matchurl(Url *u, Url *s);
 void	freeurl(Url *u);
 
-/* idn */
-char*	idn2utf(char *name, char *buf, int nbuf);
-char*	utf2idn(char *name, char *buf, int nbuf);
-
 /* buq */
 int	buread(Buq *q, void *v, int l);
 int	buwrite(Buq *q, void *v, int l);
--- a/sys/src/cmd/webfs/idn.c
+++ /dev/null
@@ -1,267 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-
-#include "dat.h"
-#include "fns.h"
-
-enum {
-	base = 36,
-	tmin = 1,
-	tmax = 26,
-	skew = 38,
-	damp = 700,
-	initial_bias = 72,
-	initial_n = 0x80,
-};
-
-static uint maxint = ~0;
-
-static uint
-decode_digit(uint cp)
-{
-	if((cp - '0') < 10)
-		return cp - ('0' - 26);
-	if((cp - 'A') < 26)
-		return cp - 'A';
-	if((cp - 'a') < 26)
-		return cp - 'a';
-	return base;
-}
-
-static char
-encode_digit(uint d, int flag)
-{
-	if(d < 26)
-		return d + (flag ? 'A' : 'a');
-	return d + ('0' - 26);
-}
-
-static uint
-adapt(uint delta, uint numpoints, int firsttime)
-{
-	uint k;
-
-	delta = firsttime ? delta / damp : delta >> 1;
-	delta += delta / numpoints;
-	for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
-		delta /= base - tmin;
-	return k + (base - tmin + 1) * delta / (delta + skew);
-}
-
-static int
-punyencode(uint input_length, Rune input[], uint max_out, char output[])
-{
-	uint n, delta, h, b, out, bias, j, m, q, k, t;
-
-	n = initial_n;
-	delta = out = 0;
-	bias = initial_bias;
-
-	for (j = 0;  j < input_length;  ++j) {
-		if ((uint)input[j] < 0x80) {
-			if (max_out - out < 2)
-				return -1;
-			output[out++] = input[j];
-		}
-	}
-
-	h = b = out;
-
-	if (b > 0)
-		output[out++] = '-';
-
-	while (h < input_length) {
-		for (m = maxint, j = 0; j < input_length; ++j) {
-			if (input[j] >= n && input[j] < m)
-				m = input[j];
-		}
-
-		if (m - n > (maxint - delta) / (h + 1))
-			return -1;
-
-		delta += (m - n) * (h + 1);
-		n = m;
-
-		for (j = 0;  j < input_length;  ++j) {
-			if (input[j] < n) {
-				if (++delta == 0)
-					return -1;
-			}
-
-			if (input[j] == n) {
-				for (q = delta, k = base;; k += base) {
-					if (out >= max_out)
-						return -1;
-					if (k <= bias)
-						t = tmin;
-					else if (k >= bias + tmax)
-						t = tmax;
-					else
-						t = k - bias;
-					if (q < t)
-						break;
-					output[out++] = encode_digit(t + (q - t) % (base - t), 0);
-					q = (q - t) / (base - t);
-				}
-				output[out++] = encode_digit(q, isupperrune(input[j]));
-				bias = adapt(delta, h + 1, h == b);
-				delta = 0;
-				++h;
-			}
-		}
-
-		++delta, ++n;
-	}
-
-	return (int)out;
-}
-
-static int
-punydecode(uint input_length, char input[], uint max_out, Rune output[])
-{
-	uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
-
-	n = initial_n;
-	out = i = 0;
-	bias = initial_bias;
-
-	for (b = j = 0; j < input_length; ++j)
-		if (input[j] == '-')
-			b = j;
-
-	if (b > max_out)
-		return -1;
-
-	for (j = 0;  j < b;  ++j) {
-		if (input[j] & 0x80)
-			return -1;
-		output[out++] = input[j];
-	}
-
-	for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
-		for (oldi = i, w = 1, k = base;; k += base) {
-			if (in >= input_length)
-				return -1;
-			digit = decode_digit(input[in++]);
-			if (digit >= base)
-				return -1;
-			if (digit > (maxint - i) / w)
-				return -1;
-			i += digit * w;
-			if (k <= bias)
-				t = tmin;
-			else if (k >= bias + tmax)
-				t = tmax;
-			else
-				t = k - bias;
-			if (digit < t)
-				break;
-			if (w > maxint / (base - t))
-				return -1;
-			w *= (base - t);
-		}
-
-		bias = adapt(i - oldi, out + 1, oldi == 0);
-
-		if (i / (out + 1) > maxint - n)
-			return -1;
-		n += i / (out + 1);
-		i %= (out + 1);
-
-		if (out >= max_out)
-			return -1;
-
-		memmove(output + i + 1, output + i, (out - i) * sizeof *output);
-		if(((uint)input[in-1] - 'A') < 26)
-			output[i++] = toupperrune(n);
-		else
-			output[i++] = tolowerrune(n);
-	}
-
-	return (int)out;
-}
-
-/*
- * convert punycode encoded internationalized
- * domain name to unicode string
- */
-char*
-idn2utf(char *name, char *buf, int nbuf)
-{
-	char *dp, *de, *cp;
-	Rune rb[Domlen], r;
-	int nc, nr, n;
-
-	cp = name;
-	dp = buf;
-	de = dp+nbuf-1;
-	for(;;){
-		nc = nr = 0;
-		while(cp[nc] != 0){
-			n = chartorune(&r, cp+nc);
-			if(r == '.')
-				break;
-			rb[nr++] = r;
-			nc += n;
-		}
-		if(cistrncmp(cp, "xn--", 4) == 0)
-			if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
-				return nil;
-		dp = seprint(dp, de, "%.*S", nr, rb);
-		if(dp >= de)
-			return nil;
-		if(cp[nc] == 0)
-			break;
-		*dp++ = '.';
-		cp += nc+1;
-	}
-	*dp = 0;
-	return buf;
-}
-
-/*
- * convert unicode string to punycode
- * encoded internationalized domain name
- */
-char*
-utf2idn(char *name, char *buf, int nbuf)
-{
-	char *dp, *de, *cp;
-	Rune rb[Domlen], r;
-	int nc, nr, n;
-
-	dp = buf;
-	de = dp+nbuf-1;
-	cp = name;
-	for(;;){
-		nc = nr = 0;
-		while(cp[nc] != 0 && nr < nelem(rb)){
-			n = chartorune(&r, cp+nc);
-			if(r == '.')
-				break;
-			rb[nr++] = r;
-			nc += n;
-		}
-		if(nc == nr)
-			dp = seprint(dp, de, "%.*s", nc, cp);
-		else {
-			dp = seprint(dp, de, "xn--");
-			if((n = punyencode(nr, rb, de - dp, dp)) < 0)
-				return nil;
-			dp += n;
-		}
-		if(dp >= de)
-			return nil;
-		if(cp[nc] == 0)
-			break;
-		*dp++ = '.';
-		cp += nc+1;
-	}
-	*dp = 0;
-	return buf;
-}
-
--- a/sys/src/cmd/webfs/mkfile
+++ b/sys/src/cmd/webfs/mkfile
@@ -3,6 +3,6 @@
 TARG=webfs
 
 HFILES=fns.h dat.h
-OFILES=sub.$O url.$O buq.$O http.$O fs.$O idn.$O
+OFILES=sub.$O url.$O buq.$O http.$O fs.$O
 
 </sys/src/cmd/mkone
--- a/sys/src/cmd/webfs/url.c
+++ b/sys/src/cmd/webfs/url.c
@@ -73,15 +73,12 @@
 int
 Nfmt(Fmt *f)
 {
-	char *d, *s;
+	char d[Domlen], *s;
 
 	s = va_arg(f->args, char*);
-	d = emalloc(Domlen);
-	if(utf2idn(s, d, Domlen) == nil)
-		d = s;
-	fmtprint(f, "%s", d);
-	if(d != s)
-		free(d);
+	if(utf2idn(s, d, sizeof(d)) != nil)
+		s = d;
+	fmtprint(f, "%s", s);
 	return 0;
 }
 
--- /dev/null
+++ b/sys/src/libc/9sys/idn.c
@@ -1,0 +1,262 @@
+#include <u.h>
+#include <libc.h>
+
+enum {
+	base = 36,
+	tmin = 1,
+	tmax = 26,
+	skew = 38,
+	damp = 700,
+	initial_bias = 72,
+	initial_n = 0x80,
+
+	Domlen = 256,
+};
+
+static uint maxint = ~0;
+
+static uint
+decode_digit(uint cp)
+{
+	if((cp - '0') < 10)
+		return cp - ('0' - 26);
+	if((cp - 'A') < 26)
+		return cp - 'A';
+	if((cp - 'a') < 26)
+		return cp - 'a';
+	return base;
+}
+
+static char
+encode_digit(uint d, int flag)
+{
+	if(d < 26)
+		return d + (flag ? 'A' : 'a');
+	return d + ('0' - 26);
+}
+
+static uint
+adapt(uint delta, uint numpoints, int firsttime)
+{
+	uint k;
+
+	delta = firsttime ? delta / damp : delta >> 1;
+	delta += delta / numpoints;
+	for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
+		delta /= base - tmin;
+	return k + (base - tmin + 1) * delta / (delta + skew);
+}
+
+static int
+punyencode(uint input_length, Rune input[], uint max_out, char output[])
+{
+	uint n, delta, h, b, out, bias, j, m, q, k, t;
+
+	n = initial_n;
+	delta = out = 0;
+	bias = initial_bias;
+
+	for (j = 0;  j < input_length;  ++j) {
+		if ((uint)input[j] < 0x80) {
+			if (max_out - out < 2)
+				return -1;
+			output[out++] = input[j];
+		}
+	}
+
+	h = b = out;
+
+	if (b > 0)
+		output[out++] = '-';
+
+	while (h < input_length) {
+		for (m = maxint, j = 0; j < input_length; ++j) {
+			if (input[j] >= n && input[j] < m)
+				m = input[j];
+		}
+
+		if (m - n > (maxint - delta) / (h + 1))
+			return -1;
+
+		delta += (m - n) * (h + 1);
+		n = m;
+
+		for (j = 0;  j < input_length;  ++j) {
+			if (input[j] < n) {
+				if (++delta == 0)
+					return -1;
+			}
+
+			if (input[j] == n) {
+				for (q = delta, k = base;; k += base) {
+					if (out >= max_out)
+						return -1;
+					if (k <= bias)
+						t = tmin;
+					else if (k >= bias + tmax)
+						t = tmax;
+					else
+						t = k - bias;
+					if (q < t)
+						break;
+					output[out++] = encode_digit(t + (q - t) % (base - t), 0);
+					q = (q - t) / (base - t);
+				}
+				output[out++] = encode_digit(q, isupperrune(input[j]));
+				bias = adapt(delta, h + 1, h == b);
+				delta = 0;
+				++h;
+			}
+		}
+
+		++delta, ++n;
+	}
+
+	return (int)out;
+}
+
+static int
+punydecode(uint input_length, char input[], uint max_out, Rune output[])
+{
+	uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
+
+	n = initial_n;
+	out = i = 0;
+	bias = initial_bias;
+
+	for (b = j = 0; j < input_length; ++j)
+		if (input[j] == '-')
+			b = j;
+
+	if (b > max_out)
+		return -1;
+
+	for (j = 0;  j < b;  ++j) {
+		if (input[j] & 0x80)
+			return -1;
+		output[out++] = input[j];
+	}
+
+	for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
+		for (oldi = i, w = 1, k = base;; k += base) {
+			if (in >= input_length)
+				return -1;
+			digit = decode_digit(input[in++]);
+			if (digit >= base)
+				return -1;
+			if (digit > (maxint - i) / w)
+				return -1;
+			i += digit * w;
+			if (k <= bias)
+				t = tmin;
+			else if (k >= bias + tmax)
+				t = tmax;
+			else
+				t = k - bias;
+			if (digit < t)
+				break;
+			if (w > maxint / (base - t))
+				return -1;
+			w *= (base - t);
+		}
+
+		bias = adapt(i - oldi, out + 1, oldi == 0);
+
+		if (i / (out + 1) > maxint - n)
+			return -1;
+		n += i / (out + 1);
+		i %= (out + 1);
+
+		if (out >= max_out)
+			return -1;
+
+		memmove(output + i + 1, output + i, (out - i) * sizeof *output);
+		if(((uint)input[in-1] - 'A') < 26)
+			output[i++] = toupperrune(n);
+		else
+			output[i++] = tolowerrune(n);
+	}
+
+	return (int)out;
+}
+
+/*
+ * convert punycode encoded internationalized
+ * domain name to unicode string
+ */
+char*
+idn2utf(char *name, char *buf, int nbuf)
+{
+	char *dp, *de, *cp;
+	Rune rb[Domlen], r;
+	int nc, nr, n;
+
+	cp = name;
+	dp = buf;
+	de = dp+nbuf-1;
+	for(;;){
+		nc = nr = 0;
+		while(cp[nc] != 0){
+			n = chartorune(&r, cp+nc);
+			if(r == '.')
+				break;
+			rb[nr++] = r;
+			nc += n;
+		}
+		if(cistrncmp(cp, "xn--", 4) == 0)
+			if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
+				return nil;
+		dp = seprint(dp, de, "%.*S", nr, rb);
+		if(dp >= de)
+			return nil;
+		if(cp[nc] == 0)
+			break;
+		*dp++ = '.';
+		cp += nc+1;
+	}
+	*dp = 0;
+	return buf;
+}
+
+/*
+ * convert unicode string to punycode
+ * encoded internationalized domain name
+ */
+char*
+utf2idn(char *name, char *buf, int nbuf)
+{
+	char *dp, *de, *cp;
+	Rune rb[Domlen], r;
+	int nc, nr, n;
+
+	dp = buf;
+	de = dp+nbuf-1;
+	cp = name;
+	for(;;){
+		nc = nr = 0;
+		while(cp[nc] != 0 && nr < nelem(rb)){
+			n = chartorune(&r, cp+nc);
+			if(r == '.')
+				break;
+			rb[nr++] = r;
+			nc += n;
+		}
+		if(nc == nr)
+			dp = seprint(dp, de, "%.*s", nc, cp);
+		else {
+			dp = seprint(dp, de, "xn--");
+			if((n = punyencode(nr, rb, de - dp, dp)) < 0)
+				return nil;
+			dp += n;
+		}
+		if(dp >= de)
+			return nil;
+		if(cp[nc] == 0)
+			break;
+		*dp++ = '.';
+		cp += nc+1;
+	}
+	*dp = 0;
+	return buf;
+}
+
--- a/sys/src/libc/9sys/mkfile
+++ b/sys/src/libc/9sys/mkfile
@@ -25,6 +25,7 @@
 	getpid.$O\
 	getppid.$O\
 	getwd.$O\
+	idn.$O\
 	iounit.$O\
 	nsec.$O\
 	nulldir.$O\