2326 lines · 44.2 KB · C
RawDownload
/*  * 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.