/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/netif.h"#include "../port/error.h" #include <libsec.h>#include "../port/thwack.h" /* * sdp - secure datagram protocol */ typedef struct Sdp Sdp;typedef struct Conv Conv;typedef struct OneWay OneWay;typedef struct Stats Stats;typedef struct AckPkt AckPkt;typedef struct Algorithm Algorithm;typedef struct CipherRc4 CipherRc4; enum{ Qtopdir= 1, /* top level directory */ Qsdpdir, /* sdp directory */ Qclone, Qlog, Qconvdir, /* directory per conversation */ Qctl, Qdata, /* unreliable packet channel */ Qcontrol, /* reliable control channel */ Qstatus, Qstats, Qrstats, MaxQ, Maxconv= 256, // power of 2 Nfs= 4, // number of file systems MaxRetries= 12, KeepAlive = 300, // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug SecretLength= 32, // a secret per direction SeqMax = (1<<24), SeqWindow = 32, NCompStats = 8,}; #define TYPE(x) (((ulong)(x).path) & 0xff)#define CONV(x) ((((ulong)(x).path) >> 8)&(Maxconv-1))#define QID(x, y) (((x)<<8) | (y)) struct Stats{ ulong outPackets; ulong outDataPackets; ulong outDataBytes; ulong outCompDataBytes; ulong outCompBytes; ulong outCompStats[NCompStats]; ulong inPackets; ulong inDataPackets; ulong inDataBytes; ulong inCompDataBytes; ulong inMissing; ulong inDup; ulong inReorder; ulong inBadComp; ulong inBadAuth; ulong inBadSeq; ulong inBadOther;}; struct OneWay{ Rendez statsready; ulong seqwrap; // number of wraps of the sequence number ulong seq; ulong window; uchar secret[SecretLength]; QLock controllk; Rendez controlready; Block *controlpkt; // control channel ulong controlseq; void *cipherstate; // state cipher int cipherivlen; // initial vector length int cipherblklen; // block length int (*cipher)(OneWay*, uchar *buf, int len); void *authstate; // auth state int authlen; // auth data length in bytes int (*auth)(OneWay*, uchar *buf, int len); void *compstate; int (*comp)(Conv*, int subtype, ulong seq, Block **);}; // conv statesenum { CFree, CInit, CDial, CAccept, COpen, CLocalClose, CRemoteClose, CClosed,}; struct Conv { QLock; Sdp *sdp; int id; int ref; // holds conv up int state; int dataopen; // ref count of opens on Qdata int controlopen; // ref count of opens on Qcontrol int reader; // reader proc has been started Stats lstats; Stats rstats; ulong lastrecv; // time last packet was received ulong timeout; int retries; // the following pair uniquely define conversation on this port ulong dialid; ulong acceptid; QLock readlk; // protects readproc Proc *readproc; Chan *chan; // packet channel char *channame; char owner[KNAMELEN]; /* protections */ int perm; Algorithm *auth; Algorithm *cipher; Algorithm *comp; int drop; OneWay in; OneWay out;}; struct Sdp { QLock; Log; int nconv; Conv *conv[Maxconv]; int ackproc;}; enum { TConnect, TControl, TData, TCompData,}; enum { ControlMesg, ControlAck,}; enum { ThwackU, ThwackC,}; enum { ConOpenRequest, ConOpenAck, ConOpenAckAck, ConClose, ConCloseAck, ConReset,}; struct AckPkt{ uchar cseq[4]; uchar outPackets[4]; uchar outDataPackets[4]; uchar outDataBytes[4]; uchar outCompDataBytes[4]; uchar outCompStats[4*NCompStats]; uchar inPackets[4]; uchar inDataPackets[4]; uchar inDataBytes[4]; uchar inCompDataBytes[4]; uchar inMissing[4]; uchar inDup[4]; uchar inReorder[4]; uchar inBadComp[4]; uchar inBadAuth[4]; uchar inBadSeq[4]; uchar inBadOther[4];}; struct Algorithm{ char *name; int keylen; // in bytes void (*init)(Conv*);}; enum { RC4forward = 10*1024*1024, // maximum skip forward RC4back = 100*1024, // maximum look back}; struct CipherRc4{ ulong cseq; // current byte sequence number RC4state current; int ovalid; // old is valid ulong lgseq; // last good sequence ulong oseq; // old byte sequence number RC4state old;}; static Dirtab sdpdirtab[]={ "log", {Qlog}, 0, 0666, "clone", {Qclone}, 0, 0666,}; static Dirtab convdirtab[]={ "ctl", {Qctl}, 0, 0666, "data", {Qdata}, 0, 0666, "control", {Qcontrol}, 0, 0666, "status", {Qstatus}, 0, 0444, "stats", {Qstats}, 0, 0444, "rstats", {Qrstats}, 0, 0444,}; static int m2p[] = { [OREAD] 4, [OWRITE] 2, [ORDWR] 6}; enum { Logcompress= (1<<0), Logauth= (1<<1), Loghmac= (1<<2),}; static Logflag logflags[] ={ { "compress", Logcompress, }, { "auth", Logauth, }, { "hmac", Loghmac, }, { nil, 0, },}; static Dirtab *dirtab[MaxQ];static Sdp sdptab[Nfs];static char *convstatename[] = { [CFree] "Free", [CInit] "Init", [CDial] "Dial", [CAccept] "Accept", [COpen] "Open", [CLocalClose] "LocalClose", [CRemoteClose] "RemoteClose", [CClosed] "Closed",}; static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);static Conv *sdpclone(Sdp *sdp);static void sdpackproc(void *a);static void onewaycleanup(OneWay *ow);static int readready(void *a);static int controlread();static void convsetstate(Conv *c, int state);static Block *readcontrol(Conv *c, int n);static void writecontrol(Conv *c, void *p, int n, int wait);static Block *readdata(Conv *c, int n);static long writedata(Conv *c, Block *b);static void convderef(Conv *c);static Block *conviput(Conv *c, Block *b, int control);static void conviconnect(Conv *c, int op, Block *b);static void convicontrol(Conv *c, int op, Block *b);static Block *convicomp(Conv *c, int op, ulong, Block *b);static void convoput(Conv *c, int type, int subtype, Block *b);static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);static void convopenchan(Conv *c, char *path);static void convstats(Conv *c, int local, char *buf, int n);static void convreader(void *a); static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);static void setsecret(OneWay *cc, char *secret); static void nullcipherinit(Conv*c);static void descipherinit(Conv*c);static void rc4cipherinit(Conv*c);static void nullauthinit(Conv*c);static void shaauthinit(Conv*c);static void md5authinit(Conv*c);static void nullcompinit(Conv*c);static void thwackcompinit(Conv*c); static Algorithm cipheralg[] ={ "null", 0, nullcipherinit, "des_56_cbc", 7, descipherinit, "rc4_128", 16, rc4cipherinit, "rc4_256", 32, rc4cipherinit, nil, 0, nil,}; static Algorithm authalg[] ={ "null", 0, nullauthinit, "hmac_sha1_96", 16, shaauthinit, "hmac_md5_96", 16, md5authinit, nil, 0, nil,}; static Algorithm compalg[] ={ "null", 0, nullcompinit, "thwack", 0, thwackcompinit, nil, 0, nil,}; static voidsdpinit(void){ int i; Dirtab *dt; // setup dirtab with non directory entries for(i=0; i<nelem(sdpdirtab); i++) { dt = sdpdirtab + i; dirtab[TYPE(dt->qid)] = dt; } for(i=0; i<nelem(convdirtab); i++) { dt = convdirtab + i; dirtab[TYPE(dt->qid)] = dt; } } static Chan*sdpattach(char* spec){ Chan *c; int dev; char buf[100]; Sdp *sdp; int start; dev = atoi(spec); if(dev<0 || dev >= Nfs) error("bad specification"); c = devattach('E', spec); c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR}; c->dev = dev; sdp = sdptab + dev; qlock(sdp); start = sdp->ackproc == 0; sdp->ackproc = 1; qunlock(sdp); if(start) { snprint(buf, sizeof(buf), "sdpackproc%d", dev); kproc(buf, sdpackproc, sdp); } return c;} static Walkqid*sdpwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, sdpgen);} static intsdpstat(Chan* c, uchar* db, int n){ return devstat(c, db, n, nil, 0, sdpgen);} static Chan*sdpopen(Chan* ch, int omode){ int perm; Sdp *sdp; Conv *c; omode &= 3; perm = m2p[omode]; USED(perm); sdp = sdptab + ch->dev; switch(TYPE(ch->qid)) { default: break; case Qtopdir: case Qsdpdir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qlog: logopen(sdp); break; case Qclone: c = sdpclone(sdp); if(c == nil) error(Enodev); ch->qid.path = QID(c->id, Qctl); break; case Qdata: case Qctl: case Qstatus: case Qcontrol: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); if(waserror()) { qunlock(c); nexterror(); } if((perm & (c->perm>>6)) != perm) if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) error(Eperm); c->ref++; if(TYPE(ch->qid) == Qdata) { c->dataopen++; // kill reader if Qdata is opened for the first time if(c->dataopen == 1) if(c->readproc != nil) postnote(c->readproc, 1, "interrupt", 0); } else if(TYPE(ch->qid) == Qcontrol) { c->controlopen++; } qunlock(c); poperror(); break; } ch->mode = openmode(omode); ch->flag |= COPEN; ch->offset = 0; return ch;} static voidsdpclose(Chan* ch){ Sdp *sdp = sdptab + ch->dev; Conv *c; if(!(ch->flag & COPEN)) return; switch(TYPE(ch->qid)) { case Qlog: logclose(sdp); break; case Qctl: case Qstatus: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); convderef(c);Lines 1–500 of 2326. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/netif.h" #include "../port/error.h" #include <libsec.h> #include "../port/thwack.h" /* * sdp - secure datagram protocol */ typedef struct Sdp Sdp; typedef struct Conv Conv; typedef struct OneWay OneWay; typedef struct Stats Stats; typedef struct AckPkt AckPkt; typedef struct Algorithm Algorithm; typedef struct CipherRc4 CipherRc4; enum { Qtopdir= 1, /* top level directory */ Qsdpdir, /* sdp directory */ Qclone, Qlog, Qconvdir, /* directory per conversation */ Qctl, Qdata, /* unreliable packet channel */ Qcontrol, /* reliable control channel */ Qstatus, Qstats, Qrstats, MaxQ, Maxconv= 256, // power of 2 Nfs= 4, // number of file systems MaxRetries= 12, KeepAlive = 300, // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug SecretLength= 32, // a secret per direction SeqMax = (1<<24), SeqWindow = 32, NCompStats = 8, }; #define TYPE(x) (((ulong)(x).path) & 0xff) #define CONV(x) ((((ulong)(x).path) >> 8)&(Maxconv-1)) #define QID(x, y) (((x)<<8) | (y)) struct Stats { ulong outPackets; ulong outDataPackets; ulong outDataBytes; ulong outCompDataBytes; ulong outCompBytes; ulong outCompStats[NCompStats]; ulong inPackets; ulong inDataPackets; ulong inDataBytes; ulong inCompDataBytes; ulong inMissing; ulong inDup; ulong inReorder; ulong inBadComp; ulong inBadAuth; ulong inBadSeq; ulong inBadOther; }; struct OneWay { Rendez statsready; ulong seqwrap; // number of wraps of the sequence number ulong seq; ulong window; uchar secret[SecretLength]; QLock controllk; Rendez controlready; Block *controlpkt; // control channel ulong controlseq; void *cipherstate; // state cipher int cipherivlen; // initial vector length int cipherblklen; // block length int (*cipher)(OneWay*, uchar *buf, int len); void *authstate; // auth state int authlen; // auth data length in bytes int (*auth)(OneWay*, uchar *buf, int len); void *compstate; int (*comp)(Conv*, int subtype, ulong seq, Block **); }; // conv states enum { CFree, CInit, CDial, CAccept, COpen, CLocalClose, CRemoteClose, CClosed, }; struct Conv { QLock; Sdp *sdp; int id; int ref; // holds conv up int state; int dataopen; // ref count of opens on Qdata int controlopen; // ref count of opens on Qcontrol int reader; // reader proc has been started Stats lstats; Stats rstats; ulong lastrecv; // time last packet was received ulong timeout; int retries; // the following pair uniquely define conversation on this port ulong dialid; ulong acceptid; QLock readlk; // protects readproc Proc *readproc; Chan *chan; // packet channel char *channame; char owner[KNAMELEN]; /* protections */ int perm; Algorithm *auth; Algorithm *cipher; Algorithm *comp; int drop; OneWay in; OneWay out; }; struct Sdp { QLock; Log; int nconv; Conv *conv[Maxconv]; int ackproc; }; enum { TConnect, TControl, TData, TCompData, }; enum { ControlMesg, ControlAck, }; enum { ThwackU, ThwackC, }; enum { ConOpenRequest, ConOpenAck, ConOpenAckAck, ConClose, ConCloseAck, ConReset, }; struct AckPkt { uchar cseq[4]; uchar outPackets[4]; uchar outDataPackets[4]; uchar outDataBytes[4]; uchar outCompDataBytes[4]; uchar outCompStats[4*NCompStats]; uchar inPackets[4]; uchar inDataPackets[4]; uchar inDataBytes[4]; uchar inCompDataBytes[4]; uchar inMissing[4]; uchar inDup[4]; uchar inReorder[4]; uchar inBadComp[4]; uchar inBadAuth[4]; uchar inBadSeq[4]; uchar inBadOther[4]; }; struct Algorithm { char *name; int keylen; // in bytes void (*init)(Conv*); }; enum { RC4forward = 10*1024*1024, // maximum skip forward RC4back = 100*1024, // maximum look back }; struct CipherRc4 { ulong cseq; // current byte sequence number RC4state current; int ovalid; // old is valid ulong lgseq; // last good sequence ulong oseq; // old byte sequence number RC4state old; }; static Dirtab sdpdirtab[]={ "log", {Qlog}, 0, 0666, "clone", {Qclone}, 0, 0666, }; static Dirtab convdirtab[]={ "ctl", {Qctl}, 0, 0666, "data", {Qdata}, 0, 0666, "control", {Qcontrol}, 0, 0666, "status", {Qstatus}, 0, 0444, "stats", {Qstats}, 0, 0444, "rstats", {Qrstats}, 0, 0444, }; static int m2p[] = { [OREAD] 4, [OWRITE] 2, [ORDWR] 6 }; enum { Logcompress= (1<<0), Logauth= (1<<1), Loghmac= (1<<2), }; static Logflag logflags[] = { { "compress", Logcompress, }, { "auth", Logauth, }, { "hmac", Loghmac, }, { nil, 0, }, }; static Dirtab *dirtab[MaxQ]; static Sdp sdptab[Nfs]; static char *convstatename[] = { [CFree] "Free", [CInit] "Init", [CDial] "Dial", [CAccept] "Accept", [COpen] "Open", [CLocalClose] "LocalClose", [CRemoteClose] "RemoteClose", [CClosed] "Closed", }; static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp); static Conv *sdpclone(Sdp *sdp); static void sdpackproc(void *a); static void onewaycleanup(OneWay *ow); static int readready(void *a); static int controlread(); static void convsetstate(Conv *c, int state); static Block *readcontrol(Conv *c, int n); static void writecontrol(Conv *c, void *p, int n, int wait); static Block *readdata(Conv *c, int n); static long writedata(Conv *c, Block *b); static void convderef(Conv *c); static Block *conviput(Conv *c, Block *b, int control); static void conviconnect(Conv *c, int op, Block *b); static void convicontrol(Conv *c, int op, Block *b); static Block *convicomp(Conv *c, int op, ulong, Block *b); static void convoput(Conv *c, int type, int subtype, Block *b); static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid); static void convopenchan(Conv *c, char *path); static void convstats(Conv *c, int local, char *buf, int n); static void convreader(void *a); static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **); static void setsecret(OneWay *cc, char *secret); static void nullcipherinit(Conv*c); static void descipherinit(Conv*c); static void rc4cipherinit(Conv*c); static void nullauthinit(Conv*c); static void shaauthinit(Conv*c); static void md5authinit(Conv*c); static void nullcompinit(Conv*c); static void thwackcompinit(Conv*c); static Algorithm cipheralg[] = { "null", 0, nullcipherinit, "des_56_cbc", 7, descipherinit, "rc4_128", 16, rc4cipherinit, "rc4_256", 32, rc4cipherinit, nil, 0, nil, }; static Algorithm authalg[] = { "null", 0, nullauthinit, "hmac_sha1_96", 16, shaauthinit, "hmac_md5_96", 16, md5authinit, nil, 0, nil, }; static Algorithm compalg[] = { "null", 0, nullcompinit, "thwack", 0, thwackcompinit, nil, 0, nil, }; static void sdpinit(void) { int i; Dirtab *dt; // setup dirtab with non directory entries for(i=0; i<nelem(sdpdirtab); i++) { dt = sdpdirtab + i; dirtab[TYPE(dt->qid)] = dt; } for(i=0; i<nelem(convdirtab); i++) { dt = convdirtab + i; dirtab[TYPE(dt->qid)] = dt; } } static Chan* sdpattach(char* spec) { Chan *c; int dev; char buf[100]; Sdp *sdp; int start; dev = atoi(spec); if(dev<0 || dev >= Nfs) error("bad specification"); c = devattach('E', spec); c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR}; c->dev = dev; sdp = sdptab + dev; qlock(sdp); start = sdp->ackproc == 0; sdp->ackproc = 1; qunlock(sdp); if(start) { snprint(buf, sizeof(buf), "sdpackproc%d", dev); kproc(buf, sdpackproc, sdp); } return c; } static Walkqid* sdpwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, sdpgen); } static int sdpstat(Chan* c, uchar* db, int n) { return devstat(c, db, n, nil, 0, sdpgen); } static Chan* sdpopen(Chan* ch, int omode) { int perm; Sdp *sdp; Conv *c; omode &= 3; perm = m2p[omode]; USED(perm); sdp = sdptab + ch->dev; switch(TYPE(ch->qid)) { default: break; case Qtopdir: case Qsdpdir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qlog: logopen(sdp); break; case Qclone: c = sdpclone(sdp); if(c == nil) error(Enodev); ch->qid.path = QID(c->id, Qctl); break; case Qdata: case Qctl: case Qstatus: case Qcontrol: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); if(waserror()) { qunlock(c); nexterror(); } if((perm & (c->perm>>6)) != perm) if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) error(Eperm); c->ref++; if(TYPE(ch->qid) == Qdata) { c->dataopen++; // kill reader if Qdata is opened for the first time if(c->dataopen == 1) if(c->readproc != nil) postnote(c->readproc, 1, "interrupt", 0); } else if(TYPE(ch->qid) == Qcontrol) { c->controlopen++; } qunlock(c); poperror(); break; } ch->mode = openmode(omode); ch->flag |= COPEN; ch->offset = 0; return ch; } static void sdpclose(Chan* ch) { Sdp *sdp = sdptab + ch->dev; Conv *c; if(!(ch->flag & COPEN)) return; switch(TYPE(ch->qid)) { case Qlog: logclose(sdp); break; case Qctl: case Qstatus: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); convderef(c);