shithub: riscv

Download patch

ref: d75f7d273bbb71e03ef141b88269c1d047805546
parent: a0acae173ee17ddf101a4e57eb4030c9fead13b3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Mar 10 15:07:58 EDT 2019

ip/tinc: 4096 bit RSA, (passive) pmtu discovery, fix udpfd close() race, cleanup

- increase buffer size to support up to 4096 bit RSA keys
- handle PMTUDiscovery option and respond to pmtu probes
- handle port in Address option
- wlock(&netlk) before closing udpfd to sync with writers
- move default subnet handling out of gethost()

--- a/sys/src/cmd/ip/tinc.c
+++ b/sys/src/cmd/ip/tinc.c
@@ -177,6 +177,7 @@
 
 int	consend(Conn *c, char *fmt, ...);
 #pragma varargck argpos consend 2
+int	sendudp(Host *h, int fd, uchar *p, int n);
 void	routepkt(Host *s, uchar *p, int n);
 void	needkey(Host *from);
 void	clearkey(Host *from);
@@ -624,47 +625,50 @@
 	for(h = hosts; h != nil; h = h->next)
 		if(strcmp(h->name, name) == 0)
 			goto out;
+
+	n = -1;
 	snprint(buf, sizeof(buf), "hosts/%s", name);
-	if((fd = open(buf, OREAD)) < 0){
-		if(!new)
-			goto out;
-		buf[0] = 0;
-	} else {
+	if((fd = open(buf, OREAD)) >= 0){
 		n = read(fd, buf, sizeof(buf)-1);
 		close(fd);
-		if(n <= 0)
+	}
+	if(n < 0){
+		if(!new)
 			goto out;
-		buf[n] = 0;
+		n = 0;
 	}
+	buf[n] = 0;
+
 	h = emalloc(sizeof(Host));
 	h->name = estrdup(name);
 	h->addr = estrdup(name);
 	h->port = 655;
 	h->pmtu = DefPMTU;
-	h->options = OptClampMss;
+	h->options = OptClampMss|OptPmtuDiscov;
 	h->udpfd = -1;
 	h->connected = 0;
+	h->rsapub = nil;
 	h->next = hosts;
 	hosts = h;
-	if((s = (char*)decodePEM(buf, "RSA PUBLIC KEY", &n, nil)) == nil)
-		goto out;
-	h->rsapub = asn1toRSApub((uchar*)s, n);
-	free(s);
-	if(h->rsapub == nil)
-		goto out;
+	if((s = (char*)decodePEM(buf, "RSA PUBLIC KEY", &n, nil)) != nil){
+		h->rsapub = asn1toRSApub((uchar*)s, n);
+		free(s);
+	}
 	for(s = buf; s != nil; s = e){
 		char *f[2];
 
 		if((e = strchr(s, '\n')) != nil)
 			*e++ = 0;
-		if((x = strchr(s, '=')) == nil)
+		if(*s == '#' || (x = strchr(s, '=')) == nil)
 			continue;
 		*x = ' ';
-		if((n = tokenize(s, f, nelem(f))) != 2)
+		if((n = tokenize(s, f, 2)) != 2)
 			continue;
 		if(cistrcmp(f[0], "Address") == 0){
+			if(tokenize(f[1], f, 2) > 1)
+				h->port = atoi(f[1]);
 			free(h->addr);
-			h->addr = estrdup(f[1]);
+			h->addr = estrdup(f[0]);
 			continue;
 		}
 		if(cistrcmp(f[0], "IndirectData") == 0){
@@ -679,6 +683,10 @@
 			h->options &= ~(OptClampMss*(cistrcmp(f[1], "no") == 0));
 			continue;
 		}
+		if(cistrcmp(f[0], "PMTUDiscovery") == 0){
+			h->options &= ~(OptPmtuDiscov*(cistrcmp(f[1], "no") == 0));
+			continue;
+		}
 		if(cistrcmp(f[0], "PMTU") == 0){
 			h->pmtu = atoi(f[1]);
 			if(h->pmtu > MaxPacket)
@@ -697,10 +705,6 @@
 			continue;
 		}
 	}
-	if(myhost == nil && h->snet == nil){
-		snprint(buf, sizeof(buf), "%I/%d", localip, isv4(localip) ? 32 : 128);
-		getsubnet(h, buf, 1);
-	}
 	parseip(h->ip, h->addr);
 out:
 	qunlock(&hostslk);
@@ -861,7 +865,7 @@
 	}
 	memmove(cs, h->cin->cs, sizeof(cs));
 	(*h->cin->crypt)(buf, n, cs);
-	if((n -= buf[n-1]) < 4+EtherHdr){
+	if((n -= buf[n-1]) < 4){
 		unlock(h->cin);
 		return -1;
 	}
@@ -885,11 +889,20 @@
 	h->udpfd = fd;
 	unlock(h->cin);
 
+	/* pmtu probe */
+	if(n >= 4+14 && buf[4+12] == 0 && buf[4+13] == 0){
+		if(buf[4+0] == 0){
+			buf[4+0] = 1;
+			sendudp(h, fd, buf+4, n-4);
+		}
+		return 0;
+	}
+
 	routepkt(h, buf+4, n-4);
 	return 0;
 }
 int
-sendudp(Host *h, uchar *p, int n)
+sendudp(Host *h, int fd, uchar *p, int n)
 {
 	uchar buf[4+MaxPacket+AESbsize+SHA2_256dlen];
 	AESstate cs[1];
@@ -896,7 +909,7 @@
 	uint seq;
 	int pad;
 
-	if(h->udpfd < 0 || n > MaxPacket || n > h->pmtu)
+	if(fd < 0 || n > MaxPacket)
 		return -1;
 	lock(h->cout);
 	if(h->cout->crypt == nil){
@@ -919,7 +932,7 @@
 	hmac_sha2_256(buf, n, h->cout->key, sizeof(h->cout->key), buf+n, nil);
 	unlock(h->cout);
 	n += MAClen;
-	if(write(h->udpfd, buf, n) != n)
+	if(write(fd, buf, n) != n)
 		return -1;
 	if((seq & 0xFFFFF) == 0) needkey(h);
 	return 0;
@@ -951,7 +964,7 @@
 	if(d->from == nil)
 		return;
 	while(d != s && d != myhost){
-		if(sendudp(d, p, n) == 0)
+		if(n <= d->pmtu && sendudp(d, d->udpfd, p, n) == 0)
 			return;
 		if(sendtcp(d, p, n) == 0)
 			return;
@@ -1085,7 +1098,7 @@
 metaauth(Conn *c)
 {
 	mpint *m, *h;
-	uchar b[256];
+	uchar b[512];
 	AuthRpc *rpc;
 	char *f[8];
 	int n, n1, n2, ms;
@@ -1403,8 +1416,8 @@
 	procsetname("tcpclient %s %s %s %I!%d", myhost->name,
 		incoming ? "in" : "out", dir, c->ip, c->port);
 	if(metaauth(c) == 0){
-		procsetname("tcpclient %s %s %I!%d %s", myhost->name,
-			dir, c->ip, c->port, c->host->name);
+		procsetname("tcpclient %s %s %s %I!%d %s", myhost->name,
+			incoming ? "in" : "out", dir, c->ip, c->port, c->host->name);
 		metapeer(c);
 	}
 	netlock(c);
@@ -1429,8 +1442,8 @@
 	char dir[128];
 	Host *h;
 
-	if((h = findhost(ip, dir2ipport(fd2dir(fd, dir, sizeof(dir)), ip))) != nil
-	&& h != myhost){
+	h = findhost(ip, dir2ipport(fd2dir(fd, dir, sizeof(dir)), ip));
+	if(h != nil && h != myhost){
 		procsetname("udpclient %s %s %s %I!%d %s", myhost->name,
 			incoming ? "in": "out", dir, h->ip, h->port, h->name);
 
@@ -1449,6 +1462,9 @@
 		if(h->udpfd == fd)
 			h->udpfd = -1;
 		unlock(h->cin);
+
+		wlock(&netlk);
+		wunlock(&netlk);
 	}
 	close(fd);
 }
@@ -1656,6 +1672,11 @@
 			sysfatal("no RSA public key for: %s", h->name);
 	}
 
+	if(myhost->snet == nil){
+		char snet[64];
+		snprint(snet, sizeof(snet), "%I/128", localip);
+		getsubnet(myhost, snet, 1);
+	}
 	if((t = lookupnet(localip)) == nil)
 		sysfatal("no subnet found for local ip %I", localip);
 	if(t->owner != myhost)