sshnet: implement listen (port forwarding)
This commit is contained in:
parent
7a3ceb58fc
commit
634292c2f8
2 changed files with 142 additions and 25 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue