mirror of
https://github.com/0intro/conterm
synced 2024-11-22 05:41:28 +03:00
939 lines
16 KiB
C
939 lines
16 KiB
C
#include "u.h"
|
|
#include "lib.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "error.h"
|
|
|
|
#include "devip.h"
|
|
|
|
void hnputl(void *p, unsigned long v);
|
|
void hnputs(void *p, unsigned short v);
|
|
unsigned long nhgetl(void *p);
|
|
unsigned short nhgets(void *p);
|
|
unsigned long parseip(char *to, char *from);
|
|
void csclose(Chan*);
|
|
long csread(Chan*, void*, long, vlong);
|
|
long cswrite(Chan*, void*, long, vlong);
|
|
|
|
void osipinit(void);
|
|
|
|
enum
|
|
{
|
|
Qtopdir = 1, /* top level directory */
|
|
Qcs,
|
|
Qprotodir, /* directory for a protocol */
|
|
Qclonus,
|
|
Qconvdir, /* directory for a conversation */
|
|
Qdata,
|
|
Qctl,
|
|
Qstatus,
|
|
Qremote,
|
|
Qlocal,
|
|
Qlisten,
|
|
|
|
MAXPROTO = 4
|
|
};
|
|
#define TYPE(x) ((int)((x).path & 0xf))
|
|
#define CONV(x) ((int)(((x).path >> 4)&0xfff))
|
|
#define PROTO(x) ((int)(((x).path >> 16)&0xff))
|
|
#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
|
|
|
|
typedef struct Proto Proto;
|
|
typedef struct Conv Conv;
|
|
struct Conv
|
|
{
|
|
int x;
|
|
Ref r;
|
|
int sfd;
|
|
int perm;
|
|
char owner[KNAMELEN];
|
|
char* state;
|
|
ulong laddr;
|
|
ushort lport;
|
|
ulong raddr;
|
|
ushort rport;
|
|
int restricted;
|
|
char cerr[KNAMELEN];
|
|
Proto* p;
|
|
};
|
|
|
|
struct Proto
|
|
{
|
|
Lock l;
|
|
int x;
|
|
int stype;
|
|
char name[KNAMELEN];
|
|
int nc;
|
|
int maxconv;
|
|
Conv** conv;
|
|
Qid qid;
|
|
};
|
|
|
|
static int np;
|
|
static Proto proto[MAXPROTO];
|
|
int eipfmt(Fmt*);
|
|
|
|
static Conv* protoclone(Proto*, char*, int);
|
|
static void setladdr(Conv*);
|
|
|
|
int
|
|
ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
|
|
{
|
|
Qid q;
|
|
Conv *cv;
|
|
char *p;
|
|
|
|
USED(nname);
|
|
q.vers = 0;
|
|
q.type = 0;
|
|
switch(TYPE(c->qid)) {
|
|
case Qtopdir:
|
|
if(s >= 1+np)
|
|
return -1;
|
|
|
|
if(s == 0){
|
|
q.path = QID(s, 0, Qcs);
|
|
devdir(c, q, "cs", 0, "network", 0666, dp);
|
|
}else{
|
|
s--;
|
|
q.path = QID(s, 0, Qprotodir);
|
|
q.type = QTDIR;
|
|
devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
|
|
}
|
|
return 1;
|
|
case Qprotodir:
|
|
if(s < proto[PROTO(c->qid)].nc) {
|
|
cv = proto[PROTO(c->qid)].conv[s];
|
|
sprint(up->genbuf, "%d", s);
|
|
q.path = QID(PROTO(c->qid), s, Qconvdir);
|
|
q.type = QTDIR;
|
|
devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
|
|
return 1;
|
|
}
|
|
s -= proto[PROTO(c->qid)].nc;
|
|
switch(s) {
|
|
default:
|
|
return -1;
|
|
case 0:
|
|
p = "clone";
|
|
q.path = QID(PROTO(c->qid), 0, Qclonus);
|
|
break;
|
|
}
|
|
devdir(c, q, p, 0, "network", 0555, dp);
|
|
return 1;
|
|
case Qconvdir:
|
|
cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
|
|
switch(s) {
|
|
default:
|
|
return -1;
|
|
case 0:
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
|
|
devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
|
|
return 1;
|
|
case 1:
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
|
|
devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
|
|
return 1;
|
|
case 2:
|
|
p = "status";
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
|
|
break;
|
|
case 3:
|
|
p = "remote";
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
|
|
break;
|
|
case 4:
|
|
p = "local";
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
|
|
break;
|
|
case 5:
|
|
p = "listen";
|
|
q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
|
|
break;
|
|
}
|
|
devdir(c, q, p, 0, cv->owner, 0444, dp);
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
newproto(char *name, int type, int maxconv)
|
|
{
|
|
int l;
|
|
Proto *p;
|
|
|
|
if(np >= MAXPROTO) {
|
|
print("no %s: increase MAXPROTO", name);
|
|
return;
|
|
}
|
|
|
|
p = &proto[np];
|
|
strcpy(p->name, name);
|
|
p->stype = type;
|
|
p->qid.path = QID(np, 0, Qprotodir);
|
|
p->qid.type = QTDIR;
|
|
p->x = np++;
|
|
p->maxconv = maxconv;
|
|
l = sizeof(Conv*)*(p->maxconv+1);
|
|
p->conv = mallocz(l, 1);
|
|
if(p->conv == 0)
|
|
panic("no memory");
|
|
}
|
|
|
|
void
|
|
ipinit(void)
|
|
{
|
|
osipinit();
|
|
|
|
newproto("udp", S_UDP, 10);
|
|
newproto("tcp", S_TCP, 30);
|
|
|
|
fmtinstall('I', eipfmt);
|
|
fmtinstall('E', eipfmt);
|
|
|
|
}
|
|
|
|
Chan *
|
|
ipattach(char *spec)
|
|
{
|
|
Chan *c;
|
|
|
|
c = devattach('I', spec);
|
|
c->qid.path = QID(0, 0, Qtopdir);
|
|
c->qid.type = QTDIR;
|
|
c->qid.vers = 0;
|
|
return c;
|
|
}
|
|
|
|
static Walkqid*
|
|
ipwalk(Chan *c, Chan *nc, char **name, int nname)
|
|
{
|
|
return devwalk(c, nc, name, nname, 0, 0, ipgen);
|
|
}
|
|
|
|
int
|
|
ipstat(Chan *c, uchar *dp, int n)
|
|
{
|
|
return devstat(c, dp, n, 0, 0, ipgen);
|
|
}
|
|
|
|
Chan *
|
|
ipopen(Chan *c, int omode)
|
|
{
|
|
Proto *p;
|
|
ulong raddr;
|
|
ushort rport;
|
|
int perm, sfd;
|
|
Conv *cv, *lcv;
|
|
|
|
omode &= 3;
|
|
perm = 0;
|
|
switch(omode) {
|
|
case OREAD:
|
|
perm = 4;
|
|
break;
|
|
case OWRITE:
|
|
perm = 2;
|
|
break;
|
|
case ORDWR:
|
|
perm = 6;
|
|
break;
|
|
}
|
|
|
|
switch(TYPE(c->qid)) {
|
|
default:
|
|
break;
|
|
case Qtopdir:
|
|
case Qprotodir:
|
|
case Qconvdir:
|
|
case Qstatus:
|
|
case Qremote:
|
|
case Qlocal:
|
|
if(omode != OREAD)
|
|
error(Eperm);
|
|
break;
|
|
case Qclonus:
|
|
p = &proto[PROTO(c->qid)];
|
|
cv = protoclone(p, up->user, -1);
|
|
if(cv == 0)
|
|
error(Enodev);
|
|
c->qid.path = QID(p->x, cv->x, Qctl);
|
|
c->qid.vers = 0;
|
|
break;
|
|
case Qdata:
|
|
case Qctl:
|
|
p = &proto[PROTO(c->qid)];
|
|
lock(&p->l);
|
|
cv = p->conv[CONV(c->qid)];
|
|
lock(&cv->r.lk);
|
|
if((perm & (cv->perm>>6)) != perm) {
|
|
if(strcmp(up->user, cv->owner) != 0 ||
|
|
(perm & cv->perm) != perm) {
|
|
unlock(&cv->r.lk);
|
|
unlock(&p->l);
|
|
error(Eperm);
|
|
}
|
|
}
|
|
cv->r.ref++;
|
|
if(cv->r.ref == 1) {
|
|
memmove(cv->owner, up->user, KNAMELEN);
|
|
cv->perm = 0660;
|
|
}
|
|
unlock(&cv->r.lk);
|
|
unlock(&p->l);
|
|
break;
|
|
case Qlisten:
|
|
p = &proto[PROTO(c->qid)];
|
|
lcv = p->conv[CONV(c->qid)];
|
|
sfd = so_accept(lcv->sfd, &raddr, &rport);
|
|
cv = protoclone(p, up->user, sfd);
|
|
if(cv == 0) {
|
|
close(sfd);
|
|
error(Enodev);
|
|
}
|
|
cv->raddr = raddr;
|
|
cv->rport = rport;
|
|
setladdr(cv);
|
|
cv->state = "Established";
|
|
c->qid.path = QID(p->x, cv->x, Qctl);
|
|
break;
|
|
}
|
|
c->mode = openmode(omode);
|
|
c->flag |= COPEN;
|
|
c->offset = 0;
|
|
return c;
|
|
}
|
|
|
|
void
|
|
ipclose(Chan *c)
|
|
{
|
|
Conv *cc;
|
|
|
|
switch(TYPE(c->qid)) {
|
|
case Qcs:
|
|
csclose(c);
|
|
break;
|
|
case Qdata:
|
|
case Qctl:
|
|
if((c->flag & COPEN) == 0)
|
|
break;
|
|
cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
|
|
if(decref(&cc->r) != 0)
|
|
break;
|
|
strcpy(cc->owner, "network");
|
|
cc->perm = 0666;
|
|
cc->state = "Closed";
|
|
cc->laddr = 0;
|
|
cc->raddr = 0;
|
|
cc->lport = 0;
|
|
cc->rport = 0;
|
|
close(cc->sfd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
long
|
|
ipread(Chan *ch, void *a, long n, vlong offset)
|
|
{
|
|
int r;
|
|
Conv *c;
|
|
Proto *x;
|
|
uchar ip[4];
|
|
char buf[128], *p;
|
|
|
|
/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
|
|
p = a;
|
|
switch(TYPE(ch->qid)) {
|
|
default:
|
|
error(Eperm);
|
|
case Qcs:
|
|
return csread(ch, a, n, offset);
|
|
case Qprotodir:
|
|
case Qtopdir:
|
|
case Qconvdir:
|
|
return devdirread(ch, a, n, 0, 0, ipgen);
|
|
case Qctl:
|
|
sprint(buf, "%d", CONV(ch->qid));
|
|
return readstr(offset, p, n, buf);
|
|
case Qremote:
|
|
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
|
|
hnputl(ip, c->raddr);
|
|
sprint(buf, "%I!%d\n", ip, c->rport);
|
|
return readstr(offset, p, n, buf);
|
|
case Qlocal:
|
|
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
|
|
hnputl(ip, c->laddr);
|
|
sprint(buf, "%I!%d\n", ip, c->lport);
|
|
return readstr(offset, p, n, buf);
|
|
case Qstatus:
|
|
x = &proto[PROTO(ch->qid)];
|
|
c = x->conv[CONV(ch->qid)];
|
|
sprint(buf, "%s/%d %d %s \n",
|
|
c->p->name, c->x, c->r.ref, c->state);
|
|
return readstr(offset, p, n, buf);
|
|
case Qdata:
|
|
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
|
|
r = so_recv(c->sfd, a, n, 0);
|
|
if(r < 0){
|
|
oserrstr();
|
|
nexterror();
|
|
}
|
|
return r;
|
|
}
|
|
}
|
|
|
|
static void
|
|
setladdr(Conv *c)
|
|
{
|
|
so_getsockname(c->sfd, &c->laddr, &c->lport);
|
|
}
|
|
|
|
static void
|
|
setlport(Conv *c)
|
|
{
|
|
if(c->restricted == 0 && c->lport == 0)
|
|
return;
|
|
|
|
so_bind(c->sfd, c->restricted, c->lport);
|
|
}
|
|
|
|
static void
|
|
setladdrport(Conv *c, char *str)
|
|
{
|
|
char *p, addr[4];
|
|
|
|
p = strchr(str, '!');
|
|
if(p == 0) {
|
|
p = str;
|
|
c->laddr = 0;
|
|
}
|
|
else {
|
|
*p++ = 0;
|
|
parseip(addr, str);
|
|
c->laddr = nhgetl((uchar*)addr);
|
|
}
|
|
if(*p == '*')
|
|
c->lport = 0;
|
|
else
|
|
c->lport = atoi(p);
|
|
|
|
setlport(c);
|
|
}
|
|
|
|
static char*
|
|
setraddrport(Conv *c, char *str)
|
|
{
|
|
char *p, addr[4];
|
|
|
|
p = strchr(str, '!');
|
|
if(p == 0)
|
|
return "malformed address";
|
|
*p++ = 0;
|
|
parseip(addr, str);
|
|
c->raddr = nhgetl((uchar*)addr);
|
|
c->rport = atoi(p);
|
|
p = strchr(p, '!');
|
|
if(p) {
|
|
if(strcmp(p, "!r") == 0)
|
|
c->restricted = 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
long
|
|
ipwrite(Chan *ch, void *a, long n, vlong offset)
|
|
{
|
|
Conv *c;
|
|
Proto *x;
|
|
int r, nf;
|
|
char *p, *fields[3], buf[128];
|
|
|
|
switch(TYPE(ch->qid)) {
|
|
default:
|
|
error(Eperm);
|
|
case Qcs:
|
|
return cswrite(ch, a, n, offset);
|
|
case Qctl:
|
|
x = &proto[PROTO(ch->qid)];
|
|
c = x->conv[CONV(ch->qid)];
|
|
if(n > sizeof(buf)-1)
|
|
n = sizeof(buf)-1;
|
|
memmove(buf, a, n);
|
|
buf[n] = '\0';
|
|
|
|
nf = tokenize(buf, fields, 3);
|
|
if(strcmp(fields[0], "connect") == 0){
|
|
switch(nf) {
|
|
default:
|
|
error("bad args to connect");
|
|
case 2:
|
|
p = setraddrport(c, fields[1]);
|
|
if(p != 0)
|
|
error(p);
|
|
break;
|
|
case 3:
|
|
p = setraddrport(c, fields[1]);
|
|
if(p != 0)
|
|
error(p);
|
|
c->lport = atoi(fields[2]);
|
|
setlport(c);
|
|
break;
|
|
}
|
|
so_connect(c->sfd, c->raddr, c->rport);
|
|
setladdr(c);
|
|
c->state = "Established";
|
|
return n;
|
|
}
|
|
if(strcmp(fields[0], "announce") == 0) {
|
|
switch(nf){
|
|
default:
|
|
error("bad args to announce");
|
|
case 2:
|
|
setladdrport(c, fields[1]);
|
|
break;
|
|
}
|
|
so_listen(c->sfd);
|
|
c->state = "Announced";
|
|
return n;
|
|
}
|
|
if(strcmp(fields[0], "bind") == 0){
|
|
switch(nf){
|
|
default:
|
|
error("bad args to bind");
|
|
case 2:
|
|
c->lport = atoi(fields[1]);
|
|
break;
|
|
}
|
|
setlport(c);
|
|
return n;
|
|
}
|
|
error("bad control message");
|
|
case Qdata:
|
|
x = &proto[PROTO(ch->qid)];
|
|
c = x->conv[CONV(ch->qid)];
|
|
r = so_send(c->sfd, a, n, 0);
|
|
if(r < 0){
|
|
oserrstr();
|
|
nexterror();
|
|
}
|
|
return r;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static Conv*
|
|
protoclone(Proto *p, char *user, int nfd)
|
|
{
|
|
Conv *c, **pp, **ep;
|
|
|
|
c = 0;
|
|
lock(&p->l);
|
|
if(waserror()) {
|
|
unlock(&p->l);
|
|
nexterror();
|
|
}
|
|
ep = &p->conv[p->maxconv];
|
|
for(pp = p->conv; pp < ep; pp++) {
|
|
c = *pp;
|
|
if(c == 0) {
|
|
c = mallocz(sizeof(Conv), 1);
|
|
if(c == 0)
|
|
error(Enomem);
|
|
lock(&c->r.lk);
|
|
c->r.ref = 1;
|
|
c->p = p;
|
|
c->x = pp - p->conv;
|
|
p->nc++;
|
|
*pp = c;
|
|
break;
|
|
}
|
|
lock(&c->r.lk);
|
|
if(c->r.ref == 0) {
|
|
c->r.ref++;
|
|
break;
|
|
}
|
|
unlock(&c->r.lk);
|
|
}
|
|
if(pp >= ep) {
|
|
unlock(&p->l);
|
|
poperror();
|
|
return 0;
|
|
}
|
|
|
|
strcpy(c->owner, user);
|
|
c->perm = 0660;
|
|
c->state = "Closed";
|
|
c->restricted = 0;
|
|
c->laddr = 0;
|
|
c->raddr = 0;
|
|
c->lport = 0;
|
|
c->rport = 0;
|
|
c->sfd = nfd;
|
|
if(nfd == -1)
|
|
c->sfd = so_socket(p->stype);
|
|
|
|
unlock(&c->r.lk);
|
|
unlock(&p->l);
|
|
poperror();
|
|
return c;
|
|
}
|
|
|
|
enum
|
|
{
|
|
Isprefix= 16,
|
|
};
|
|
|
|
uchar prefixvals[256] =
|
|
{
|
|
/*0x00*/ 0 | Isprefix,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x80*/ 1 | Isprefix,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xC0*/ 2 | Isprefix,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xE0*/ 3 | Isprefix,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*0xF0*/ 4 | Isprefix,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
/*0xF8*/ 5 | Isprefix,
|
|
0, 0, 0,
|
|
/*0xFC*/ 6 | Isprefix,
|
|
0,
|
|
/*0xFE*/ 7 | Isprefix,
|
|
/*0xFF*/ 8 | Isprefix,
|
|
};
|
|
|
|
int
|
|
eipfmt(Fmt *f)
|
|
{
|
|
char buf[5*8];
|
|
static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
|
|
static char *ifmt = "%d.%d.%d.%d";
|
|
uchar *p, ip[16];
|
|
ulong ul;
|
|
|
|
switch(f->r) {
|
|
case 'E': /* Ethernet address */
|
|
p = va_arg(f->args, uchar*);
|
|
snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
|
|
return fmtstrcpy(f, buf);
|
|
|
|
case 'I':
|
|
ul = va_arg(f->args, ulong);
|
|
hnputl(ip, ul);
|
|
snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
|
|
return fmtstrcpy(f, buf);
|
|
}
|
|
return fmtstrcpy(f, "(eipfmt)");
|
|
}
|
|
|
|
void
|
|
hnputl(void *p, unsigned long v)
|
|
{
|
|
unsigned char *a;
|
|
|
|
a = p;
|
|
a[0] = v>>24;
|
|
a[1] = v>>16;
|
|
a[2] = v>>8;
|
|
a[3] = v;
|
|
}
|
|
|
|
void
|
|
hnputs(void *p, unsigned short v)
|
|
{
|
|
unsigned char *a;
|
|
|
|
a = p;
|
|
a[0] = v>>8;
|
|
a[1] = v;
|
|
}
|
|
|
|
unsigned long
|
|
nhgetl(void *p)
|
|
{
|
|
unsigned char *a;
|
|
a = p;
|
|
return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
|
|
}
|
|
|
|
unsigned short
|
|
nhgets(void *p)
|
|
{
|
|
unsigned char *a;
|
|
a = p;
|
|
return (a[0]<<8)|(a[1]<<0);
|
|
}
|
|
|
|
#define CLASS(p) ((*(unsigned char*)(p))>>6)
|
|
|
|
unsigned long
|
|
parseip(char *to, char *from)
|
|
{
|
|
int i;
|
|
char *p;
|
|
|
|
p = from;
|
|
memset(to, 0, 4);
|
|
for(i = 0; i < 4 && *p; i++){
|
|
to[i] = strtoul(p, &p, 10);
|
|
if(*p != '.' && *p != 0){
|
|
memset(to, 0, 4);
|
|
return 0;
|
|
}
|
|
if(*p == '.')
|
|
p++;
|
|
}
|
|
switch(CLASS(to)){
|
|
case 0: /* class A - 1 byte net */
|
|
case 1:
|
|
if(i == 3){
|
|
to[3] = to[2];
|
|
to[2] = to[1];
|
|
to[1] = 0;
|
|
} else if (i == 2){
|
|
to[3] = to[1];
|
|
to[1] = 0;
|
|
}
|
|
break;
|
|
case 2: /* class B - 2 byte net */
|
|
if(i == 3){
|
|
to[3] = to[2];
|
|
to[2] = 0;
|
|
}
|
|
break;
|
|
}
|
|
return nhgetl(to);
|
|
}
|
|
|
|
void
|
|
csclose(Chan *c)
|
|
{
|
|
free(c->aux);
|
|
}
|
|
|
|
long
|
|
csread(Chan *c, void *a, long n, vlong offset)
|
|
{
|
|
if(c->aux == nil)
|
|
return 0;
|
|
return readstr(offset, a, n, c->aux);
|
|
}
|
|
|
|
static struct
|
|
{
|
|
char *name;
|
|
uint num;
|
|
} tab[] = {
|
|
"cs", 1,
|
|
"echo", 7,
|
|
"discard", 9,
|
|
"systat", 11,
|
|
"daytime", 13,
|
|
"netstat", 15,
|
|
"chargen", 19,
|
|
"ftp-data", 20,
|
|
"ftp", 21,
|
|
"ssh", 22,
|
|
"telnet", 23,
|
|
"smtp", 25,
|
|
"time", 37,
|
|
"whois", 43,
|
|
"dns", 53,
|
|
"domain", 53,
|
|
"uucp", 64,
|
|
"gopher", 70,
|
|
"rje", 77,
|
|
"finger", 79,
|
|
"http", 80,
|
|
"link", 87,
|
|
"supdup", 95,
|
|
"hostnames", 101,
|
|
"iso-tsap", 102,
|
|
"x400", 103,
|
|
"x400-snd", 104,
|
|
"csnet-ns", 105,
|
|
"pop-2", 109,
|
|
"pop3", 110,
|
|
"portmap", 111,
|
|
"uucp-path", 117,
|
|
"nntp", 119,
|
|
"netbios", 139,
|
|
"imap4", 143,
|
|
"NeWS", 144,
|
|
"print-srv", 170,
|
|
"z39.50", 210,
|
|
"fsb", 400,
|
|
"sysmon", 401,
|
|
"proxy", 402,
|
|
"proxyd", 404,
|
|
"https", 443,
|
|
"cifs", 445,
|
|
"ssmtp", 465,
|
|
"rexec", 512,
|
|
"login", 513,
|
|
"shell", 514,
|
|
"printer", 515,
|
|
"courier", 530,
|
|
"cscan", 531,
|
|
"uucp", 540,
|
|
"snntp", 563,
|
|
"9fs", 564,
|
|
"whoami", 565,
|
|
"guard", 566,
|
|
"ticket", 567,
|
|
"dlsftp", 666,
|
|
"fmclient", 729,
|
|
"imaps", 993,
|
|
"pop3s", 995,
|
|
"ingreslock", 1524,
|
|
"pptp", 1723,
|
|
"nfs", 2049,
|
|
"webster", 2627,
|
|
"weather", 3000,
|
|
"secstore", 5356,
|
|
"Xdisplay", 6000,
|
|
"styx", 6666,
|
|
"mpeg", 6667,
|
|
"rstyx", 6668,
|
|
"infdb", 6669,
|
|
"infsigner", 6671,
|
|
"infcsigner", 6672,
|
|
"inflogin", 6673,
|
|
"bandt", 7330,
|
|
"face", 32000,
|
|
"dhashgate", 11978,
|
|
"exportfs", 17007,
|
|
"rexexec", 17009,
|
|
"ncpu", 17010,
|
|
"cpu", 17013,
|
|
"glenglenda1", 17020,
|
|
"glenglenda2", 17021,
|
|
"glenglenda3", 17022,
|
|
"glenglenda4", 17023,
|
|
"glenglenda5", 17024,
|
|
"glenglenda6", 17025,
|
|
"glenglenda7", 17026,
|
|
"glenglenda8", 17027,
|
|
"glenglenda9", 17028,
|
|
"glenglenda10", 17029,
|
|
"flyboy", 17032,
|
|
"dlsftp", 17033,
|
|
"venti", 17034,
|
|
"wiki", 17035,
|
|
"vica", 17036,
|
|
0
|
|
};
|
|
|
|
static int
|
|
lookupport(char *s)
|
|
{
|
|
int i;
|
|
char buf[10], *p;
|
|
|
|
i = strtol(s, &p, 0);
|
|
if(*s && *p == 0)
|
|
return i;
|
|
|
|
i = so_getservbyname(s, "tcp", buf);
|
|
if(i != -1)
|
|
return atoi(buf);
|
|
for(i=0; tab[i].name; i++)
|
|
if(strcmp(s, tab[i].name) == 0)
|
|
return tab[i].num;
|
|
return 0;
|
|
}
|
|
|
|
static ulong
|
|
lookuphost(char *s)
|
|
{
|
|
char to[4];
|
|
ulong ip;
|
|
|
|
memset(to, 0, sizeof to);
|
|
parseip(to, s);
|
|
ip = nhgetl(to);
|
|
if(ip != 0)
|
|
return ip;
|
|
if((s = hostlookup(s)) == nil)
|
|
return 0;
|
|
parseip(to, s);
|
|
ip = nhgetl(to);
|
|
free(s);
|
|
return ip;
|
|
}
|
|
|
|
long
|
|
cswrite(Chan *c, void *a, long n, vlong offset)
|
|
{
|
|
char *f[4];
|
|
char *s, *ns;
|
|
ulong ip;
|
|
int nf, port;
|
|
|
|
s = malloc(n+1);
|
|
if(s == nil)
|
|
error(Enomem);
|
|
if(waserror()){
|
|
free(s);
|
|
nexterror();
|
|
}
|
|
memmove(s, a, n);
|
|
s[n] = 0;
|
|
nf = getfields(s, f, nelem(f), 0, "!");
|
|
if(nf != 3)
|
|
error("can't translate");
|
|
|
|
port = lookupport(f[2]);
|
|
if(port <= 0)
|
|
error("no translation for port found");
|
|
|
|
ip = lookuphost(f[1]);
|
|
if(ip == 0)
|
|
error("no translation for host found");
|
|
|
|
ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
|
|
if(ns == nil)
|
|
error(Enomem);
|
|
free(c->aux);
|
|
c->aux = ns;
|
|
poperror();
|
|
free(s);
|
|
return n;
|
|
}
|
|
|
|
Dev ipdevtab =
|
|
{
|
|
'I',
|
|
"ip",
|
|
|
|
devreset,
|
|
ipinit,
|
|
devshutdown,
|
|
ipattach,
|
|
ipwalk,
|
|
ipstat,
|
|
ipopen,
|
|
devcreate,
|
|
ipclose,
|
|
ipread,
|
|
devbread,
|
|
ipwrite,
|
|
devbwrite,
|
|
devremove,
|
|
devwstat,
|
|
};
|
|
|