changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: sshnet: implement listen (port forwarding)

changeset 7131: 764656b4f929
parent 7130: b7844d3b2bdf
child 7132: f7a2615a3bca
author: cinap_lenrek@felloff.net
date: Wed, 03 Apr 2019 22:15:47 +0200
files: sys/man/4/sshnet sys/src/cmd/sshnet.c
description: sshnet: implement listen (port forwarding)
     1.1--- a/sys/man/4/sshnet
     1.2+++ b/sys/man/4/sshnet
     1.3@@ -45,8 +45,6 @@ All other arguments are passed to
     1.4 as is.
     1.5 .SH SOURCE
     1.6 .B /sys/src/cmd/sshnet.c
     1.7-.SH BUGS
     1.8-Incoming connections are not supported.
     1.9 .SH "SEE ALSO"
    1.10 .IR ssh (1),
    1.11 .IR ip (3)
     2.1--- a/sys/src/cmd/sshnet.c
     2.2+++ b/sys/src/cmd/sshnet.c
     2.3@@ -26,6 +26,7 @@ enum
     2.4 	Qlocal,
     2.5 	Qremote,
     2.6 	Qstatus,
     2.7+	Qlisten,
     2.8 };
     2.9 
    2.10 #define PATH(type, n)		((type)|((n)<<8))
    2.11@@ -44,6 +45,8 @@ enum
    2.12 {
    2.13 	Closed,
    2.14 	Dialing,
    2.15+	Announced,
    2.16+	Listen,
    2.17 	Established,
    2.18 	Teardown,
    2.19 	Finished,
    2.20@@ -52,6 +55,8 @@ enum
    2.21 char *statestr[] = {
    2.22 	"Closed",
    2.23 	"Dialing",
    2.24+	"Announced",
    2.25+	"Listen",
    2.26 	"Established",
    2.27 	"Teardown",
    2.28 	"Finished",
    2.29@@ -63,7 +68,10 @@ struct Client
    2.30 	int state;
    2.31 	int num;
    2.32 	int servernum;
    2.33-	char *connect;
    2.34+
    2.35+	int rport, lport;
    2.36+	char *rhost;
    2.37+	char *lhost;
    2.38 
    2.39 	int sendpkt;
    2.40 	int sendwin;
    2.41@@ -83,6 +91,8 @@ struct Client
    2.42 };
    2.43 
    2.44 enum {
    2.45+	MSG_GLOBAL_REQUEST = 80,
    2.46+
    2.47 	MSG_CHANNEL_OPEN = 90,
    2.48 	MSG_CHANNEL_OPEN_CONFIRMATION,
    2.49 	MSG_CHANNEL_OPEN_FAILURE,
    2.50@@ -119,8 +129,6 @@ int nclient;
    2.51 Client **client;
    2.52 char *mtpt;
    2.53 int sshfd;
    2.54-int localport;
    2.55-char localip[] = "::";
    2.56 
    2.57 int
    2.58 vpack(uchar *p, int n, char *fmt, va_list a)
    2.59@@ -301,6 +309,19 @@ getclient(int num)
    2.60 	return client[num];
    2.61 }
    2.62 
    2.63+Client*
    2.64+getlistener(char *host, int port)
    2.65+{
    2.66+	int i;
    2.67+
    2.68+	USED(host);
    2.69+	for(i = 0; i < nclient; i++){
    2.70+		if(client[i]->state == Listen && client[i]->lport == port)
    2.71+			return client[i];
    2.72+	}
    2.73+	return nil;
    2.74+}
    2.75+
    2.76 void
    2.77 adjustwin(Client *c, int len)
    2.78 {
    2.79@@ -472,6 +493,16 @@ closeclient(Client *c)
    2.80 		c->state = Closed;
    2.81 		sendmsg(pack(nil, "bu", MSG_CHANNEL_CLOSE, c->servernum));
    2.82 		break;
    2.83+	case Announced:
    2.84+		sendmsg(pack(nil, "bsbsu", MSG_GLOBAL_REQUEST,
    2.85+			"cancel-tcpip-forward", 20,
    2.86+			0,
    2.87+			c->lhost, strlen(c->lhost),
    2.88+			c->lport));
    2.89+		/* wet floor */
    2.90+	case Listen:
    2.91+		c->state = Closed;
    2.92+		break;
    2.93 	}
    2.94 	while((m = c->mq) != nil){
    2.95 		c->mq = m->link;
    2.96@@ -514,6 +545,7 @@ Tab tab[] =
    2.97 	"local",	0444,
    2.98 	"remote",	0444,
    2.99 	"status",	0444,
   2.100+	"listen",	0666,
   2.101 };
   2.102 
   2.103 static void
   2.104@@ -768,7 +800,7 @@ static void
   2.105 ctlwrite(Req *r, Client *c)
   2.106 {
   2.107 	char *f[3], *s;
   2.108-	int nf;
   2.109+	int nf, port;
   2.110 
   2.111 	s = emalloc9p(r->ifcall.count+1);
   2.112 	r->ofcall.count = r->ifcall.count;
   2.113@@ -790,15 +822,18 @@ ctlwrite(Req *r, Client *c)
   2.114 		teardownclient(c);
   2.115 		respond(r, nil);
   2.116 	}else if(strcmp(f[0], "connect") == 0){
   2.117-		if(c->state != Closed)
   2.118+		if(nf != 2 || c->state != Closed)
   2.119 			goto Badarg;
   2.120-		if(nf != 2)
   2.121+		if(getfields(f[1], f, nelem(f), 0, "!") != 2)
   2.122+			goto Badarg;
   2.123+		if((port = ndbfindport(f[1])) < 0)
   2.124 			goto Badarg;
   2.125-		free(c->connect);
   2.126-		c->connect = estrdup9p(f[1]);
   2.127-		nf = getfields(f[1], f, nelem(f), 0, "!");
   2.128-		if(nf != 2)
   2.129-			goto Badarg;
   2.130+		free(c->lhost);
   2.131+		c->lhost = estrdup9p("::");
   2.132+		c->lport = 0;
   2.133+		free(c->rhost);
   2.134+		c->rhost = estrdup9p(f[0]);
   2.135+		c->rport = port;
   2.136 		c->recvwin = WinPackets*MaxPacket;
   2.137 		c->recvacc = 0;
   2.138 		c->state = Dialing;
   2.139@@ -807,8 +842,28 @@ ctlwrite(Req *r, Client *c)
   2.140 		sendmsg(pack(nil, "bsuuususu", MSG_CHANNEL_OPEN,
   2.141 			"direct-tcpip", 12,
   2.142 			c->num, c->recvwin, MaxPacket,
   2.143-			f[0], strlen(f[0]), ndbfindport(f[1]),
   2.144-			localip, strlen(localip), localport));
   2.145+			c->rhost, strlen(c->rhost), c->rport,
   2.146+			c->lhost, strlen(c->lhost), c->lport));
   2.147+	}else if(strcmp(f[0], "announce") == 0){
   2.148+		if(nf != 2 || c->state != Closed)
   2.149+			goto Badarg;
   2.150+		if(getfields(f[1], f, nelem(f), 0, "!") != 2)
   2.151+			goto Badarg;
   2.152+		if((port = ndbfindport(f[1])) < 0)
   2.153+			goto Badarg;
   2.154+		if(strcmp(f[0], "*") == 0)
   2.155+			f[0] = "";
   2.156+		free(c->lhost);
   2.157+		c->lhost = estrdup9p(f[0]);
   2.158+		c->lport = port;
   2.159+		free(c->rhost);
   2.160+		c->rhost = estrdup9p("::");
   2.161+		c->rport = 0;
   2.162+		c->state = Announced;
   2.163+		sendmsg(pack(nil, "bsbsu", MSG_GLOBAL_REQUEST,
   2.164+			"tcpip-forward", 13, 0,
   2.165+			c->lhost, strlen(c->lhost), c->lport));
   2.166+		respond(r, nil);
   2.167 	}else{
   2.168 	Badarg:
   2.169 		respond(r, "bad or inappropriate tcp control message");
   2.170@@ -844,11 +899,16 @@ datawrite(Req *r, Client *c)
   2.171 }
   2.172 
   2.173 static void
   2.174-localread(Req *r)
   2.175+localread(Req *r, Client *c)
   2.176 {
   2.177-	char buf[128];
   2.178+	char buf[128], *s;
   2.179 
   2.180-	snprint(buf, sizeof buf, "%s!%d\n", localip, localport);
   2.181+	s = c->lhost;
   2.182+	if(s == nil)
   2.183+		s = "::";
   2.184+	else if(*s == 0)
   2.185+		s = "*";
   2.186+	snprint(buf, sizeof buf, "%s!%d\n", s, c->lport);
   2.187 	readstr(r, buf);
   2.188 	respond(r, nil);
   2.189 }
   2.190@@ -856,13 +916,12 @@ localread(Req *r)
   2.191 static void
   2.192 remoteread(Req *r, Client *c)
   2.193 {
   2.194-	char *s;
   2.195-	char buf[128];
   2.196+	char buf[128], *s;
   2.197 
   2.198-	s = c->connect;
   2.199+	s = c->rhost;
   2.200 	if(s == nil)
   2.201-		s = "::!0";
   2.202-	snprint(buf, sizeof buf, "%s\n", s);
   2.203+		s = "::";
   2.204+	snprint(buf, sizeof buf, "%s!%d\n", s, c->rport);
   2.205 	readstr(r, buf);
   2.206 	respond(r, nil);
   2.207 }
   2.208@@ -918,7 +977,7 @@ fsread(Req *r)
   2.209 		break;
   2.210 
   2.211 	case Qlocal:
   2.212-		localread(r);
   2.213+		localread(r, client[NUM(path)]);
   2.214 		break;
   2.215 
   2.216 	case Qremote:
   2.217@@ -985,6 +1044,22 @@ fsopen(Req *r)
   2.218 		r->fid->aux = cs;
   2.219 		respond(r, nil);
   2.220 		break;
   2.221+	case Qlisten:
   2.222+		if(client[NUM(path)]->state != Announced){
   2.223+			respond(r, "not announced");
   2.224+			break;
   2.225+		}
   2.226+		n = newclient();
   2.227+		free(client[n]->lhost);
   2.228+		client[n]->lhost = estrdup9p(client[NUM(path)]->lhost);
   2.229+		client[n]->lport = client[NUM(path)]->lport;
   2.230+		r->fid->qid.path = PATH(Qctl, n);
   2.231+		r->ofcall.qid.path = r->fid->qid.path;
   2.232+		r->aux = nil;
   2.233+		client[n]->wq = r;
   2.234+		client[n]->ref++;
   2.235+		client[n]->state = Listen;
   2.236+		break;
   2.237 	case Qclone:
   2.238 		n = newclient();
   2.239 		path = PATH(Qctl, n);
   2.240@@ -1016,9 +1091,9 @@ fsflush(Req *r)
   2.241 static void
   2.242 handlemsg(Msg *m)
   2.243 {
   2.244-	int chan, win, pkt, n;
   2.245+	int chan, win, pkt, lport, rport, n, ln, rn;
   2.246+	char *s, *lhost, *rhost;
   2.247 	Client *c;
   2.248-	char *s;
   2.249 
   2.250 	switch(m->rp[0]){
   2.251 	case MSG_CHANNEL_WINDOW_ADJUST:
   2.252@@ -1109,6 +1184,50 @@ handlemsg(Msg *m)
   2.253 		}
   2.254 		free(s);
   2.255 		break;
   2.256+	case MSG_CHANNEL_OPEN:
   2.257+		if(unpack(m, "_suuususu", &s, &n, &chan,
   2.258+			&win, &pkt,
   2.259+			&lhost, &ln, &lport,
   2.260+			&rhost, &rn, &rport) < 0)
   2.261+			break;
   2.262+		if(n != 15 || strncmp(s, "forwarded-tcpip", 15) != 0){
   2.263+			n = 3, s = "unknown open type";
   2.264+		Reject:
   2.265+			sendmsg(pack(nil, "buus", MSG_CHANNEL_OPEN_FAILURE,
   2.266+				chan, n, s, strlen(s)));
   2.267+			break;
   2.268+		}
   2.269+		lhost = smprint("%.*s", utfnlen(lhost, ln), lhost);
   2.270+		rhost = smprint("%.*s", utfnlen(rhost, rn), rhost);
   2.271+		c = getlistener(lhost, lport);
   2.272+		if(c == nil){
   2.273+			free(lhost);
   2.274+			free(rhost);
   2.275+			n = 2, s = "connection refused";
   2.276+			goto Reject;
   2.277+		}
   2.278+		free(c->lhost);
   2.279+		c->lhost = lhost;
   2.280+		c->lport = lport;
   2.281+		free(c->rhost);
   2.282+		c->rhost = rhost;
   2.283+		c->rport = rport;
   2.284+		c->servernum = chan;
   2.285+		c->recvwin = WinPackets*MaxPacket;
   2.286+		c->recvacc = 0;
   2.287+		c->eof = 0;
   2.288+		c->sendpkt = pkt;
   2.289+		c->sendwin = win;
   2.290+		c->state = Established;
   2.291+		sendmsg(pack(nil, "buuuu", MSG_CHANNEL_OPEN_CONFIRMATION,
   2.292+			c->servernum, c->num, c->recvwin, MaxPacket));
   2.293+		if(c->wq == nil){
   2.294+			teardownclient(c);
   2.295+			break;
   2.296+		}
   2.297+		respond(c->wq, nil);
   2.298+		c->wq = nil;
   2.299+		break;
   2.300 	}
   2.301 	free(m);
   2.302 }