Exemple #1
0
        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);
        }
Exemple #2
0
        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);
                }
            }
        }
Exemple #3
0
        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();
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
        }