📄 sshnet.c
字号:
/* * SSH network file system. * Presents remote TCP stack as /net-style file system. */#include "ssh.h"#include <bio.h>#include <ndb.h>#include <thread.h>#include <fcall.h>#include <9p.h>int rawhack = 1;Conn *conn;char *remoteip = "<remote>";char *mtpt;Cipher *allcipher[] = { &cipherrc4, &cipherblowfish, &cipher3des, &cipherdes, &ciphernone, &ciphertwiddle,};Auth *allauth[] = { &authpassword, &authrsa, &authtis,};char *cipherlist = "rc4 3des";char *authlist = "rsa password tis";Cipher*findcipher(char *name, Cipher **list, int nlist){ int i; for(i=0; i<nlist; i++) if(strcmp(name, list[i]->name) == 0) return list[i]; error("unknown cipher %s", name); return nil;}Auth*findauth(char *name, Auth **list, int nlist){ int i; for(i=0; i<nlist; i++) if(strcmp(name, list[i]->name) == 0) return list[i]; error("unknown auth %s", name); return nil;}voidusage(void){ fprint(2, "usage: sshnet [-A authlist] [-c cipherlist] [-m mtpt] [user@]hostname\n"); exits("usage");}intisatty(int fd){ char buf[64]; buf[0] = '\0'; fd2path(fd, buf, sizeof buf); if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0) return 1; return 0;}enum{ Qroot, Qcs, Qtcp, Qclone, Qn, Qctl, Qdata, Qlocal, Qremote, Qstatus,};#define PATH(type, n) ((type)|((n)<<8))#define TYPE(path) ((int)(path) & 0xFF)#define NUM(path) ((uint)(path)>>8)Channel *sshmsgchan; /* chan(Msg*) */Channel *fsreqchan; /* chan(Req*) */Channel *fsreqwaitchan; /* chan(nil) */Channel *fsclunkchan; /* chan(Fid*) */Channel *fsclunkwaitchan; /* chan(nil) */ulong time0;enum{ Closed, Dialing, Established, Teardown,};char *statestr[] = { "Closed", "Dialing", "Established", "Teardown",};typedef struct Client Client;struct Client{ int ref; int state; int num; int servernum; char *connect; Req *rq; Req **erq; Msg *mq; Msg **emq;};int nclient;Client **client;intnewclient(void){ int i; Client *c; for(i=0; i<nclient; i++) if(client[i]->ref==0 && client[i]->state == Closed) return i; if(nclient%16 == 0) client = erealloc9p(client, (nclient+16)*sizeof(client[0])); c = emalloc9p(sizeof(Client)); memset(c, 0, sizeof(*c)); c->num = nclient; client[nclient++] = c; return c->num;}voidqueuereq(Client *c, Req *r){ if(c->rq==nil) c->erq = &c->rq; *c->erq = r; r->aux = nil; c->erq = (Req**)&r->aux;}voidqueuemsg(Client *c, Msg *m){ if(c->mq==nil) c->emq = &c->mq; *c->emq = m; m->link = nil; c->emq = (Msg**)&m->link;}voidmatchmsgs(Client *c){ Req *r; Msg *m; int n, rm; while(c->rq && c->mq){ r = c->rq; c->rq = r->aux; rm = 0; m = c->mq; n = r->ifcall.count; if(n >= m->ep - m->rp){ n = m->ep - m->rp; c->mq = m->link; rm = 1; } memmove(r->ofcall.data, m->rp, n); if(rm) free(m); else m->rp += n; r->ofcall.count = n; respond(r, nil); }}Req*findreq(Client *c, Req *r){ Req **l; for(l=&c->rq; *l; l=(Req**)&(*l)->aux){ if(*l == r){ *l = r->aux; if(*l == nil) c->erq = l; return r; } } return nil;}voiddialedclient(Client *c){ Req *r; if(r=c->rq){ if(r->aux != nil) sysfatal("more than one outstanding dial request (BUG)"); if(c->state == Established) respond(r, nil); else respond(r, "connect failed"); } c->rq = nil;}voidteardownclient(Client *c){ Msg *m; c->state = Teardown; m = allocmsg(conn, SSH_MSG_CHANNEL_INPUT_EOF, 4); putlong(m, c->servernum); sendmsg(m);}voidhangupclient(Client *c){ Req *r, *next; Msg *m, *mnext; c->state = Closed; for(m=c->mq; m; m=mnext){ mnext = m->link; free(m); } c->mq = nil; for(r=c->rq; r; r=next){ next = r->aux; respond(r, "hangup on network connection"); } c->rq = nil;}voidcloseclient(Client *c){ Msg *m, *next; if(--c->ref) return; if(c->rq != nil) sysfatal("ref count reached zero with requests pending (BUG)"); for(m=c->mq; m; m=next){ next = m->link; free(m); } c->mq = nil; if(c->state != Closed) teardownclient(c);} voidsshreadproc(void *a){ Conn *c; Msg *m; c = a; for(;;){ m = recvmsg(c, -1); if(m == nil) sysfatal("eof on ssh connection"); sendp(sshmsgchan, m); }}typedef struct Tab Tab;struct Tab{ char *name; ulong mode;};Tab tab[] ={ "/", DMDIR|0555, "cs", 0666, "tcp", DMDIR|0555, "clone", 0666, nil, DMDIR|0555, "ctl", 0666, "data", 0666, "local", 0444, "remote", 0444, "status", 0444,};static voidfillstat(Dir *d, uvlong path){ Tab *t; memset(d, 0, sizeof(*d)); d->uid = estrdup9p("ssh"); d->gid = estrdup9p("ssh"); d->qid.path = path; d->atime = d->mtime = time0; t = &tab[TYPE(path)]; if(t->name) d->name = estrdup9p(t->name); else{ d->name = smprint("%ud", NUM(path)); if(d->name == nil) sysfatal("out of memory"); } d->qid.type = t->mode>>24; d->mode = t->mode;}static voidfsattach(Req *r){ if(r->ifcall.aname && r->ifcall.aname[0]){ respond(r, "invalid attach specifier"); return; } r->fid->qid.path = PATH(Qroot, 0); r->fid->qid.type = QTDIR; r->fid->qid.vers = 0; r->ofcall.qid = r->fid->qid; respond(r, nil);}static voidfsstat(Req *r){ fillstat(&r->d, r->fid->qid.path); respond(r, nil);}static introotgen(int i, Dir *d, void*){ i += Qroot+1; if(i <= Qtcp){ fillstat(d, i); return 0; } return -1;}static inttcpgen(int i, Dir *d, void*){ i += Qtcp+1; if(i < Qn){ fillstat(d, i); return 0; } i -= Qn; if(i < nclient){ fillstat(d, PATH(Qn, i)); return 0; } return -1;}static intclientgen(int i, Dir *d, void *aux){ Client *c; c = aux; i += Qn+1; if(i <= Qstatus){ fillstat(d, PATH(i, c->num)); return 0; } return -1;}static char*fswalk1(Fid *fid, char *name, Qid *qid){ int i, n; char buf[32]; ulong path; path = fid->qid.path; if(!(fid->qid.type&QTDIR)) return "walk in non-directory"; if(strcmp(name, "..") == 0){ switch(TYPE(path)){ case Qn: qid->path = PATH(Qtcp, NUM(path)); qid->type = tab[Qtcp].mode>>24; return nil; case Qtcp: qid->path = PATH(Qroot, 0); qid->type = tab[Qroot].mode>>24; return nil; case Qroot: return nil; default: return "bug in fswalk1"; } } i = TYPE(path)+1; for(; i<nelem(tab); i++){ if(i==Qn){ n = atoi(name); snprint(buf, sizeof buf, "%d", n); if(n < nclient && strcmp(buf, name) == 0){ qid->path = PATH(i, n); qid->type = tab[i].mode>>24; return nil; } break; } if(strcmp(name, tab[i].name) == 0){ qid->path = PATH(i, NUM(path)); qid->type = tab[i].mode>>24; return nil; } if(tab[i].mode&DMDIR) break; } return "directory entry not found";}typedef struct Cs Cs;struct Cs{ char *resp; int isnew;};static intndbfindport(char *p){ char *s, *port; int n; static Ndb *db; if(*p == '\0') return -1; n = strtol(p, &s, 0); if(*s == '\0') return n; if(db == nil){ db = ndbopen("/lib/ndb/common"); if(db == nil) return -1; } port = ndbgetvalue(db, nil, "tcp", p, "port", nil); if(port == nil) return -1; n = atoi(port); free(port); return n;} static voidcsread(Req *r){ Cs *cs; cs = r->fid->aux; if(cs->resp==nil){ respond(r, "cs read without write"); return; } if(r->ifcall.offset==0){ if(!cs->isnew){ r->ofcall.count = 0; respond(r, nil); return; } cs->isnew = 0; } readstr(r, cs->resp); respond(r, nil);}static voidcswrite(Req *r){ int port, nf; char err[ERRMAX], *f[4], *s, *ns; Cs *cs; cs = r->fid->aux; s = emalloc(r->ifcall.count+1); memmove(s, r->ifcall.data, r->ifcall.count); s[r->ifcall.count] = '\0'; nf = getfields(s, f, nelem(f), 0, "!"); if(nf != 3){ free(s); respond(r, "can't translate"); return; } if(strcmp(f[0], "tcp") != 0 && strcmp(f[0], "net") != 0){ free(s); respond(r, "unknown protocol"); return; } port = ndbfindport(f[2]); if(port <= 0){ free(s); respond(r, "no translation found"); return; } ns = smprint("%s/tcp/clone %s!%d", mtpt, f[1], port); if(ns == nil){ free(s); rerrstr(err, sizeof err); respond(r, err); return; } free(s); free(cs->resp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -