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