sshnet: implement listen (port forwarding)

This commit is contained in:
cinap_lenrek 2019-04-03 22:15:47 +02:00
parent 7a3ceb58fc
commit 634292c2f8
2 changed files with 142 additions and 25 deletions

View file

@ -45,8 +45,6 @@ All other arguments are passed to
as is. as is.
.SH SOURCE .SH SOURCE
.B /sys/src/cmd/sshnet.c .B /sys/src/cmd/sshnet.c
.SH BUGS
Incoming connections are not supported.
.SH "SEE ALSO" .SH "SEE ALSO"
.IR ssh (1), .IR ssh (1),
.IR ip (3) .IR ip (3)

View file

@ -26,6 +26,7 @@ enum
Qlocal, Qlocal,
Qremote, Qremote,
Qstatus, Qstatus,
Qlisten,
}; };
#define PATH(type, n) ((type)|((n)<<8)) #define PATH(type, n) ((type)|((n)<<8))
@ -44,6 +45,8 @@ enum
{ {
Closed, Closed,
Dialing, Dialing,
Announced,
Listen,
Established, Established,
Teardown, Teardown,
Finished, Finished,
@ -52,6 +55,8 @@ enum
char *statestr[] = { char *statestr[] = {
"Closed", "Closed",
"Dialing", "Dialing",
"Announced",
"Listen",
"Established", "Established",
"Teardown", "Teardown",
"Finished", "Finished",
@ -63,7 +68,10 @@ struct Client
int state; int state;
int num; int num;
int servernum; int servernum;
char *connect;
int rport, lport;
char *rhost;
char *lhost;
int sendpkt; int sendpkt;
int sendwin; int sendwin;
@ -83,6 +91,8 @@ struct Client
}; };
enum { enum {
MSG_GLOBAL_REQUEST = 80,
MSG_CHANNEL_OPEN = 90, MSG_CHANNEL_OPEN = 90,
MSG_CHANNEL_OPEN_CONFIRMATION, MSG_CHANNEL_OPEN_CONFIRMATION,
MSG_CHANNEL_OPEN_FAILURE, MSG_CHANNEL_OPEN_FAILURE,
@ -119,8 +129,6 @@ int nclient;
Client **client; Client **client;
char *mtpt; char *mtpt;
int sshfd; int sshfd;
int localport;
char localip[] = "::";
int int
vpack(uchar *p, int n, char *fmt, va_list a) vpack(uchar *p, int n, char *fmt, va_list a)
@ -301,6 +309,19 @@ getclient(int num)
return client[num]; return client[num];
} }
Client*
getlistener(char *host, int port)
{
int i;
USED(host);
for(i = 0; i < nclient; i++){
if(client[i]->state == Listen && client[i]->lport == port)
return client[i];
}
return nil;
}
void void
adjustwin(Client *c, int len) adjustwin(Client *c, int len)
{ {
@ -472,6 +493,16 @@ closeclient(Client *c)
c->state = Closed; c->state = Closed;
sendmsg(pack(nil, "bu", MSG_CHANNEL_CLOSE, c->servernum)); sendmsg(pack(nil, "bu", MSG_CHANNEL_CLOSE, c->servernum));
break; break;
case Announced:
sendmsg(pack(nil, "bsbsu", MSG_GLOBAL_REQUEST,
"cancel-tcpip-forward", 20,
0,
c->lhost, strlen(c->lhost),
c->lport));
/* wet floor */
case Listen:
c->state = Closed;
break;
} }
while((m = c->mq) != nil){ while((m = c->mq) != nil){
c->mq = m->link; c->mq = m->link;
@ -514,6 +545,7 @@ Tab tab[] =
"local", 0444, "local", 0444,
"remote", 0444, "remote", 0444,
"status", 0444, "status", 0444,
"listen", 0666,
}; };
static void static void
@ -768,7 +800,7 @@ static void
ctlwrite(Req *r, Client *c) ctlwrite(Req *r, Client *c)
{ {
char *f[3], *s; char *f[3], *s;
int nf; int nf, port;
s = emalloc9p(r->ifcall.count+1); s = emalloc9p(r->ifcall.count+1);
r->ofcall.count = r->ifcall.count; r->ofcall.count = r->ifcall.count;
@ -790,15 +822,18 @@ ctlwrite(Req *r, Client *c)
teardownclient(c); teardownclient(c);
respond(r, nil); respond(r, nil);
}else if(strcmp(f[0], "connect") == 0){ }else if(strcmp(f[0], "connect") == 0){
if(c->state != Closed) if(nf != 2 || c->state != Closed)
goto Badarg; goto Badarg;
if(nf != 2) if(getfields(f[1], f, nelem(f), 0, "!") != 2)
goto Badarg; goto Badarg;
free(c->connect); if((port = ndbfindport(f[1])) < 0)
c->connect = estrdup9p(f[1]);
nf = getfields(f[1], f, nelem(f), 0, "!");
if(nf != 2)
goto Badarg; goto Badarg;
free(c->lhost);
c->lhost = estrdup9p("::");
c->lport = 0;
free(c->rhost);
c->rhost = estrdup9p(f[0]);
c->rport = port;
c->recvwin = WinPackets*MaxPacket; c->recvwin = WinPackets*MaxPacket;
c->recvacc = 0; c->recvacc = 0;
c->state = Dialing; c->state = Dialing;
@ -807,8 +842,28 @@ ctlwrite(Req *r, Client *c)
sendmsg(pack(nil, "bsuuususu", MSG_CHANNEL_OPEN, sendmsg(pack(nil, "bsuuususu", MSG_CHANNEL_OPEN,
"direct-tcpip", 12, "direct-tcpip", 12,
c->num, c->recvwin, MaxPacket, c->num, c->recvwin, MaxPacket,
f[0], strlen(f[0]), ndbfindport(f[1]), c->rhost, strlen(c->rhost), c->rport,
localip, strlen(localip), localport)); c->lhost, strlen(c->lhost), c->lport));
}else if(strcmp(f[0], "announce") == 0){
if(nf != 2 || c->state != Closed)
goto Badarg;
if(getfields(f[1], f, nelem(f), 0, "!") != 2)
goto Badarg;
if((port = ndbfindport(f[1])) < 0)
goto Badarg;
if(strcmp(f[0], "*") == 0)
f[0] = "";
free(c->lhost);
c->lhost = estrdup9p(f[0]);
c->lport = port;
free(c->rhost);
c->rhost = estrdup9p("::");
c->rport = 0;
c->state = Announced;
sendmsg(pack(nil, "bsbsu", MSG_GLOBAL_REQUEST,
"tcpip-forward", 13, 0,
c->lhost, strlen(c->lhost), c->lport));
respond(r, nil);
}else{ }else{
Badarg: Badarg:
respond(r, "bad or inappropriate tcp control message"); respond(r, "bad or inappropriate tcp control message");
@ -844,11 +899,16 @@ datawrite(Req *r, Client *c)
} }
static void static void
localread(Req *r) localread(Req *r, Client *c)
{ {
char buf[128]; char buf[128], *s;
snprint(buf, sizeof buf, "%s!%d\n", localip, localport); s = c->lhost;
if(s == nil)
s = "::";
else if(*s == 0)
s = "*";
snprint(buf, sizeof buf, "%s!%d\n", s, c->lport);
readstr(r, buf); readstr(r, buf);
respond(r, nil); respond(r, nil);
} }
@ -856,13 +916,12 @@ localread(Req *r)
static void static void
remoteread(Req *r, Client *c) remoteread(Req *r, Client *c)
{ {
char *s; char buf[128], *s;
char buf[128];
s = c->connect; s = c->rhost;
if(s == nil) if(s == nil)
s = "::!0"; s = "::";
snprint(buf, sizeof buf, "%s\n", s); snprint(buf, sizeof buf, "%s!%d\n", s, c->rport);
readstr(r, buf); readstr(r, buf);
respond(r, nil); respond(r, nil);
} }
@ -918,7 +977,7 @@ fsread(Req *r)
break; break;
case Qlocal: case Qlocal:
localread(r); localread(r, client[NUM(path)]);
break; break;
case Qremote: case Qremote:
@ -985,6 +1044,22 @@ fsopen(Req *r)
r->fid->aux = cs; r->fid->aux = cs;
respond(r, nil); respond(r, nil);
break; break;
case Qlisten:
if(client[NUM(path)]->state != Announced){
respond(r, "not announced");
break;
}
n = newclient();
free(client[n]->lhost);
client[n]->lhost = estrdup9p(client[NUM(path)]->lhost);
client[n]->lport = client[NUM(path)]->lport;
r->fid->qid.path = PATH(Qctl, n);
r->ofcall.qid.path = r->fid->qid.path;
r->aux = nil;
client[n]->wq = r;
client[n]->ref++;
client[n]->state = Listen;
break;
case Qclone: case Qclone:
n = newclient(); n = newclient();
path = PATH(Qctl, n); path = PATH(Qctl, n);
@ -1016,9 +1091,9 @@ fsflush(Req *r)
static void static void
handlemsg(Msg *m) handlemsg(Msg *m)
{ {
int chan, win, pkt, n; int chan, win, pkt, lport, rport, n, ln, rn;
char *s, *lhost, *rhost;
Client *c; Client *c;
char *s;
switch(m->rp[0]){ switch(m->rp[0]){
case MSG_CHANNEL_WINDOW_ADJUST: case MSG_CHANNEL_WINDOW_ADJUST:
@ -1109,6 +1184,50 @@ handlemsg(Msg *m)
} }
free(s); free(s);
break; break;
case MSG_CHANNEL_OPEN:
if(unpack(m, "_suuususu", &s, &n, &chan,
&win, &pkt,
&lhost, &ln, &lport,
&rhost, &rn, &rport) < 0)
break;
if(n != 15 || strncmp(s, "forwarded-tcpip", 15) != 0){
n = 3, s = "unknown open type";
Reject:
sendmsg(pack(nil, "buus", MSG_CHANNEL_OPEN_FAILURE,
chan, n, s, strlen(s)));
break;
}
lhost = smprint("%.*s", utfnlen(lhost, ln), lhost);
rhost = smprint("%.*s", utfnlen(rhost, rn), rhost);
c = getlistener(lhost, lport);
if(c == nil){
free(lhost);
free(rhost);
n = 2, s = "connection refused";
goto Reject;
}
free(c->lhost);
c->lhost = lhost;
c->lport = lport;
free(c->rhost);
c->rhost = rhost;
c->rport = rport;
c->servernum = chan;
c->recvwin = WinPackets*MaxPacket;
c->recvacc = 0;
c->eof = 0;
c->sendpkt = pkt;
c->sendwin = win;
c->state = Established;
sendmsg(pack(nil, "buuuu", MSG_CHANNEL_OPEN_CONFIRMATION,
c->servernum, c->num, c->recvwin, MaxPacket));
if(c->wq == nil){
teardownclient(c);
break;
}
respond(c->wq, nil);
c->wq = nil;
break;
} }
free(m); free(m);
} }