protected int RecvChallengeReply(int our_challenge) { int challenge; byte[] peer_digest; try { OtpInputStream ibuf = Read2BytePackage(); int tag = ibuf.Read1(); if (tag != ChallengeReply) { throw new IOException("Handshake protocol error"); } challenge = ibuf.Read4BE(); peer_digest = ibuf.ReadN(16); byte[] our_digest = GenDigest(our_challenge, Local.Cookie); if (!peer_digest.SequenceEqual(our_digest)) { throw new OtpAuthException("Peer authentication error."); } } catch (OtpDecodeException e) { throw new IOException("Handshake failed - not enough data", e); } if (TraceLevel >= TraceHandshake) { Logger.Debug($"<- HANDSHAKE recvChallengeReply from={Peer.Node} challenge={challenge} digest={Hex(peer_digest)} local={Local}"); } return(challenge); }
protected void RecvComplement(int send_name_tag) { if (send_name_tag == 'n' && (Peer.CapFlags & AbstractNode.dFlagHandshake23) != 0) { try { OtpInputStream ibuf = Read2BytePackage(); if (ibuf.Read1() != 'c') { throw new IOException("Not a complement tag"); } long flagsHigh = ibuf.Read4BE(); Peer.CapFlags |= flagsHigh << 32; Peer.Creation = ibuf.Read4BE(); } catch (OtpDecodeException e) { throw new IOException("Handshake failed - not enough data", e); } } }
public override void Run() { if (!Connected) { Deliver(new IOException("Not connected")); return; } byte[] lbuf = new byte[4]; int len; try { while (!Stopping) { // don't return until we get a real message // or a failure of some kind (e.g. EXIT) // read length and read buffer must be atomic! // read 4 bytes - get length of incoming packet ReadSock(lbuf); OtpInputStream ibuf = new OtpInputStream(lbuf) { Flags = Local.Flags }; len = ibuf.Read4BE(); // received tick? send tock! if (len == 0) { lock (objWrite) { socket.OutputStream.Write(TOCK, 0, TOCK.Length); socket.OutputStream.Flush(); } continue; } // got a real message (maybe) - read len bytes byte[] tmpbuf = new byte[len]; ReadSock(tmpbuf); ibuf = new OtpInputStream(tmpbuf) { Flags = Local.Flags }; if (ibuf.Read1() != passThrough) { continue; } // got a real message (really) IOtpErlangObject reason = null; OtpErlangAtom cookie = null; IOtpErlangObject tmp = null; OtpErlangTuple head = null; OtpErlangAtom toName; OtpErlangPid to; OtpErlangPid from; int tag; // decode the header tmp = ibuf.ReadAny(); if (!(tmp is OtpErlangTuple)) { continue; } head = (OtpErlangTuple)tmp; if (!(head.ElementAt(0) is OtpErlangLong)) { continue; } // lets see what kind of message this is tag = (int)((OtpErlangLong)head.ElementAt(0)).LongValue(); switch (tag) { case sendTag: // { SEND, Cookie, ToPid } case sendTTTag: // { SEND, Cookie, ToPid, TraceToken } if (!cookieOk) { // we only check this once, he can send us bad cookies later if he likes if (!(head.ElementAt(1) is OtpErlangAtom)) { continue; } cookie = (OtpErlangAtom)head.ElementAt(1); if (sendCookie) { if (cookie.Value != Local.Cookie) { CookieError(Local, cookie); } } else { if (cookie.Value != "") { CookieError(Local, cookie); } } cookieOk = true; } if (TraceLevel >= TraceSend) { Logger.Debug($"<- {HeaderType(head)} {head}"); /* show received payload too */ ibuf.Mark(); Logger.Debug($" {ibuf.ReadAny()}"); ibuf.Reset(); } to = (OtpErlangPid)head.ElementAt(2); Deliver(new OtpMsg(to, ibuf)); break; case regSendTag: // { REG_SEND, FromPid, Cookie, ToName } case regSendTTTag: // { REG_SEND, FromPid, Cookie, ToName, TraceToken } if (!cookieOk) { // we only check this once, he can send us bad cookies later if he likes if (!(head.ElementAt(2) is OtpErlangAtom)) { continue; } cookie = (OtpErlangAtom)head.ElementAt(2); if (sendCookie) { if (cookie.Value != Local.Cookie) { CookieError(Local, cookie); } } else { if (cookie.Value != "") { CookieError(Local, cookie); } } cookieOk = true; } if (TraceLevel >= TraceSend) { Logger.Debug($"<- {HeaderType(head)} {head}"); /* show received payload too */ ibuf.Mark(); Logger.Debug($" {ibuf.ReadAny()}"); ibuf.Reset(); } from = (OtpErlangPid)head.ElementAt(1); toName = (OtpErlangAtom)head.ElementAt(3); Deliver(new OtpMsg(from, toName.Value, ibuf)); break; case exitTag: // { EXIT, FromPid, ToPid, Reason } case exit2Tag: // { EXIT2, FromPid, ToPid, Reason } if (head.ElementAt(3) == null) { continue; } if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); reason = head.ElementAt(3); Deliver(new OtpMsg(tag, from, to, reason)); break; case exitTTTag: // { EXIT, FromPid, ToPid, TraceToken, Reason } case exit2TTTag: // { EXIT2, FromPid, ToPid, TraceToken, Reason } // as above, but bifferent element number if (head.ElementAt(4) == null) { continue; } if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); reason = head.ElementAt(4); Deliver(new OtpMsg(tag, from, to, reason)); break; case linkTag: // { LINK, FromPid, ToPid} case unlinkTag: // { UNLINK, FromPid, ToPid} if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); Deliver(new OtpMsg(tag, from, to)); break; // absolutely no idea what to do with these, so we ignore them... case groupLeaderTag: // { GROUPLEADER, FromPid, ToPid} // (just show trace) if (TraceLevel >= TraceCTRL) { Logger.Debug("<- " + HeaderType(head) + " " + head); } break; default: // garbage? break; } } // this section reachable only with break // we have received garbage from peer Deliver(new OtpExit("Remote is sending garbage")); } catch (OtpAuthException e) { Deliver(e); } catch (OtpDecodeException) { Deliver(new OtpExit("Remote is sending garbage")); } catch (IOException) { Deliver(new OtpExit("Remote has closed connection")); } finally { Close(); } }
protected int RecvChallenge() { int challenge; try { OtpInputStream ibuf = Read2BytePackage(); int namelen; switch (ibuf.Read1()) { case 'n': if (Peer.DistChoose != 5) { throw new IOException("Old challenge wrong version"); } Peer.DistLow = Peer.DistHigh = ibuf.Read2BE(); Peer.CapFlags = ibuf.Read4BE(); if ((Peer.CapFlags & AbstractNode.dFlagHandshake23) != 0) { throw new IOException("Old challenge unexpected DFLAG_HANDHAKE_23"); } challenge = ibuf.Read4BE(); namelen = (int)ibuf.Length - (1 + 2 + 4 + 4); break; case 'N': Peer.DistLow = Peer.DistHigh = Peer.DistChoose = 6; Peer.CapFlags = ibuf.Read8BE(); if ((Peer.CapFlags & AbstractNode.dFlagHandshake23) == 0) { throw new IOException("New challenge missing DFLAG_HANDHAKE_23"); } challenge = ibuf.Read4BE(); Peer.Creation = ibuf.Read4BE(); namelen = ibuf.Read2BE(); break; default: throw new IOException("Unexpected peer type"); } string hisname = ibuf.ReadStringData(namelen); if (!hisname.Equals(Peer.Node)) { throw new IOException("Handshake failed - peer has wrong name: " + hisname); } if ((Peer.CapFlags & AbstractNode.dFlagExtendedReferences) == 0) { throw new IOException("Handshake failed - peer cannot handle extended references"); } if ((Peer.CapFlags & AbstractNode.dFlagExtendedPidsPorts) == 0) { throw new IOException("Handshake failed - peer cannot handle extended pids and ports"); } } catch (OtpDecodeException e) { throw new IOException("Handshake failed - not enough data", e); } if (TraceLevel >= TraceHandshake) { Logger.Debug($"<- HANDSHAKE recvChallenge from={Peer.Node} challenge={challenge} local={Local}"); } return(challenge); }
protected int RecvName() { int nameTag; string hisname; try { OtpInputStream ibuf = Read2BytePackage(); nameTag = ibuf.Read1(); switch (nameTag) { case 'n': Peer.DistLow = Peer.DistHigh = ibuf.Read2BE(); if (Peer.DistLow != 5) { throw new IOException("Invalid handshake version"); } Peer.CapFlags = ibuf.Read4BE(); hisname = ibuf.ReadStringData((int)ibuf.Length - 7); break; case 'N': Peer.DistLow = Peer.DistHigh = 6; Peer.CapFlags = ibuf.Read8BE(); if ((Peer.CapFlags & AbstractNode.dFlagHandshake23) == 0) { throw new IOException("Missing DFLAG_HANDSHAKE_23"); } Peer.Creation = ibuf.Read4BE(); hisname = ibuf.ReadStringData(); break; default: throw new IOException("Unknown remote node type"); } if ((Peer.CapFlags & AbstractNode.dFlagExtendedReferences) == 0) { throw new IOException("Handshake failed - peer cannot handle extended references"); } if ((Peer.CapFlags & AbstractNode.dFlagExtendedPidsPorts) == 0) { throw new IOException("Handshake failed - peer cannot handle extended pids and ports"); } } catch (OtpDecodeException) { throw new IOException("Handshake failed - not enough data"); } Peer.Node = hisname; if (Peer.Alive == null || Peer.Host == null) { throw new IOException("Handshake failed - peer name invalid: " + hisname); } if (TraceLevel >= TraceHandshake) { Logger.Debug($"<- HANDSHAKE ntype={Peer.Type} dist={Peer.DistHigh} remote={Peer}"); } return(nameTag); }