2 #include "../port/lib.h"
6 #include "../port/netif.h"
7 #include "../port/error.h"
10 #include "../port/thwack.h"
13 * sdp - secure datagram protocol
16 typedef struct Sdp Sdp;
17 typedef struct Conv Conv;
18 typedef struct OneWay OneWay;
19 typedef struct Stats Stats;
20 typedef struct AckPkt AckPkt;
21 typedef struct Algorithm Algorithm;
22 typedef struct CipherRc4 CipherRc4;
26 Qtopdir= 1, /* top level directory */
28 Qsdpdir, /* sdp directory */
32 Qconvdir, /* directory per conversation */
34 Qdata, /* unreliable packet channel */
35 Qcontrol, /* reliable control channel */
42 Maxconv= 256, // power of 2
43 Nfs= 4, // number of file systems
45 KeepAlive = 300, // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug
46 SecretLength= 32, // a secret per direction
52 #define TYPE(x) (((ulong)(x).path) & 0xff)
53 #define CONV(x) ((((ulong)(x).path) >> 8)&(Maxconv-1))
54 #define QID(x, y) (((x)<<8) | (y))
61 ulong outCompDataBytes;
63 ulong outCompStats[NCompStats];
67 ulong inCompDataBytes;
81 ulong seqwrap; // number of wraps of the sequence number
85 uchar secret[SecretLength];
89 Block *controlpkt; // control channel
92 void *cipherstate; // state cipher
93 int cipherivlen; // initial vector length
94 int cipherblklen; // block length
95 int (*cipher)(OneWay*, uchar *buf, int len);
97 void *authstate; // auth state
98 int authlen; // auth data length in bytes
99 int (*auth)(OneWay*, uchar *buf, int len);
102 int (*comp)(Conv*, int subtype, ulong seq, Block **);
122 int ref; // holds conv up
126 int dataopen; // ref count of opens on Qdata
127 int controlopen; // ref count of opens on Qcontrol
128 int reader; // reader proc has been started
133 ulong lastrecv; // time last packet was received
137 // the following pair uniquely define conversation on this port
141 QLock readlk; // protects readproc
144 Chan *chan; // packet channel
147 char owner[KNAMELEN]; /* protections */
198 uchar outDataPackets[4];
199 uchar outDataBytes[4];
200 uchar outCompDataBytes[4];
201 uchar outCompStats[4*NCompStats];
203 uchar inDataPackets[4];
204 uchar inDataBytes[4];
205 uchar inCompDataBytes[4];
218 int keylen; // in bytes
223 RC4forward = 10*1024*1024, // maximum skip forward
224 RC4back = 100*1024, // maximum look back
229 ulong cseq; // current byte sequence number
232 int ovalid; // old is valid
233 ulong lgseq; // last good sequence
234 ulong oseq; // old byte sequence number
238 static Dirtab sdpdirtab[]={
239 "log", {Qlog}, 0, 0666,
240 "clone", {Qclone}, 0, 0666,
243 static Dirtab convdirtab[]={
244 "ctl", {Qctl}, 0, 0666,
245 "data", {Qdata}, 0, 0666,
246 "control", {Qcontrol}, 0, 0666,
247 "status", {Qstatus}, 0, 0444,
248 "stats", {Qstats}, 0, 0444,
249 "rstats", {Qrstats}, 0, 0444,
264 static Logflag logflags[] =
266 { "compress", Logcompress, },
267 { "auth", Logauth, },
268 { "hmac", Loghmac, },
272 static Dirtab *dirtab[MaxQ];
273 static Sdp sdptab[Nfs];
274 static char *convstatename[] = {
280 [CLocalClose] "LocalClose",
281 [CRemoteClose] "RemoteClose",
285 static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
286 static Conv *sdpclone(Sdp *sdp);
287 static void sdpackproc(void *a);
288 static void onewaycleanup(OneWay *ow);
289 static int readready(void *a);
290 static int controlread();
291 static void convsetstate(Conv *c, int state);
292 static Block *readcontrol(Conv *c, int n);
293 static void writecontrol(Conv *c, void *p, int n, int wait);
294 static Block *readdata(Conv *c, int n);
295 static long writedata(Conv *c, Block *b);
296 static void convderef(Conv *c);
297 static Block *conviput(Conv *c, Block *b, int control);
298 static void conviconnect(Conv *c, int op, Block *b);
299 static void convicontrol(Conv *c, int op, Block *b);
300 static Block *convicomp(Conv *c, int op, ulong, Block *b);
301 static void convoput(Conv *c, int type, int subtype, Block *b);
302 static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);
303 static void convopenchan(Conv *c, char *path);
304 static void convstats(Conv *c, int local, char *buf, int n);
305 static void convreader(void *a);
307 static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);
308 static void setsecret(OneWay *cc, char *secret);
310 static void nullcipherinit(Conv*c);
311 static void descipherinit(Conv*c);
312 static void rc4cipherinit(Conv*c);
313 static void nullauthinit(Conv*c);
314 static void shaauthinit(Conv*c);
315 static void md5authinit(Conv*c);
316 static void nullcompinit(Conv*c);
317 static void thwackcompinit(Conv*c);
319 static Algorithm cipheralg[] =
321 "null", 0, nullcipherinit,
322 "des_56_cbc", 7, descipherinit,
323 "rc4_128", 16, rc4cipherinit,
324 "rc4_256", 32, rc4cipherinit,
328 static Algorithm authalg[] =
330 "null", 0, nullauthinit,
331 "hmac_sha1_96", 16, shaauthinit,
332 "hmac_md5_96", 16, md5authinit,
336 static Algorithm compalg[] =
338 "null", 0, nullcompinit,
339 "thwack", 0, thwackcompinit,
350 // setup dirtab with non directory entries
351 for(i=0; i<nelem(sdpdirtab); i++) {
353 dirtab[TYPE(dt->qid)] = dt;
356 for(i=0; i<nelem(convdirtab); i++) {
358 dirtab[TYPE(dt->qid)] = dt;
364 sdpattach(char* spec)
373 if(dev<0 || dev >= Nfs)
374 error("bad specification");
376 c = devattach('E', spec);
377 c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR};
382 start = sdp->ackproc == 0;
387 snprint(buf, sizeof(buf), "sdpackproc%d", dev);
388 kproc(buf, sdpackproc, sdp);
395 sdpwalk(Chan *c, Chan *nc, char **name, int nname)
397 return devwalk(c, nc, name, nname, 0, 0, sdpgen);
401 sdpstat(Chan* c, uchar* db, int n)
403 return devstat(c, db, n, nil, 0, sdpgen);
407 sdpopen(Chan* ch, int omode)
417 sdp = sdptab + ch->dev;
419 switch(TYPE(ch->qid)) {
435 ch->qid.path = QID(c->id, Qctl);
443 c = sdp->conv[CONV(ch->qid)];
449 if((perm & (c->perm>>6)) != perm)
450 if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm)
454 if(TYPE(ch->qid) == Qdata) {
456 // kill reader if Qdata is opened for the first time
458 if(c->readproc != nil)
459 postnote(c->readproc, 1, "interrupt", 0);
460 } else if(TYPE(ch->qid) == Qcontrol) {
467 ch->mode = openmode(omode);
476 Sdp *sdp = sdptab + ch->dev;
479 if(!(ch->flag & COPEN))
481 switch(TYPE(ch->qid)) {
489 c = sdp->conv[CONV(ch->qid)];
496 c = sdp->conv[CONV(ch->qid)];
504 kproc("convreader", convreader, c);
513 c = sdp->conv[CONV(ch->qid)];
517 if(c->controlopen == 0 && c->ref != 0) {
520 convsetstate(c, CClosed);
524 convsetstate(c, CLocalClose);
534 sdpread(Chan *ch, void *a, long n, vlong off)
538 Sdp *sdp = sdptab + ch->dev;
544 switch(TYPE(ch->qid)) {
550 return devdirread(ch, a, n, 0, 0, sdpgen);
552 return logread(sdp, a, off, n);
554 c = sdp->conv[CONV(ch->qid)];
556 n = readstr(off, a, n, convstatename[c->state]);
560 sprint(buf, "%lud", CONV(ch->qid));
561 return readstr(off, a, n, buf);
563 b = readcontrol(sdp->conv[CONV(ch->qid)], n);
568 memmove(a, b->rp, n);
572 b = readdata(sdp->conv[CONV(ch->qid)], n);
577 memmove(a, b->rp, n);
582 c = sdp->conv[CONV(ch->qid)];
584 convstats(c, TYPE(ch->qid) == Qstats, s, 1000);
585 rv = readstr(off, a, n, s);
592 sdpbread(Chan* ch, long n, ulong offset)
594 Sdp *sdp = sdptab + ch->dev;
596 if(TYPE(ch->qid) != Qdata)
597 return devbread(ch, n, offset);
598 return readdata(sdp->conv[CONV(ch->qid)], n);
603 sdpwrite(Chan *ch, void *a, long n, vlong off)
605 Sdp *sdp = sdptab + ch->dev;
613 switch(TYPE(ch->qid)) {
617 c = sdp->conv[CONV(ch->qid)];
626 error("short write");
628 if(strcmp(arg0, "accept") == 0) {
630 error("usage: accept file");
631 convopenchan(c, cb->f[1]);
632 } else if(strcmp(arg0, "dial") == 0) {
634 error("usage: dial file");
635 convopenchan(c, cb->f[1]);
636 convsetstate(c, CDial);
637 } else if(strcmp(arg0, "drop") == 0) {
639 error("usage: drop permil");
640 c->drop = atoi(cb->f[1]);
641 } else if(strcmp(arg0, "cipher") == 0) {
643 error("usage: cipher alg");
644 setalg(c, cb->f[1], cipheralg, &c->cipher);
645 } else if(strcmp(arg0, "auth") == 0) {
647 error("usage: auth alg");
648 setalg(c, cb->f[1], authalg, &c->auth);
649 } else if(strcmp(arg0, "comp") == 0) {
651 error("usage: comp alg");
652 setalg(c, cb->f[1], compalg, &c->comp);
653 } else if(strcmp(arg0, "insecret") == 0) {
655 error("usage: insecret secret");
656 setsecret(&c->in, cb->f[1]);
661 } else if(strcmp(arg0, "outsecret") == 0) {
663 error("usage: outsecret secret");
664 setsecret(&c->out, cb->f[1]);
670 error("unknown control request");
677 p = logctl(sdp, cb->nf, cb->f, logflags);
683 writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0);
687 memmove(b->wp, a, n);
689 return writedata(sdp->conv[CONV(ch->qid)], b);
694 sdpbwrite(Chan *ch, Block *bp, ulong offset)
696 Sdp *sdp = sdptab + ch->dev;
698 if(TYPE(ch->qid) != Qdata)
699 return devbwrite(ch, bp, offset);
700 return writedata(sdp->conv[CONV(ch->qid)], bp);
704 sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
706 Sdp *sdp = sdptab + c->dev;
707 int type = TYPE(c->qid);
712 switch(TYPE(c->qid)){
715 snprint(up->genbuf, sizeof(up->genbuf), "#E%ld", c->dev);
716 mkqid(&qid, Qtopdir, 0, QTDIR);
717 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
720 snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
721 mkqid(&qid, Qsdpdir, 0, QTDIR);
722 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
725 panic("sdpwalk %llux", c->qid.path);
732 // non directory entries end up here
733 if(c->qid.type & QTDIR)
734 panic("sdpgen: unexpected directory");
737 dt = dirtab[TYPE(c->qid)];
739 panic("sdpgen: unknown type: %lud", TYPE(c->qid));
740 devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
745 mkqid(&qid, QID(0, Qsdpdir), 0, QTDIR);
746 devdir(c, qid, "sdp", 0, eve, 0555, dp);
749 if(s<nelem(sdpdirtab)) {
751 devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
754 s -= nelem(sdpdirtab);
757 mkqid(&qid, QID(s, Qconvdir), 0, QTDIR);
758 snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
759 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
762 if(s>=nelem(convdirtab))
765 mkqid(&qid, QID(CONV(c->qid),TYPE(dt->qid)), 0, QTFILE);
766 devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
777 ep = sdp->conv + nelem(sdp->conv);
783 for(pp = sdp->conv; pp < ep; pp++) {
786 c = malloc(sizeof(Conv));
789 memset(c, 0, sizeof(Conv));
792 c->id = pp - sdp->conv;
797 if(c->ref == 0 && canqlock(c)){
809 assert(c->state == CFree);
810 // set ref to 2 - 1 ref for open - 1 ref for channel state
814 strncpy(c->owner, up->user, sizeof(c->owner));
821 // assume c is locked
823 convretryinit(Conv *c)
826 // +2 to avoid rounding effects.
827 c->timeout = TK2SEC(m->ticks) + 2;
830 // assume c is locked
832 convretry(Conv *c, int reset)
835 if(c->retries > MaxRetries) {
837 convoconnect(c, ConReset, c->dialid, c->acceptid);
838 convsetstate(c, CClosed);
841 c->timeout = TK2SEC(m->ticks) + (c->retries+1);
845 // assumes c is locked
847 convtimer(Conv *c, ulong sec)
859 convoconnect(c, ConOpenRequest, c->dialid, 0);
863 convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
866 b = c->out.controlpkt;
869 convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
873 c->timeout = c->lastrecv + KeepAlive;
876 // keepalive - randomly spaced between KeepAlive and 2*KeepAlive
877 if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0)
879 // can not use writecontrol
882 hnputl(b->wp, c->out.controlseq);
884 c->out.controlpkt = b;
887 convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
893 convoconnect(c, ConClose, c->dialid, c->acceptid);
911 tsleep(&up->sleep, return0, 0, 1000);
912 sec = TK2SEC(m->ticks);
914 for(i=0; i<sdp->nconv; i++) {
920 if(c->ref > 0 && !waserror()) {
952 // assume hold lock on c
954 convsetstate(Conv *c, int state)
957 if(0)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
961 panic("setstate: bad state: %d", state);
963 assert(c->state == CInit);
964 c->dialid = (rand()<<16) + rand();
966 convoconnect(c, ConOpenRequest, c->dialid, 0);
969 assert(c->state == CInit);
970 c->acceptid = (rand()<<16) + rand();
972 convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
975 assert(c->state == CDial || c->state == CAccept);
976 c->lastrecv = TK2SEC(m->ticks);
977 if(c->state == CDial) {
979 convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid);
980 hnputl(c->in.secret, c->acceptid);
981 hnputl(c->in.secret+4, c->dialid);
982 hnputl(c->out.secret, c->dialid);
983 hnputl(c->out.secret+4, c->acceptid);
985 hnputl(c->in.secret, c->dialid);
986 hnputl(c->in.secret+4, c->acceptid);
987 hnputl(c->out.secret, c->acceptid);
988 hnputl(c->out.secret+4, c->dialid);
990 setalg(c, "hmac_md5_96", authalg, &c->auth);
993 assert(c->state == CAccept || c->state == COpen);
995 convoconnect(c, ConClose, c->dialid, c->acceptid);
998 wakeup(&c->in.controlready);
999 wakeup(&c->out.controlready);
1002 wakeup(&c->in.controlready);
1003 wakeup(&c->out.controlready);
1005 postnote(c->readproc, 1, "interrupt", 0);
1006 if(c->state != CClosed)
1014 //assumes c is locked
1022 assert(c->ref == 0);
1023 assert(c->dataopen == 0);
1024 assert(c->controlopen == 0);
1025 if(0)print("convderef: %d: ref == 0!\n", c->id);
1038 strcpy(c->owner, "network");
1045 onewaycleanup(&c->in);
1046 onewaycleanup(&c->out);
1047 memset(&c->lstats, 0, sizeof(Stats));
1048 memset(&c->rstats, 0, sizeof(Stats));
1052 onewaycleanup(OneWay *ow)
1055 freeb(ow->controlpkt);
1057 free(ow->authstate);
1059 free(ow->cipherstate);
1061 free(ow->compstate);
1062 memset(ow, 0, sizeof(OneWay));
1066 // assumes conv is locked
1068 convopenchan(Conv *c, char *path)
1070 if(c->state != CInit || c->chan != nil)
1071 error("already connected");
1072 c->chan = namec(path, Aopen, ORDWR, 0);
1073 c->channame = smalloc(strlen(path)+1);
1074 strcpy(c->channame, path);
1082 kproc("convreader", convreader, c);
1084 assert(c->reader == 0 && c->ref > 0);
1085 // after kproc in case it fails
1093 convstats(Conv *c, int local, char *buf, int n)
1103 writecontrol(c, 0, 0, 1);
1112 p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets);
1113 p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets);
1114 p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes);
1115 p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes);
1116 for(i=0; i<NCompStats; i++) {
1117 if(stats->outCompStats[i] == 0)
1119 p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]);
1121 p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets);
1122 p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets);
1123 p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes);
1124 p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes);
1125 p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing);
1126 p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup);
1127 p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder);
1128 p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp);
1129 p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth);
1130 p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq);
1131 p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther);
1145 b = allocb(sizeof(AckPkt));
1146 ack = (AckPkt*)b->wp;
1147 b->wp += sizeof(AckPkt);
1149 hnputl(ack->cseq, c->in.controlseq);
1150 hnputl(ack->outPackets, s->outPackets);
1151 hnputl(ack->outDataPackets, s->outDataPackets);
1152 hnputl(ack->outDataBytes, s->outDataBytes);
1153 hnputl(ack->outCompDataBytes, s->outCompDataBytes);
1154 for(i=0; i<NCompStats; i++)
1155 hnputl(ack->outCompStats+i*4, s->outCompStats[i]);
1156 hnputl(ack->inPackets, s->inPackets);
1157 hnputl(ack->inDataPackets, s->inDataPackets);
1158 hnputl(ack->inDataBytes, s->inDataBytes);
1159 hnputl(ack->inCompDataBytes, s->inCompDataBytes);
1160 hnputl(ack->inMissing, s->inMissing);
1161 hnputl(ack->inDup, s->inDup);
1162 hnputl(ack->inReorder, s->inReorder);
1163 hnputl(ack->inBadComp, s->inBadComp);
1164 hnputl(ack->inBadAuth, s->inBadAuth);
1165 hnputl(ack->inBadSeq, s->inBadSeq);
1166 hnputl(ack->inBadOther, s->inBadOther);
1167 convoput(c, TControl, ControlAck, b);
1171 // assume we hold lock for c
1173 conviput(Conv *c, Block *b, int control)
1180 c->lstats.inPackets++;
1183 c->lstats.inBadOther++;
1188 type = b->rp[0] >> 4;
1189 subtype = b->rp[0] & 0xf;
1191 if(type == TConnect) {
1192 conviconnect(c, subtype, b);
1199 c->lstats.inBadOther++;
1200 convoconnect(c, ConReset, c->dialid, c->acceptid);
1201 convsetstate(c, CClosed);
1206 c->lstats.inBadOther++;
1211 seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2];
1214 seqwrap = c->in.seqwrap;
1215 seqdiff = seq - c->in.seq;
1216 if(seqdiff < -(SeqMax*3/4)) {
1219 } else if(seqdiff > SeqMax*3/4) {
1225 if(seqdiff <= -SeqWindow) {
1226 if(0)print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
1227 c->lstats.inBadSeq++;
1232 if(c->in.window & (1<<-seqdiff)) {
1233 if(0)print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
1239 c->lstats.inReorder++;
1242 // ok the sequence number looks ok
1243 if(0) print("coniput seq=%ulx\n", seq);
1244 if(c->in.auth != 0) {
1245 if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) {
1246 if(0)print("bad auth %ld\n", BLEN(b)+4);
1247 c->lstats.inBadAuth++;
1251 b->wp -= c->in.authlen;
1254 if(c->in.cipher != 0) {
1255 if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) {
1256 if(0)print("bad cipher\n");
1257 c->lstats.inBadOther++;
1261 b->rp += c->in.cipherivlen;
1262 if(c->in.cipherblklen > 1) {
1265 if(0)print("pad too big\n");
1266 c->lstats.inBadOther++;
1274 // ok the packet is good
1276 while(seqdiff > 0 && c->in.window != 0) {
1277 if((c->in.window & (1<<(SeqWindow-1))) == 0) {
1278 c->lstats.inMissing++;
1284 c->lstats.inMissing += seqdiff;
1288 c->in.seqwrap = seqwrap;
1290 c->in.window |= 1<<-seqdiff;
1291 c->lastrecv = TK2SEC(m->ticks);
1295 convicontrol(c, subtype, b);
1298 c->lstats.inDataPackets++;
1299 c->lstats.inDataBytes += BLEN(b);
1304 c->lstats.inDataPackets++;
1305 c->lstats.inCompDataBytes += BLEN(b);
1306 b = convicomp(c, subtype, seq, b);
1308 c->lstats.inBadComp++;
1311 c->lstats.inDataBytes += BLEN(b);
1316 if(0)print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
1317 c->lstats.inBadOther++;
1322 // assume hold conv lock
1324 conviconnect(Conv *c, int subtype, Block *b)
1333 dialid = nhgetl(b->rp);
1334 acceptid = nhgetl(b->rp + 4);
1337 if(0)print("sdp: conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
1339 if(subtype == ConReset) {
1340 convsetstate(c, CClosed);
1346 panic("unknown state: %d", c->state);
1350 if(dialid != c->dialid)
1357 if(dialid != c->dialid
1358 || subtype != ConOpenRequest && acceptid != c->acceptid)
1366 case ConOpenRequest:
1370 convsetstate(c, CAccept);
1374 // duplicate ConOpenRequest that we ignore
1381 c->acceptid = acceptid;
1382 convsetstate(c, COpen);
1385 // duplicate that we have to ack
1386 convoconnect(c, ConOpenAckAck, acceptid, dialid);
1393 convsetstate(c, COpen);
1398 // duplicate that we ignore
1405 convoconnect(c, ConCloseAck, dialid, acceptid);
1406 convsetstate(c, CRemoteClose);
1409 // duplicate ConClose
1410 convoconnect(c, ConCloseAck, dialid, acceptid);
1417 convsetstate(c, CClosed);
1423 // invalid connection message - reset to sender
1424 if(1)print("sdp: invalid conviconnect - sending reset\n");
1425 convoconnect(c, ConReset, dialid, acceptid);
1426 convsetstate(c, CClosed);
1430 convicontrol(Conv *c, int subtype, Block *b)
1438 cseq = nhgetl(b->rp);
1442 if(cseq == c->in.controlseq) {
1443 if(0)print("duplicate control packet: %ulx\n", cseq);
1444 // duplicate control packet
1446 if(c->in.controlpkt == nil)
1451 if(cseq != c->in.controlseq+1)
1453 c->in.controlseq = cseq;
1460 c->in.controlpkt = b;
1461 if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
1462 wakeup(&c->in.controlready);
1466 if(cseq != c->out.controlseq)
1468 if(BLEN(b) < sizeof(AckPkt))
1470 ack = (AckPkt*)(b->rp);
1471 c->rstats.outPackets = nhgetl(ack->outPackets);
1472 c->rstats.outDataPackets = nhgetl(ack->outDataPackets);
1473 c->rstats.outDataBytes = nhgetl(ack->outDataBytes);
1474 c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes);
1475 for(i=0; i<NCompStats; i++)
1476 c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i);
1477 c->rstats.inPackets = nhgetl(ack->inPackets);
1478 c->rstats.inDataPackets = nhgetl(ack->inDataPackets);
1479 c->rstats.inDataBytes = nhgetl(ack->inDataBytes);
1480 c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes);
1481 c->rstats.inMissing = nhgetl(ack->inMissing);
1482 c->rstats.inDup = nhgetl(ack->inDup);
1483 c->rstats.inReorder = nhgetl(ack->inReorder);
1484 c->rstats.inBadComp = nhgetl(ack->inBadComp);
1485 c->rstats.inBadAuth = nhgetl(ack->inBadAuth);
1486 c->rstats.inBadSeq = nhgetl(ack->inBadSeq);
1487 c->rstats.inBadOther = nhgetl(ack->inBadOther);
1489 freeb(c->out.controlpkt);
1490 c->out.controlpkt = nil;
1491 c->timeout = c->lastrecv + KeepAlive;
1492 wakeup(&c->out.controlready);
1498 convicomp(Conv *c, int subtype, ulong seq, Block *b)
1500 if(c->in.comp == nil) {
1504 if(!(*c->in.comp)(c, subtype, seq, &b))
1511 convwriteblock(Conv *c, Block *b)
1514 if(c->drop && nrand(c->drop) == 0)
1518 convsetstate(c, CClosed);
1521 devtab[c->chan->type]->bwrite(c->chan, b, 0);
1526 // assume hold conv lock
1528 convoput(Conv *c, int type, int subtype, Block *b)
1532 c->lstats.outPackets++;
1533 /* Make room for sdp trailer */
1534 if(c->out.cipherblklen > 1)
1535 pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen;
1539 b = padblock(b, -(pad+c->out.authlen));
1542 memset(b->wp, 0, pad-1);
1547 /* Make space to fit sdp header */
1548 b = padblock(b, 4 + c->out.cipherivlen);
1549 b->rp[0] = (type << 4) | subtype;
1551 if(c->out.seq == (1<<24)) {
1555 b->rp[1] = c->out.seq>>16;
1556 b->rp[2] = c->out.seq>>8;
1557 b->rp[3] = c->out.seq;
1560 (*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4);
1564 b->wp += c->out.authlen;
1565 (*c->out.auth)(&c->out, b->rp, BLEN(b));
1568 convwriteblock(c, b);
1571 // assume hold conv lock
1573 convoconnect(Conv *c, int op, ulong dialid, ulong acceptid)
1577 c->lstats.outPackets++;
1578 assert(c->chan != nil);
1580 b->wp[0] = (TConnect << 4) | op;
1581 hnputl(b->wp+1, dialid);
1582 hnputl(b->wp+5, acceptid);
1586 convwriteblock(c, b);
1592 convreadblock(Conv *c, int n)
1600 qunlock(&c->readlk);
1604 if(c->state == CClosed) {
1613 b = devtab[ch->type]->bread(ch, n, 0);
1616 qunlock(&c->readlk);
1626 return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose);
1630 readcontrol(Conv *c, int n)
1636 qlock(&c->in.controllk);
1638 qunlock(&c->in.controllk);
1641 qlock(c); // this lock is not held during the sleep below
1644 if(c->chan == nil || c->state == CClosed) {
1646 if(0)print("readcontrol: return error - state = %s\n", convstatename[c->state]);
1647 error("conversation closed");
1650 if(c->in.controlpkt != nil)
1653 if(c->state == CRemoteClose) {
1655 if(0)print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
1660 sleep(&c->in.controlready, readready, c);
1666 b = c->in.controlpkt;
1667 c->in.controlpkt = nil;
1670 qunlock(&c->in.controllk);
1680 return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose);
1688 if(c->state == CFree || c->state == CInit ||
1689 c->state == CClosed || c->state == CRemoteClose)
1690 error("conversation closed");
1692 if(c->state == COpen && c->out.controlpkt == nil)
1700 sleep(&c->out.controlready, writeready, c);
1707 writecontrol(Conv *c, void *p, int n, int wait)
1711 qlock(&c->out.controllk);
1715 qunlock(&c->out.controllk);
1720 c->out.controlseq++;
1721 hnputl(b->wp, c->out.controlseq);
1722 memmove(b->wp+4, p, n);
1724 c->out.controlpkt = b;
1726 convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
1731 qunlock(&c->out.controllk);
1735 readdata(Conv *c, int n)
1742 // some slack for tunneling overhead
1745 // make sure size is big enough for control messages
1748 b = convreadblock(c, nn);
1756 b = conviput(c, b, 0);
1768 writedata(Conv *c, Block *b)
1780 if(c->state != COpen) {
1782 error("conversation not open");
1786 c->lstats.outDataPackets++;
1787 c->lstats.outDataBytes += n;
1789 if(c->out.comp != nil) {
1790 // must generate same value as convoput
1791 seq = (c->out.seq + 1) & (SeqMax-1);
1793 subtype = (*c->out.comp)(c, 0, seq, &b);
1794 c->lstats.outCompDataBytes += BLEN(b);
1795 convoput(c, TCompData, subtype, b);
1797 convoput(c, TData, 0, b);
1811 assert(c->reader == 1);
1812 while(c->dataopen == 0 && c->state != CClosed) {
1816 b = convreadblock(c, 2000);
1821 if(strcmp(up->errstr, Eintr) != 0) {
1822 convsetstate(c, CClosed);
1825 } else if(!waserror()) {
1837 /* ciphers, authenticators, and compressors */
1840 setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p)
1842 for(; alg->name; alg++)
1843 if(strcmp(name, alg->name) == 0)
1845 if(alg->name == nil)
1846 error("unknown algorithm");
1853 setsecret(OneWay *ow, char *secret)
1859 memset(ow->secret, 0, sizeof(ow->secret));
1860 for(p=secret; *p; p++) {
1861 if(i >= sizeof(ow->secret)*2)
1864 if(c >= '0' && c <= '9')
1866 else if(c >= 'a' && c <= 'f')
1868 else if(c >= 'A' && c <= 'F')
1871 error("bad character in secret");
1874 ow->secret[i>>1] |= c;
1880 setkey(uchar *key, int n, OneWay *ow, char *prefix)
1882 uchar ibuf[SHA1dlen], obuf[MD5dlen], salt[10];
1886 for(i=0; i<round+1; i++)
1887 salt[i] = 'A'+round;
1888 sha1((uchar*)prefix, strlen(prefix), ibuf, sha1(salt, round+1, nil, nil));
1889 md5(ibuf, SHA1dlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
1890 i = (n<MD5dlen) ? n : MD5dlen;
1891 memmove(key, obuf, i);
1894 if(++round > sizeof salt)
1895 panic("setkey: you ask too much");
1902 if(c->in.cipherstate) {
1903 free(c->in.cipherstate);
1904 c->in.cipherstate = nil;
1906 if(c->out.cipherstate) {
1907 free(c->out.cipherstate);
1908 c->out.cipherstate = nil;
1911 c->in.cipherblklen = 0;
1912 c->out.cipherblklen = 0;
1913 c->in.cipherivlen = 0;
1914 c->out.cipherivlen = 0;
1920 if(c->in.authstate) {
1921 free(c->in.authstate);
1922 c->in.authstate = nil;
1924 if(c->out.authstate) {
1925 free(c->out.authstate);
1926 c->out.authstate = nil;
1936 if(c->in.compstate) {
1937 free(c->in.compstate);
1938 c->in.compstate = nil;
1940 if(c->out.compstate) {
1941 free(c->out.compstate);
1942 c->out.compstate = nil;
1948 nullcipherinit(Conv *c)
1954 desencrypt(OneWay *ow, uchar *p, int n)
1956 uchar *pp, *ip, *eip, *ep;
1957 DESstate *ds = ow->cipherstate;
1959 if(n < 8 || (n & 0x7 != 0))
1962 memmove(p, ds->ivec, 8);
1963 for(p += 8; p < ep; p += 8){
1966 for(eip = ip+8; ip < eip; )
1968 block_cipher(ds->expanded, p, 0);
1969 memmove(ds->ivec, p, 8);
1975 desdecrypt(OneWay *ow, uchar *p, int n)
1978 uchar *tp, *ip, *eip, *ep;
1979 DESstate *ds = ow->cipherstate;
1981 if(n < 8 || (n & 0x7 != 0))
1984 memmove(ds->ivec, p, 8);
1988 block_cipher(ds->expanded, p, 1);
1991 for(eip = ip+8; ip < eip; ){
2000 descipherinit(Conv *c)
2005 int n = c->cipher->keylen;
2013 memset(key, 0, sizeof(key));
2014 setkey(key, n, &c->in, "cipher");
2015 memset(ivec, 0, sizeof(ivec));
2016 c->in.cipherblklen = 8;
2017 c->in.cipherivlen = 8;
2018 c->in.cipher = desdecrypt;
2019 c->in.cipherstate = smalloc(sizeof(DESstate));
2020 setupDESstate(c->in.cipherstate, key, ivec);
2023 memset(key, 0, sizeof(key));
2024 setkey(key, n, &c->out, "cipher");
2026 ivec[i] = nrand(256);
2027 c->out.cipherblklen = 8;
2028 c->out.cipherivlen = 8;
2029 c->out.cipher = desencrypt;
2030 c->out.cipherstate = smalloc(sizeof(DESstate));
2031 setupDESstate(c->out.cipherstate, key, ivec);
2035 rc4encrypt(OneWay *ow, uchar *p, int n)
2037 CipherRc4 *cr = ow->cipherstate;
2042 hnputl(p, cr->cseq);
2045 rc4(&cr->current, p, n);
2051 rc4decrypt(OneWay *ow, uchar *p, int n)
2053 CipherRc4 *cr = ow->cipherstate;
2066 rc4(&cr->current, p, n);
2069 dd = cr->cseq - cr->lgseq;
2074 //print("missing packet: %uld %ld\n", seq, d);
2075 // this link is hosed
2081 cr->oseq = cr->cseq;
2082 memmove(&cr->old, &cr->current, sizeof(RC4state));
2084 rc4skip(&cr->current, d);
2085 rc4(&cr->current, p, n);
2088 //print("reordered packet: %uld %ld\n", seq, d);
2089 dd = seq - cr->oseq;
2090 if(!cr->ovalid || -d > RC4back || dd < 0)
2092 memmove(&tmpstate, &cr->old, sizeof(RC4state));
2093 rc4skip(&tmpstate, dd);
2094 rc4(&tmpstate, p, n);
2098 // move old state up
2100 dd = cr->cseq - RC4back - cr->oseq;
2102 rc4skip(&cr->old, dd);
2111 rc4cipherinit(Conv *c)
2119 n = c->cipher->keylen;
2124 memset(key, 0, sizeof(key));
2125 setkey(key, n, &c->in, "cipher");
2126 c->in.cipherblklen = 1;
2127 c->in.cipherivlen = 4;
2128 c->in.cipher = rc4decrypt;
2129 cr = smalloc(sizeof(CipherRc4));
2130 memset(cr, 0, sizeof(*cr));
2131 setupRC4state(&cr->current, key, n);
2132 c->in.cipherstate = cr;
2135 memset(key, 0, sizeof(key));
2136 setkey(key, n, &c->out, "cipher");
2137 c->out.cipherblklen = 1;
2138 c->out.cipherivlen = 4;
2139 c->out.cipher = rc4encrypt;
2140 cr = smalloc(sizeof(CipherRc4));
2141 memset(cr, 0, sizeof(*cr));
2142 setupRC4state(&cr->current, key, n);
2143 c->out.cipherstate = cr;
2147 nullauthinit(Conv *c)
2153 shaauthinit(Conv *c)
2159 seanq_hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
2161 uchar ipad[65], opad[65], wbuf[4];
2163 DigestState *digest;
2164 uchar innerhash[MD5dlen];
2166 for(i=0; i<64; i++){
2170 ipad[64] = opad[64] = 0;
2171 for(i=0; i<klen; i++){
2176 digest = md5(ipad, 64, nil, nil);
2177 digest = md5(wbuf, sizeof(wbuf), nil, digest);
2178 md5(t, tlen, innerhash, digest);
2179 digest = md5(opad, 64, nil, nil);
2180 md5(innerhash, MD5dlen, hash, digest);
2184 md5auth(OneWay *ow, uchar *t, int tlen)
2186 uchar hash[MD5dlen];
2189 if(tlen < ow->authlen)
2191 tlen -= ow->authlen;
2193 memset(hash, 0, MD5dlen);
2194 seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
2195 r = memcmp(t+tlen, hash, ow->authlen) == 0;
2196 memmove(t+tlen, hash, ow->authlen);
2201 md5authinit(Conv *c)
2207 keylen = c->auth->keylen;
2212 c->in.authstate = smalloc(16);
2213 memset(c->in.authstate, 0, 16);
2214 setkey(c->in.authstate, keylen, &c->in, "auth");
2216 c->in.auth = md5auth;
2219 c->out.authstate = smalloc(16);
2220 memset(c->out.authstate, 0, 16);
2221 setkey(c->out.authstate, keylen, &c->out, "auth");
2222 c->out.authlen = 12;
2223 c->out.auth = md5auth;
2227 nullcompinit(Conv *c)
2233 thwackcomp(Conv *c, int, ulong seq, Block **bp)
2241 b = padblock(*bp, 4);
2243 ackseq = unthwackstate(c->in.compstate, &mask);
2245 b->rp[1] = ackseq>>16;
2246 b->rp[2] = ackseq>>8;
2249 bb = allocb(BLEN(b));
2250 nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
2264 thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp)
2277 mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
2279 thwackack(c->out.compstate, mseq, mask);
2283 b = allocb(ThwMaxBlock);
2284 n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq);
2288 if(0)print("unthwack failed: %d\n", n);
2294 mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
2295 thwackack(c->out.compstate, mseq, mask);
2303 thwackcompinit(Conv *c)
2307 c->in.compstate = malloc(sizeof(Unthwack));
2308 if(c->in.compstate == nil)
2310 unthwackinit(c->in.compstate);
2311 c->out.compstate = malloc(sizeof(Thwack));
2312 if(c->out.compstate == nil)
2314 thwackinit(c->out.compstate);
2315 c->in.comp = thwackuncomp;
2316 c->out.comp = thwackcomp;