ref: 14da3b8a1ff5d1643e2cd0482976d5092d476fc5
parent: 57284d07ca8bf02e4e8afacc5f9fd78f22c281de
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Mar 4 15:29:33 EST 2019
ip/tinc: honor TcpOnly and IndirectData settings, script support, prefer incoming udp connections only try listen/dial on udp when IndirectData/TcpOnly is not enabled. add support for scipts: host-up host-down tinc-up tinc-down subnet-up subnet-down when dialing udp connection, only switch when there is no other udp connection active. when we receive an authenticated message, we switch to that connection immidiately.
--- a/sys/src/cmd/ip/tinc.c
+++ b/sys/src/cmd/ip/tinc.c
@@ -155,7 +155,6 @@
int debug;
int maxprocs = 100;
-char *confdir = ".";
char *myname = nil;
Host *myhost = nil;
@@ -165,11 +164,12 @@
char *outside = "/net";
char *inside = "/net";
-int ipifn = 0;
+char device[128];
int ipcfd = -1;
int ipdfd = -1;
uchar localip[IPaddrlen];
uchar localmask[IPaddrlen];
+int rcfd = -1;
void deledge(Edge*);
void delsubnet(Snet*);
@@ -384,6 +384,7 @@
void
netrecalc(void)
{
+ static int hostup = 0;
Host *h;
Edge *e;
Snet *t;
@@ -417,6 +418,13 @@
for(t = h->snet; t != nil; t = t->next)
t->reported = 0;
e->reported = 0;
+
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I"
+ " REMOTENET=%s REMOTEADDRESS=%I REMOTEPORT=%d"
+ " ./hosts/%s-up\n",
+ myname, h->name, device, localip,
+ outside, h->ip, h->port,
+ h->name);
}
goto Loop;
}
@@ -425,6 +433,14 @@
if(h->from == nil && h->connected){
h->connected = 0;
clearkey(h);
+
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I"
+ " REMOTENET=%s REMOTEADDRESS=%I REMOTEPORT=%d"
+ " ./hosts/%s-down\n",
+ myname, h->name, device, localip,
+ outside, h->ip, h->port,
+ h->name);
+
while(h->link != nil) {
deledge(h->link->rev);
deledge(h->link);
@@ -433,14 +449,39 @@
}
}
+ i = myhost->link != nil;
+ if(i != hostup){
+ hostup = i;
+
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I"
+ " REMOTENET=%s REMOTEADDRESS=%I REMOTEPORT=%d"
+ " ./host-%s\n",
+ myname, myhost->name, device, localip,
+ outside, myhost->ip, myhost->port,
+ hostup ? "up" : "down");
+ }
+
+
qsort(snet, nsnet, sizeof(snet[0]), subnetpcmp);
for(i = nsnet-1; i >= 0; i--){
- reportsubnet(bcast, snet[i]);
- if(snet[i]->deleted){
+ t = snet[i];
+
+ if(t->owner != myhost && (t->deleted || t->reported == 0))
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I"
+ " REMOTENET=%s REMOTEADDRESS=%I REMOTEPORT=%d"
+ " SUBNET=(%I %M) WEIGHT=%d"
+ " ./subnet-%s\n",
+ myname, t->owner->name, device, localip,
+ outside, t->owner->ip, t->owner->port,
+ t->ip, t->mask, t->weight,
+ t->deleted ? "down" : "up");
+
+ reportsubnet(bcast, t);
+ if(t->deleted){
assert(i == nsnet-1);
- nsnet = i;
- free(snet[i]);
snet[i] = nil;
+ nsnet = i;
+ free(t);
}
}
@@ -488,8 +529,6 @@
if(!new)
return nil;
-if(debug) fprint(2, "%s adding subnet: %I %M #%d\n", h->name, ip, mask, weight);
-
t = emalloc(sizeof(Snet));
ipmove(t->ip, ip);
ipmove(t->mask, mask);
@@ -585,7 +624,7 @@
for(h = hosts; h != nil; h = h->next)
if(strcmp(h->name, name) == 0)
goto out;
- snprint(buf, sizeof(buf), "%s/hosts/%s", confdir, name);
+ snprint(buf, sizeof(buf), "hosts/%s", name);
if((fd = open(buf, OREAD)) < 0){
if(!new)
goto out;
@@ -801,7 +840,7 @@
}
int
-recvudp(Host *h)
+recvudp(Host *h, int fd)
{
uchar buf[4+MaxPacket+AESbsize+MAClen], mac[SHA2_256dlen];
AESstate cs[1];
@@ -808,7 +847,7 @@
uint seq;
int n, o;
- if((n = read(h->udpfd, buf, sizeof(buf))) <= 0)
+ if((n = read(fd, buf, sizeof(buf))) <= 0)
return -1;
lock(h->cin);
if(h->cin->crypt == nil || (n -= MAClen) < AESbsize){
@@ -822,6 +861,10 @@
}
memmove(cs, h->cin->cs, sizeof(cs));
(*h->cin->crypt)(buf, n, cs);
+ if((n -= buf[n-1]) < 4+EtherHdr){
+ unlock(h->cin);
+ return -1;
+ }
seq = buf[0]<<24;
seq |= buf[1]<<16;
@@ -839,9 +882,9 @@
}
h->ooo |= 1ULL<<o;
}
+ h->udpfd = fd;
unlock(h->cin);
- if((n -= buf[n-1]) < 4+EtherHdr)
- return -1;
+
routepkt(h, buf+4, n-4);
return 0;
}
@@ -1347,7 +1390,7 @@
}
void
-tcpclient(int fd)
+tcpclient(int fd, int incoming)
{
Conn *c;
char dir[128];
@@ -1357,8 +1400,8 @@
c->fd = fd;
c->rp = c->wp = c->buf;
c->port = dir2ipport(fd2dir(fd, dir, sizeof(dir)), c->ip);
- procsetname("tcpclient %s %s %I!%d", myhost->name,
- dir, c->ip, c->port);
+ 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);
@@ -1380,7 +1423,7 @@
}
void
-udpclient(int fd)
+udpclient(int fd, int incoming)
{
uchar ip[IPaddrlen];
char dir[128];
@@ -1388,14 +1431,24 @@
if((h = findhost(ip, dir2ipport(fd2dir(fd, dir, sizeof(dir)), ip))) != nil
&& h != myhost){
- procsetname("udpclient %s %s %I!%d %s", myhost->name,
- dir, h->ip, h->port, h->name);
- h->udpfd = fd;
+ procsetname("udpclient %s %s %s %I!%d %s", myhost->name,
+ incoming ? "in": "out", dir, h->ip, h->port, h->name);
+
+ if(!incoming){
+ lock(h->cin);
+ if(h->udpfd == -1)
+ h->udpfd = fd;
+ unlock(h->cin);
+ }
+
do {
alarm(15*1000);
- } while(recvudp(h) == 0);
+ } while(recvudp(h, fd) == 0);
+
+ lock(h->cin);
if(h->udpfd == fd)
h->udpfd = -1;
+ unlock(h->cin);
}
close(fd);
}
@@ -1481,22 +1534,21 @@
void
ipifcsetup(void)
{
- char buf[128];
int n;
- snprint(buf, sizeof buf, "%s/ipifc/clone", inside);
- if((ipcfd = open(buf, ORDWR)) < 0)
+ snprint(device, sizeof device, "%s/ipifc/clone", inside);
+ if((ipcfd = open(device, ORDWR)) < 0)
sysfatal("can't open ip interface: %r");
- if((n = read(ipcfd, buf, sizeof buf - 1)) <= 0)
+ if((n = read(ipcfd, device, sizeof device - 1)) <= 0)
sysfatal("can't read interface number: %r");
- buf[n] = 0;
- ipifn = atoi(buf);
- snprint(buf, sizeof buf, "%s/ipifc/%d/data", inside, ipifn);
- if((ipdfd = open(buf, ORDWR)) < 0)
+ device[n] = 0;
+ snprint(device, sizeof device, "%s/ipifc/%d/data", inside, atoi(device));
+ if((ipdfd = open(device, ORDWR)) < 0)
sysfatal("can't open ip data: %r");
fprint(ipcfd, "bind pkt");
fprint(ipcfd, "mtu %d", myhost->pmtu-EtherHdr);
fprint(ipcfd, "add %I %M", localip, localmask);
+ *strrchr(device, '/') = 0;
}
void
@@ -1548,7 +1600,7 @@
Host *h;
Snet *t;
AuthRpc *rpc;
- int i;
+ int i, pfd[2];
quotefmtinstall();
fmtinstall('I', eipfmt);
@@ -1564,7 +1616,8 @@
sysfatal("bad number of procs");
break;
case 'c':
- confdir = EARGF(usage());
+ if(chdir(EARGF(usage())) < 0)
+ sysfatal("can't change directory: %r");
break;
case 'n':
myname = EARGF(usage());
@@ -1609,6 +1662,26 @@
sysfatal("local ip %I belongs to host %s subnet %I %M",
localip, t->owner->name, t->ip, t->mask);
+ if(pipe(pfd) < 0)
+ sysfatal("can't create pipe: %r");
+ switch(rfork(RFPROC|RFFDG|RFREND|RFNOTEG)){
+ case -1:
+ sysfatal("can't fork: %r");
+ case 0:
+ dup(pfd[1], 0);
+ close(pfd[0]);
+ close(pfd[1]);
+ if(!debug){
+ close(2);
+ while(open("/dev/null", OWRITE) == 1)
+ ;
+ }
+ execl("/bin/rc", "rc", debug? "-v": nil, nil);
+ sysfatal("can't exec: %r");
+ }
+ rcfd = pfd[0];
+ close(pfd[1]);
+
ipifcsetup();
notify(catch);
switch(rfork(RFPROC|RFFDG|RFREND|RFNOTEG)){
@@ -1624,12 +1697,17 @@
exits(nil);
}
atexit(shutdown);
+
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I ./tinc-up\n",
+ myname, myhost->name, device, localip);
+
if(rfork(RFPROC|RFMEM) == 0){
- tcpclient(listener("tcp", myhost->port, maxprocs));
+ tcpclient(listener("tcp", myhost->port, maxprocs), 1);
exits(nil);
}
+ if((myhost->options & OptTcpOnly) == 0)
if(rfork(RFPROC|RFMEM) == 0){
- udpclient(listener("udp", myhost->port, maxprocs));
+ udpclient(listener("udp", myhost->port, maxprocs), 1);
exits(nil);
}
for(i = 0; i < argc; i++){
@@ -1636,11 +1714,12 @@
if((h = gethost(argv[i], 0)) == nil)
continue;
if(rfork(RFPROC|RFMEM) == 0){
- tcpclient(dialer("tcp", h->addr, h->port, myhost->port));
+ tcpclient(dialer("tcp", h->addr, h->port, myhost->port), 0);
exits(nil);
}
+ if((h->options & OptTcpOnly) == 0)
if(rfork(RFPROC|RFMEM) == 0){
- udpclient(dialer("udp", h->addr, h->port, myhost->port));
+ udpclient(dialer("udp", h->addr, h->port, myhost->port), 0);
exits(nil);
}
}
@@ -1649,4 +1728,7 @@
exits(nil);
}
ip2tunnel();
+
+ fprint(rcfd, "NAME=%s NODE=%s DEVICE=%s INTERFACE=%I ./tinc-down\n",
+ myname, myhost->name, device, localip);
}